四、数据格式化及校验
4-1 数据格式化
- Spring 在格式化模块中定义了一个实现ConversionService接口的FormattingConversionService实现类,该实现类扩展了GenericConversionService,因此它也具有类型转换的功能又具有格式化的功能。
- FormattingConversionService拥有一个FormattingConversionServiceFactory工厂类,后者用于在Spring上下文中构造前者。
以时间格式化为例,在add.jsp页面添加员工表单增加birth属性
list.jsp页面添加birth属性列,在Employee实体类增加birth属性
运行添加员工,输入的时间格式为yyyy-MM-DD
只有当时间格式为yyyy/MM/DD时才才能成功添加
如何能正确处理yyyy-MM-DD?使用@DataTimeFormate注解可以指定日期的格式
在Employee实体类的birth属性上添加@DateTimeFormat注解,指定时间的格式
@DateTimeFormat(pattern = "yyyy-MM-dd") private Date birth; 复制代码
添加还是失败,只是因为我们使用的conversionService不具备格式化功能,将 Spring MVC 配置文件中注册的
org.springframework.context.support.ConversionServiceFactoryBean 复制代码
换成
org.springframework.format.support.FormattingConversionServiceFactoryBean 复制代码
<!--使用自定义的ConverterService--> <bean id="conversionServiceFactory" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <!--中间内容不变--> </bean> 复制代码
再次测试可以添加成功
FormattingConversionServiceFactoryBean内部注册了以下组件
- NumberFormatAnnotationFormatterFactory:支持对数字类型的属性使用
@NumberFormat
注解 - JodaDateTimeFormatAnnotationFormatterFactory:支持对日期类型的属性使用
@DateTimeFormat
注解
@NumerbFormat注解可以对数值类型的属性进行设置,该注解本身拥有两个属性 style:类型为NumberFormat.Style,用于指定样式类型,有三种:Style.NUMBER正常数字类型、Style.CURRENCY既货币类型、Style.PERCENT百分比类型 pattern:类型为String,可以自定义样式,如“#,###,###”等
4-2 数据校验
JSR 既 Java Specification Requests,Java规范请求,是Java为Bean数据合法性校验提供的标准框架,JSR 通过在Bean的属性上增加@NotNull、@Null、@Max等注解来指定属性的校验规则,并且自定义校验失败的提示信息。JSR是一套校验规范,Hibernate Validator实现了JSR,并且扩展了@Email、@Length、@NotEmpty、@Range注解。
关于校验框架的介绍及使用也可以参考你有没有使用过这些编程骚操作(二)- 验证框架 Part A、B、C 三部分
在Spring MVC中使用校验框架首先要引入validation依赖和hibernate实现以及el表达式的规范和实现
<dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.16.Final</version> </dependency> <dependency> <groupId>javax.el</groupId> <artifactId>javax.el-api</artifactId> <version>3.0.0</version> </dependency> <dependency> <groupId>org.glassfish.web</groupId> <artifactId>javax.el</artifactId> <version>2.2.6</version> </dependency> 复制代码
添加依赖后,要将Jar包全部PUT 进 lib目录下
在Employee实体类的属性上增加校验的注解
@NotEmpty @Length(min = 5,max = 8) private String lastName; @Email private String email; 复制代码
在方法入参中加入@Valid
注解,对出传来的参数进行校验,并使用BindingResult
来保存校验的结果
@RequestMapping(value = "/emp", method = RequestMethod.POST) public String addEmp(@Valid Employee employee, BindingResult result){ System.out.println("要添加的员工信息:" + employee); boolean hasErrors = result.hasErrors(); if (hasErrors){ System.out.println("属性校验错误"); return "add"; } employeeDao.save(employee); // 返回列表页面 return "redirect:/emps"; } 复制代码
在jsp页面中解析校验结果
LastName:<form:input path="lastName"/><form:errors path="lastName" /><br/> Email:<form:input path="email"/><form:errors path="email" /><br/> <!--其他内容不变--> birth:<form:input path="birth" /><form:errors path="birth" /><br> 复制代码
重启Tomcat,执行添加操作
如何通过其他方式取出错误信息
修改addEmp方法,通过BindingResult的getFieldErrors方法取出具体的错误信息,并输出错误代码
@RequestMapping(value = "/emp", method = RequestMethod.POST) public String addEmp(@Valid Employee employee, BindingResult result, Model model){ Map<String, Object> errorMap = new HashMap<>(); System.out.println("要添加的员工信息:" + employee); boolean hasErrors = result.hasErrors(); if (hasErrors){ System.out.println("属性校验错误"); // 获取详细报错信息 List<FieldError> fieldErrors = result.getFieldErrors(); for (FieldError fieldError : fieldErrors) { System.out.println("出错字段为:" + fieldError.getField() + ",报错信息为:" + fieldError.getDefaultMessage()); // 获取错误代码,用来作为国际化配置的Key String[] codes = fieldError.getCodes(); for (String code : codes) { System.out.println(code); } errorMap.put(fieldError.getField(),fieldError.getDefaultMessage()); } model.addAttribute("errorMap", errorMap); return "add"; } System.out.println(result); employeeDao.save(employee); // 返回列表页面 return "redirect:/emps"; } 复制代码
重启Tomcat,在执行添加操作
每个属性在数据绑定和数据校验发生错误时,都会生成一个FieldError对象 当一个属性校验失败后,校验框架会为该属性生成4个消息代码,这些代码以校验注解类名为前缀,结合modelAttribute、属性名以及属性类型名生成多个对应的消息代码
输出的错误信息都是英文,可以进行国际化配置根据浏览器的语言显示报错信息,当使用Spring MVC 时,Spring MVC会查看Web上下文是否配置了国际化消息,如果有则显示国际化消息,如果没有显示默认的信息
在resources目录下新增中文和英文的国际化配置文件error_zh_CN.properties和error_en_US.properties
Email.email=email wrong, retry NotEmpty=can't be empty Length.java.lang.String=length incorrect Past=must be a past time 复制代码
Email.email=\u90AE\u7BB1\u4E0D\u5BF9 NotEmpty=\u4E0D\u80FD\u4E3A\u7A7A Length.java.lang.String= \u957F\u5EA6\u4E0D\u5BF9 Past=\u65F6\u95F4\u5FC5\u987B\u662F\u8FC7\u53BB\u7684 typeMismatch.birth=\u751F\u65E5\u7684\u683C\u5F0F\u4E0D\u6B63\u786E 复制代码
在Spring MVC 配置文件中增加国际化配置
<!--国际化配置--> <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basename" value="error"></property> </bean> 复制代码
重启Tomcat,执行添加操作
如何将错误的字段值回显到报错信息中?
以中文的国际化配置文件为例
Email.email=\u90AE\u7BB1\u4E0D\u5BF9 - {0} NotEmpty=\u4E0D\u80FD\u4E3A\u7A7A - {0} Length.java.lang.String= \u957F\u5EA6\u4E0D\u5BF9 - {0} {1} {2} Past=\u65F6\u95F4\u5FC5\u987B\u662F\u8FC7\u53BB\u7684 - {0} typeMismatch.birth=\u751F\u65E5\u7684\u683C\u5F0F\u4E0D\u6B63\u786E - {0} 复制代码
- {0}:永远表示当前校验的属性名
- {1}和{2}表示注解中设置的属性的value,取得顺序是按照字母排列来的
重新启动Tomcat,执行添加操作