⭐⭐⭐⭐⭐⭐
Github主页https://github.com/A-BigTree
笔记链接https://github.com/A-BigTree/Code_Learning
⭐⭐⭐⭐⭐⭐
如果可以,麻烦各位看官顺手点个star~
如果文章对你有所帮助,可以点赞收藏⭐支持一下博主~
SpringMVC 将『把请求参数注入到POJO对象』这个操作称为『数据绑定』,英文单词是 binding。数据类型的转换和格式化就发生在数据绑定的过程中。 类型转换和格式化是密不可分的两个过程,很多带格式的数据必须明确指定格式之后才可以进行类型转换。最典型的就是日期类型。
HTTP 协议是一个无类型的协议,我们在服务器端接收到请求参数等形式的数据时,本质上都是字符串类型。请看 javax.servlet.ServletRequest 接口中获取全部请求参数的方法:
public Map<String, String[]> getParameterMap();
而我们在实体类当中需要的类型是非常丰富的。对此,SpringMVC对基本数据类型提供了自动的类型转换。例如:请求参数传入“100”字符串,我们实体类中需要的是 Integer 类型,那么 SpringMVC 会自动将字符串转换为 Integer 类型注入实体类。
public class Product {
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date productDate;
@NumberFormat(pattern = "###,###,###.###")
private Double productPrice;
<form th:action="@{/save/product}" method="post">
生产日期:<input type="text" name="productDate" value="1992-10-15 17:15:06" /><br/>
产品价格:<input type="text" name="productPrice" value="111,222,333.444" /><br/>
<button type="submit">保存button>
form>
@RequestMapping("/save/product")
public String saveProduct(Product product) {
logger.debug(product.toString());
return "target";
}
BindingResult
接口BindingResult
接口和它的父接口Errors
中定义了很多和数据绑定相关的方法,如果在数据绑定过程中发生了错误,那么通过这个接口类型的对象就可以获取到相关错误信息。
@RequestMapping("/save/product")
public String saveProduct(
Product product,
// 在实体类参数和 BindingResult 之间不能有任何其他参数
// 封装数据绑定结果的对象
BindingResult bindingResult) {
// 判断数据绑定过程中是否发生了错误
if (bindingResult.hasErrors()) {
// 如果发生了错误,则跳转到专门显示错误信息的页面
// 相关错误信息会自动被放到请求域
return "error";
}
logger.debug(product.toString());
return "target";
}
<p th:errors="${product.productDate}">这里显示具体错误信息p>
在实际开发过程中,难免会有某些情况需要使用自定义类型转换器。因为我们自己自定义的类型在 SpringMVC 中没有对应的内置类型转换器。此时需要我们提供自定义类型来执行转换。
public class Address {
private String province;
private String city;
private String street;
……
public class Student {
private Address address;
……
实现接口:org.springframework.core.convert.converter.Converter
;
泛型S:源类型(本例中是String类型)
泛型T:目标类型(本例中是Address类型)
public class AddressConverter implements Converter<String, Address> {
@Override
public Address convert(String source) {
// 1.按照约定的规则拆分源字符串
String[] split = source.split(",");
String province = split[0];
String city = split[1];
String street = split[2];
// 2.根据拆分结果创建 Address 对象
Address address = new Address(province, city, street);
// 3.返回转换得到的对象
return address;
}
}
<mvc:annotation-driven conversion-service="formattingConversionService"/>
<bean id="formattingConversionService"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.atguigu.mvc.converter.AddressConverter"/>
set>
property>
bean>
<h3>自定义类型转换器h3>
<form th:action="@{/save/student}" method="post">
地址:<input type="text" name="address" value="aaa,bbb,ccc" /><br/>
form>
@RequestMapping("/save/student")
public String saveStudent(Student student) {
logger.debug(student.getAddress().toString());
return "target";
}
在 Web 应用三层架构体系中,表述层负责接收浏览器提交的数据,业务逻辑层负责数据的处理。为了能够让业务逻辑层基于正确的数据进行处理,我们需要在表述层对数据进行检查,将错误的数据隔绝在业务逻辑层之外。
JSR 303 是 Java 为 Bean 数据合法性校验提供的标准框架,它已经包含在JavaEE 6.0标准中。JSR 303通过在Bean属性上标注类似于 @NotNull
、@Max
等标准的注解指定校验规则,并通过标准的验证接口对Bean进行验证。
注解 | 规则 |
---|---|
@Null | 标注值必须为 null |
@NotNull | 标注值不可为 null |
@AssertTrue | 标注值必须为 true |
@AssertFalse | 标注值必须为 false |
@Min(value) | 标注值必须大于或等于 value |
@Max(value) | 标注值必须小于或等于 value |
@DecimalMin(value) | 标注值必须大于或等于 value |
@DecimalMax(value) | 标注值必须小于或等于 value |
@Size(max,min) | 标注值大小必须在 max 和 min 限定的范围内 |
@Digits(integer,fratction) | 标注值值必须是一个数字,且必须在可接受的范围内 |
@Past | 标注值只能用于日期型,且必须是过去的日期 |
@Future | 标注值只能用于日期型,且必须是将来的日期 |
@Pattern(value) | 标注值必须符合指定的正则表达式 |
JSR 303 只是一套标准,需要提供其实现才可以使用。Hibernate Validator 是 JSR 303 的一个参考实现,除支持所有标准的校验注解外,它还支持以下的扩展注解:
注解 | 规则 |
---|---|
标注值必须是格式正确的 Email 地址 | |
@Length | 标注值字符串大小必须在指定的范围内 |
@NotEmpty | 标注值字符串不能是空字符串 |
@Range | 标注值必须在指定的范围内 |
Spring 4.0 版本已经拥有自己独立的数据校验框架,同时支持 JSR 303 标准的校验框架。Spring 在进行数据绑定时,可同时调用校验框架完成数据校验工作。在SpringMVC 中,可直接通过注解驱动 mvc:annotation-driven
的方式进行数据校验。Spring 的 LocalValidatorFactoryBean
既实现了 Spring 的 Validator
接口,也实现了 JSR 303 的 Validator
接口。只要在Spring容器中定义了一个LocalValidatorFactoryBean
,即可将其注入到需要数据校验的Bean中。Spring本身并没有提供JSR 303的实现,所以必须将JSR 303的实现者的jar包放到类路径下。
配置 mvc:annotation-driven
后,SpringMVC 会默认装配好一个 LocalValidatorFactoryBean
,通过在处理方法的入参上标注 @Validated
注解即可让 SpringMVC 在完成数据绑定后执行数据校验的工作。
<dependency>
<groupId>org.hibernate.validatorgroupId>
<artifactId>hibernate-validatorartifactId>
<version>6.2.0.Finalversion>
dependency>
<dependency>
<groupId>org.hibernate.validatorgroupId>
<artifactId>hibernate-validator-annotation-processorartifactId>
<version>6.2.0.Finalversion>
dependency>
标记规则注解:
// 字符串长度:[3,6]
@Size(min = 3, max = 6)
// 字符串必须满足Email格式
@Email
private String email;
在处理方法形参注解:
@RequestMapping("/save/person")
public String saveperson(@Validated Person person) {
logger.debug(person.getEmail());
return "target";
}
使用 @RequestMapping
注解的 params
参数实现,表达式语法参见下面的例子:
需求 | 映射方式 |
---|---|
请求参数中必须包含userName | @RequestMapping(value = “/xxx”, params=“userName”) |
请求参数中不能包含userName | @RequestMapping(value = “/xxx”, params=“!userName”) |
请求参数中必须包含userName且值必须为Tom2015 | @RequestMapping(value = “/xxx”, params=“userName=Tom2015”) |
请求参数中必须包含userName但值不能为Tom2015 | @RequestMapping(value = “/xxx”, params=“userName=!Tom2015”) |
请求参数中必须包含userName且值为Tom2015,同时必须包含userPwd但值不限 | @RequestMapping(value = “/xxx”, params={“userName=Tom2015”,“userPwd”} ) |
使用 @RequestMapping
注解的 headers 参数实现,表达式语法参见下面的例子:
需求 | 映射方式 |
---|---|
根据 Accept-Language:zh-CN,zh;q=0.8 映射 | @RequestMapping (value=“/xxx”,headers= “Accept-Language=zh-CN,en;q=0.8” ) |
@ModelAttribute
注解handler 类中,选定一个方法标记 @ModelAttribute 注解。
@Controller
public class ModelAttrHandler {
@ModelAttribute
public void doSthBefore(Model model) {
model.addAttribute("initAttr", "initValue");
}
@RequestMapping("/test/model/attr/one")
public String testModelAttrOne(Model model) {
Object modelAttribute = model.getAttribute("initAttr");
System.out.println("modelAttribute = " + modelAttribute);
return "target";
}
@RequestMapping("/test/model/attr/two")
public String testModelAttrTwo(Model model) {
Object modelAttribute = model.getAttribute("initAttr");
System.out.println("modelAttribute = " + modelAttribute);
return "target";
}
@RequestMapping("/test/model/attr/three")
public String testModelAttrThree(Model model) {
Object modelAttribute = model.getAttribute("initAttr");
System.out.println("modelAttribute = " + modelAttribute);
return "target";
}
}
@RequestHeader
注解通过这个注解获取请求消息头中的具体数据。
@RequestMapping("/request/header")
public String getRequestHeader(
// 使用 @RequestHeader 注解获取请求消息头信息
// name 或 value 属性:指定请求消息头名称
// defaultValue 属性:设置默认值
@RequestHeader(name = "Accept", defaultValue = "missing") String accept
) {
logger.debug("accept = " +accept);
return "target";
}