⭐⭐⭐⭐⭐⭐
Github主页👉https://github.com/A-BigTree
笔记链接👉https://github.com/A-BigTree/Code_Learning
⭐⭐⭐⭐⭐⭐
如果可以,麻烦各位看官顺手点个star~😊
如果文章对你有所帮助,可以点赞👍收藏⭐支持一下博主~😆
文章目录
- 10 其他概念
- 10.1 类型转换
- 10.1.1 自动类型转换
- 10.1.2 日期和数值类型
- 注解设定数据格式
- 表单
- 处理方法
- 10.1.3 转换失败处理方式
- `BindingResult`接口
- 重构处理方法
- 页面显示错误信息
- 10.1.4 自定义类型转换器
- 创建实体类
- 创建自定义类型转换器类
- Spring-MVC中注册
- 表单
- 处理方法
- 10.2 数据校验
- 10.2.1 校验概述
- 10.2.2 操作
- 导入依赖
- 应用校验规则
- 10.3 请求映射的其他方式
- 10.3.1 根据请求参数情况映射
- 10.3.2 根据请求消息头内容映射
- 10.3.3 Ant风格通配符
- 10.4 `@ModelAttribute`注解
- 10.5 `@RequestHeader`注解
10 其他概念
10.1 类型转换
SpringMVC 将『把请求参数注入到POJO对象』这个操作称为『数据绑定』,英文单词是 binding。数据类型的转换和格式化就发生在数据绑定的过程中。 类型转换和格式化是密不可分的两个过程,很多带格式的数据必须明确指定格式之后才可以进行类型转换。最典型的就是日期类型。
10.1.1 自动类型转换
HTTP 协议是一个无类型的协议,我们在服务器端接收到请求参数等形式的数据时,本质上都是字符串类型。请看 javax.servlet.ServletRequest 接口中获取全部请求参数的方法:
public Map<String, String[]> getParameterMap();
而我们在实体类当中需要的类型是非常丰富的。对此,SpringMVC对基本数据类型提供了自动的类型转换。例如:请求参数传入“100”字符串,我们实体类中需要的是 Integer 类型,那么 SpringMVC 会自动将字符串转换为 Integer 类型注入实体类。
10.1.2 日期和数值类型
注解设定数据格式
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";
}
10.1.3 转换失败处理方式
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";
}
页面显示错误信息
<!-- th:errors 属性:用来显示请求处理过程中发生的错误 -->
<!-- th:errors 属性值:访问错误信息的表达式 -->
<!-- 访问错误信息的表达式:访问请求域,需要使用 ${} 格式 -->
<!-- 访问请求域使用的属性名:执行数据绑定的实体类的简单类名首字母小写 -->
<!-- 具体错误信息:找到实体类之后进一步访问出问题的属性名 -->
<p th:errors="${product.productDate}">这里显示具体错误信息</p>
10.1.4 自定义类型转换器
在实际开发过程中,难免会有某些情况需要使用自定义类型转换器。因为我们自己自定义的类型在 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,T>
;
泛型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;
}
}
Spring-MVC中注册
<!-- 在 mvc:annotation-driven 中注册 FormattingConversionServiceFactoryBean -->
<mvc:annotation-driven conversion-service="formattingConversionService"/>
<!-- 在 FormattingConversionServiceFactoryBean 中注册自定义类型转换器 -->
<bean id="formattingConversionService"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<!-- 在 converters 属性中指定自定义类型转换器 -->
<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";
}
10.2 数据校验
在 Web 应用三层架构体系中,表述层负责接收浏览器提交的数据,业务逻辑层负责数据的处理。为了能够让业务逻辑层基于正确的数据进行处理,我们需要在表述层对数据进行检查,将错误的数据隔绝在业务逻辑层之外。
10.2.1 校验概述
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 在完成数据绑定后执行数据校验的工作。
10.2.2 操作
导入依赖
<!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.2.0.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator-annotation-processor -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator-annotation-processor</artifactId>
<version>6.2.0.Final</version>
</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";
}
10.3 请求映射的其他方式
10.3.1 根据请求参数情况映射
使用 @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”} ) |
10.3.2 根据请求消息头内容映射
使用 @RequestMapping
注解的 headers 参数实现,表达式语法参见下面的例子:
需求 | 映射方式 |
---|---|
根据 Accept-Language:zh-CN,zh;q=0.8 映射 | @RequestMapping (value=“/xxx”,headers= “Accept-Language=zh-CN,en;q=0.8” ) |
10.3.3 Ant风格通配符
- 英文问号:匹配一个字符
- 一个星号:匹配路径中的一层
- 两个连续星号:匹配路径中的多层
10.4 @ModelAttribute
注解
handler 类中,选定一个方法标记 @ModelAttribute 注解。
- 效果1:在每个 handler 方法前执行
- 效果2:可以将某些数据提前存入请求域
@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";
}
}
10.5 @RequestHeader
注解
通过这个注解获取请求消息头中的具体数据。
@RequestMapping("/request/header")
public String getRequestHeader(
// 使用 @RequestHeader 注解获取请求消息头信息
// name 或 value 属性:指定请求消息头名称
// defaultValue 属性:设置默认值
@RequestHeader(name = "Accept", defaultValue = "missing") String accept
) {
logger.debug("accept = " +accept);
return "target";
}