springMvc-07 类型转换/格式化/数据校验
前端给后端传递数据进行数据绑定时,会经过类型转换,数据格式化,以及数据校验的过程。
1、类型转换
SpringMVC框架提供了一个通用的类型转换模块,该类型转换模块位于包org.springframework.core.convert中,可以在处理方法的参数绑定中使用他们进行数据转换。
SpringMVC框架中内置了很多的类型转换。


3)自定义类型转换
默认类型转换器并不是可以将用户提交的内容,转换为用户需要的所有类型。此时 ,就需要自定义类型转换器了
例如:我们文本框里边要输入2021-01-01之后要让其转换为日期类型,则需要自定义类型转换器。
自定义类型转换器的方式有3三种:
1)Converter<S,T>:是SpringMVC最简单的一个转换器接口,可以实现任意类型间的相互转换,负责把S转为T
2)ConverterFactory<S,R>:将一种类型的对象转换成另一个类型及其子类型对象。其中S为转换的源类型,R为目标类型的基类,T为R的子类。
3)GenericConverter,转换方法参数中包含TypeDescriptor类型的参数,这个参数包含了上下文信息,能够根据上下文信息进行类型转换。
举例:
1)转换器实现
package rui.tool;
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class StringToDateConverter implements Converter<String,Date> {
//日期的格式,定义一个变量,允许配置Bean的时候动态的指定
private String datePattern;
public String getDatePattern() {
return datePattern;
}
public void setDatePattern(String datePattern) {
this.datePattern = datePattern;
}
@Override
public Date convert(String s) {
if(s==null || "".equals(s.trim())) {
return null;
}
SimpleDateFormat sdf = new SimpleDateFormat(datePattern);
Date result = null;
try {
result = sdf.parse(s);
}
catch (ParseException e)
{
e.printStackTrace();
System.out.println("转换失败");
}
return result;
}
}
2)SpringMVC配置
<!--开启自动注册处理器映射器和处理器适配器-->
<!--开启Spring的valid功能 validator="validator" -->
<mvc:annotation-driven validator="validator" conversion-service="formatService" />
<!--配置类型转换和格式化-->
<bean id="formatService"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="rui.tool.StringToDateConverter">
<property name="datePattern" value="yyyy-MM-dd" />
</bean>
</list>
</property>
</bean>
2、数据格式化
从Spring3.0开始,引入了格式化转换框架,该框架位于Spring-context.jar包中。
Spring在格式化模块中定义了一个实现ConversionService接口的FormattingConversionService实现类,该类既具有类型转换功能,有具有格式化功能。
Formatter和Converter基本功能一样, 是将一种类型转换成另一种类型, 但是,Formatter的源类型必须是一个String, 目标类型是java类型.
通过FormattingConversionServiceFactoryBean即可以实现注册定义的转换器,也可以注册自定义的格式化器。
Spring内置了很多的格式化转换器,也允许我们自定义,例如定义了一个坐标类Point,内部包含x,y属性,如果表单上输入2,3之后,能够将其转换为Point对象,则需要自己编写数据格式化器。
1) 内置的格式化
| 名称 | 功能 |
| NumberFormatter | 实现Number与String之间的解析与格式化 |
| CurrencyFormatter | 实现Number与String之间的解析与格式化(带货币符号) |
| PercentFormatter | 实现Number与String之间的解析与格式化(带百分数符号) |
| DateFormatter | 实现Date与String之间的解析与格式化 |
| NumberFormatAnnotationFormatterFactory | @NumberFormat注解,实现Number与String之间的解析与格式化,可以通过指定style来指示要转换的格式(Style.Number/Style.Currency/Style.Percent),当然也可以指定pattern(如pattern=“#.##”(保留2位小数) ),这样pattern指定的格式会覆盖掉Style指定的格式 |
| JodaDateTimeFormatAnnotationFormatterFactory | @DateTimeFormat注解,实现日期类型与String之间的解析与格式化这里的日期类型包括Date、Calendar、Long以及Joda的日期类型。必须在项目中添加Joda-Time包 |
2)自定义格式化
举例:
1)格式化器实现
package rui.tool;
import org.springframework.format.Formatter;
import rui.db.Model.Point;
import java.text.ParseException;
import java.util.Locale;
public class StringToPointFormatter implements Formatter<Point> {
@Override
public Point parse(String s, Locale locale) throws ParseException {
if(s==null || "".equals(s.trim())) {
return null;
}
String[] array = s.split(",");
if(array.length==2)
{
Point p = new Point();
p.setX(Integer.parseInt(array[0]));
p.setY(Integer.parseInt(array[1]));
return p;
}
return null;
}
@Override
public String print(Point point, Locale locale) {
if(point!= null)
{
return point.getX()+","+point.getY();
}
return "";
}
}
2)SpringMvc配置
类型转换和格式化可以放在一个Bean中配置。
<!--开启自动注册处理器映射器和处理器适配器-->
<!--开启Spring的valid功能 validator="validator" -->
<mvc:annotation-driven validator="validator" conversion-service="formatService" />
<!--配置类型转换和格式化-->
<bean id="formatService"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="formatters">
<list>
<bean class="rui.tool.StringToPointFormatter" />
</list>
</property>
</bean>

3)基于注解的格式化
@DateTimeFormat可以对Date和Calendar等时间类型的属性进行标准。
DateTimeFormat.ISO.DATE: 格式yyyy-MM-dd。DateTimeFormat.ISO.DATE_TIME: 格式yyyy-MM-dd HH:mm:ss .SSSZ。DateTimeFormat.ISO.TIME: 格式HH:mm:ss .SSSZ。DateTimeFormat.ISO.NONE: 表示不使用ISO格式的时间。
该标准拥有两个属性:
- pattern。类型为String,使用自定义的时间格式化字符串。
- style。类型为String,通过样式指定日期时间的格式,由两位字符组成,第1位表示日期的样式,第2位表示时间的格式:
- S: 短日期/时间的样式;
- M: 中日期/时间的样式;
- L: 长日期/时间的样式;
- F: 完整日期/时间的样式;
- -: 忽略日期/时间的样式;
@NumberFormat可对类似数字类型的属性进行标准,它拥有两个互斥的属性。
- pattern。类型为String,使用自定义的数字格式化字符串,"##,###.##"。
- style。类型为
NumberFormat.Style,常用值:Style.NUMBER正常数字类型Style.PERCENT百分数类型Style.CURRENCY货币类型
例子代码:
// 域对象,实现序列化接口
public class User implements Serializable{
// 日期类型
@DateTimeFormat(pattern="yyyy-MM-dd")
private Date birthday;
// 正常数字类型
@NumberFormat(style=Style.NUMBER, pattern="#,###")
private int total;
// 百分数类型
@NumberFormat(style=Style.PERCENT)
private double discount;
// 货币类型
@NumberFormat(style=Style.CURRENCY)
private double money;
}
填写数据和展示效果:

3、数据校验
SpringMVC提供了强大的数据验证功能,其中有两种方法可以验证输入
1)利用Spring自定的validation校验框架。
2)利用JSR303(Java验证规范)实现验证功能
这里极少JSR303的使用方法。
3.1、导入需要的包
<!--JSR3.0校验-->
<!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>7.0.0.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.jboss.logging/jboss-logging -->
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>3.3.2.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml/classmate -->
<dependency>
<groupId>com.fasterxml</groupId>
<artifactId>classmate</artifactId>
<version>1.5.1</version>
</dependency>
3.2、springmvc.xml注册校验器
<!--开启自动注册处理器映射器和处理器适配器-->
<!--开启Spring的valid功能 validator="validator" -->
<mvc:annotation-driven validator="validator" conversion-service="formatService" />
<!--配置验证器-->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="providerClass" value="org.hibernate.validator.HibernateValidator"></property>
</bean>

3.3、常用验证特性
| 注解 | 功能 |
|---|---|
| @Null | 对象必须为null |
| @NotNull | 对象必须不为null,无法检查长度为0的字符串 |
| @NotBlank | 字符串必须不为Null,且去掉前后空格长度必须大于0 |
| @AssertTrue | 对象必须为true |
| @AssertFalse | 对象必须为false |
| @Max(Value) | 必须为数字,且小于或等于Value |
| @Min(Value) | 必须为数字,且大于或等于Value |
| @DecimalMax(Value) | 必须为数字( BigDecimal ),且小于或等于Value。小数存在精度 |
| @DecimalMin(Value) | 必须为数字( BigDecimal ),且大于或等于Value。小数存在精度 |
| @Digits(integer,fraction) | 必须为数字( BigDecimal ),integer整数精度,fraction小数精度 |
| @Size(min,max) | 对象(Array、Collection、Map、String)长度必须在给定范围 |
| @Range(min,max) | 验证数字是否介入min和max之间 |
| 字符串必须是合法邮件地址 | |
| @Past | Date和Calendar对象必须在当前时间之前 |
| @Future | Date和Calendar对象必须在当前时间之后 |
| @Pattern(regexp=“正则”) | String对象必须符合正则表达式 |
| @Url | 验证是否合法的Url地址 |
| @CreditCardNumber | 信用卡校验 |
3.4、例子
1)在模型类上增加标准

2)控制器内判断验证是否有问题
- 给模型类前边增加@Valid标准,代表User对象绑定时会检查验证规则。
- BindResult参数必须紧跟在有@Valid参数的后边,用来获取绑定之后的错误信息
- 如果有验证错误,则重新返回到填写界面,需要把界面需要的数据都携带上。
//用户注册提交
@RequestMapping(value = "register", method = RequestMethod.POST)
public String register(Model model, @Valid User user, BindingResult bindResult,
List<MultipartFile> headImgUpload,
HttpServletRequest request
) {
System.out.println("执行TestController==2");
System.out.println(bindResult.toString());
//验证不通过
if (bindResult.getFieldErrorCount() > 0) {
//获取所有的错误
List<ObjectError> errList = bindResult.getAllErrors();
for(ObjectError err:errList)
{
System.out.println(err.toString());
}
model.addAttribute("user", user);
model.addAttribute("sexList", rui.tool.listHelper.getSex());
model.addAttribute("deptList", rui.tool.listHelper.getSex());
model.addAttribute("loveList", rui.tool.listHelper.getLove());
return "/test/register";
}
model.addAttribute("user", user);
return "forward:/test/showInfo";
}
3)前端JSP页面显示错误
<div>用户账号:<f:input path="loginId" data-id="123" /><f:errors path="loginId"/> </div>
如果是前后端分离的,需要自己获取错误描述信息,并通过JSON返回。

浙公网安备 33010602011771号