spring mvc是spring boot的基础
创建profile包
view
可以用html、jsp、vue、thymleaf模板(优点点:动态内容有默认值,url资源可以使用相对路径,每个标签都可以有占位符)
profilePage.html(profile包下)
重要内容摘录:
<form th:action="@{/profile}" method="post"> //一个可以使用post方法访问的表单
<input id="twitterhandler" type="text"/>
<input id="email" type="text"/>
<input id="birthDate" type="text"/>
</form>
@{}可以构造一个完整路径,即把服务器上下文的路径放到参数上
控制器
创建profileController(profile包下)
开头
package masterspringmvc4.包名; //声明一下包的名字
import org.springframework.stereotype.Controller;//引入控制器包
import org.springframwork.web.bind.annotation.RequestMapping;//引入requestMapping包
控制器实际上就是为了把页面变成一个虚拟路径的url资源
内容摘录
@RequestMapping("/profile")
public String displayProfile(){
return "profile/profilePage";
}
一般自动补全为profile/profilePage.html的,比如:tymeleafProperties类里前缀是classpath:/templates/,后缀是.html,所以使用thymeleaf模板需要在templates包下写view
DTO
此时虽然访问localhost:8080/profile可以访问profile/profilePage.html,但是表单里没有实现功能,需要为post URL映射行为
创建一个数据传输对象DTO命名为profileform,用于匹配表单里的域病描述校验规则
profileform(profile包下)
package masterspringmvc4.profile; //声明一下包的名字
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List; //引入一些数据类型
public class ProfileForm{
private String twitterHandle;
private String email;
private LocalDate birthDate;
private List<String>tastes=new ArrayList<>();
//...省略用于数据绑定的getter&setter方法(从mvc容器里自动获取id数据并填充),springboot是有自动补全的功能的
}
使用java8 的话里面的日期api–java.time.LocalDate比之前的java.util.Date更细致,使用了不可变的数据结构
java.time.LocalDate只是一个日期,java.time.LocalTime是精确到时间,java.time.ZonedDateTime里有时区
为了让spring把表单域绑定到DTO上,需要在profilePage.html上添加一些元数据
<form th:action="@{/profile}" th:object="${profileForm}" method="post">
<input th:field="${profileform.twitterhandler}" id="twitterhandler" type="text"/>
<input th:field="${profileform.email}" id="email" type="text"/>
<input th:field="${profileform.birthDate}" id="birthDate" type="text"/>
</form>
实际上就是给表单加了th:object属性(把一个对象绑定到控制器上),给所有输入域加了th:field属性(把实际的输入域绑定到表单bean的属性上)
为了让th:object运行起来,需要添加一个ProfileForm类型的参数到请求映射的方法里
@RequestMapping("/profile")
public String displayProfile(){
return "profile/profilePage";
}
@RequestMapping(value="/profile",method=RequestMethod.POST) //这是对post方法的映射,表单提交的时候会自然被调用
public String saveProfile(ProfileForm profileForm){ //没有ProfileForm类型的参数无法正常访问
return "redirect:/profile";//save完表单内容之后重定向回去
}
使用不正确的数据提交表单,比如提交一个日期值,实际上不能运行,提示一个400错误并且没有有用的日志,借助springboot里的日志配置就非常简单,只需把logging.level.{package}=DEBUG添加到application.properties文件里即可,{package}是应用里某个类或包的全限定名称,debug是日志级别,自己搜
如果想要调试应用可以添加logging.level.org.springframework.web=DEBUG,org.springframework.web是mvc的基础包,这样可以看到spring web产生的调试信息
为了让用户知道输入日期的正确格式可以在profilecontroller里添加dateFormat属性
@ModelAttribute("dateFormat")
public String LocaleFormat(Locale locale){
return USLocalDateFormatter.getPattern(locale);
}
@ModelAttribute注解允许我们暴露一个属性给web页面,类似于model.addAttribute()方法,此时在html页面的日期输入域添加一个占位符即可
<input th:field="${profileform.birthDate}" id="birthDate" type="text" th:field="${dateFormat}"/>
<label for="birthDate">Birth Date</label>
校验
为了防止用户输入非法或空信息,在profileForm里加一些校验逻辑
新增:
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;
import javax.validation.constrains.NotNull;
import javax.validation.constrains.Past;
import javax.validation.constrains.Size;
public class ProfileForm{
@Size(min=2) //不得小于两个字符
private String twitterHandle;
@Email
@NotEmpty
private String email; //必须是email格式并且不为空
@NotNull
private Date birthDate;
@NotEmpty
private List<String> tastes=new ArrayList<>();
}
这些校验限制的注解来源于JSR-303规范,详细规定了bean的校验功能,最流行的实现是hibernate-validator,已经包含在springboot里了
为了运行校验功能,控制器需要声明在表单提交的时候必须得到一个合法的模型,在代表表单的参数上添加javax.validation.Valid注解即可实现
@RequestMapping(value="/profile",method=RequestMethod.POST)
public String saveProfile(@Valid ProfileForm profileForm,BindingResult bindingResult){
if(bindingResult.hasErrors()){
return "profile/profilePage"; //包含错误信息的时不进行重定向
}
return "redirect:/profile";
}
之后在html页面添加展示报错的地方
<ul th:if="${#fields.hasErrors('*')}" class="erroelist">
<li th:each="err:${#fields.errors('*')}" th:text="${err}">输入错误</li>
</ul>
这样会遍历表单里的每一个错误并在列表里展示
针对用户的@NotEmpty检查会阻止表单的提交,所以不会显示到报错里
为了使错误信息更直观可以自定义报错信息(不详述)
客户端校验功能可以预先校验表单避免一直的不正确的请求对服务器形成过大的负载(不详述)