Spring 全家桶之 Spring Web MVC(五)- Data Binder(下)

简介: Spring 全家桶之 Spring Web MVC(五)- Data Binder

四、数据格式化及校验

4-1 数据格式化

  • Spring 在格式化模块中定义了一个实现ConversionService接口的FormattingConversionService实现类,该实现类扩展了GenericConversionService,因此它也具有类型转换的功能又具有格式化的功能。
  • FormattingConversionService拥有一个FormattingConversionServiceFactory工厂类,后者用于在Spring上下文中构造前者。

以时间格式化为例,在add.jsp页面添加员工表单增加birth属性

db6b888a45f746e5bf1a3d9976168024_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

list.jsp页面添加birth属性列,在Employee实体类增加birth属性

96076fd886cc4251bcd13d3db758624f_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

运行添加员工,输入的时间格式为yyyy-MM-DD

78e6b76d0ac443179149e4913abf0e51_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

只有当时间格式为yyyy/MM/DD时才才能成功添加

ae4978bac49e45e18115fe67769180b8_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

如何能正确处理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>
复制代码

再次测试可以添加成功

fbf46483a47d481db6871f673a37b723_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

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目录下

48da6130976545a5a725348aa328da42_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

在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,执行添加操作

b50cd511cb204360a7878fdc9068d3c1_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

如何通过其他方式取出错误信息

修改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,在执行添加操作

d7af327d6188414f90cafc2015d8303b_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

每个属性在数据绑定和数据校验发生错误时,都会生成一个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,执行添加操作

70388ab996604a40b5e3ae46a1ce501e_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

如何将错误的字段值回显到报错信息中?

以中文的国际化配置文件为例

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,执行添加操作

5f3268893e0a4b97a8d499f289c86fd8_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


相关文章
|
5月前
|
缓存 安全 Java
《深入理解Spring》过滤器(Filter)——Web请求的第一道防线
Servlet过滤器是Java Web核心组件,可在请求进入容器时进行预处理与响应后处理,适用于日志、认证、安全、跨域等全局性功能,具有比Spring拦截器更早的执行时机和更广的覆盖范围。
|
5月前
|
NoSQL Java 数据库连接
《深入理解Spring》Spring Data——数据访问的统一抽象与极致简化
Spring Data通过Repository抽象和方法名派生查询,简化数据访问层开发,告别冗余CRUD代码。支持JPA、MongoDB、Redis等多种存储,统一编程模型,提升开发效率与架构灵活性,是Java开发者必备利器。(238字)
|
5月前
|
前端开发 Java 微服务
《深入理解Spring》:Spring、Spring MVC与Spring Boot的深度解析
Spring Framework是Java生态的基石,提供IoC、AOP等核心功能;Spring MVC基于其构建,实现Web层MVC架构;Spring Boot则通过自动配置和内嵌服务器,极大简化了开发与部署。三者层层演进,Spring Boot并非替代,而是对前者的高效封装与增强,适用于微服务与快速开发,而深入理解Spring Framework有助于更好驾驭整体技术栈。
|
5月前
|
存储 Java 关系型数据库
Spring Boot中Spring Data JPA的常用注解
Spring Data JPA通过注解简化数据库操作,实现实体与表的映射。常用注解包括:`@Entity`、`@Table`定义表结构;`@Id`、`@GeneratedValue`配置主键策略;`@Column`、`@Transient`控制字段映射;`@OneToOne`、`@OneToMany`等处理关联关系;`@Enumerated`、`@NamedQuery`支持枚举与命名查询。合理使用可提升开发效率与代码可维护性。(238字)
542 1
存储 JSON Java
767 0
|
6月前
|
存储 安全 Java
如何在 Spring Web 应用程序中使用 @SessionScope 和 @RequestScope
Spring框架中的`@SessionScope`和`@RequestScope`注解用于管理Web应用中的状态。`@SessionScope`绑定HTTP会话生命周期,适用于用户特定数据,如购物车;`@RequestScope`限定于单个请求,适合无状态、线程安全的操作,如日志记录。合理选择作用域能提升应用性能与可维护性。
278 1
|
6月前
|
SQL Java 数据库连接
Spring Data JPA 技术深度解析与应用指南
本文档全面介绍 Spring Data JPA 的核心概念、技术原理和实际应用。作为 Spring 生态系统中数据访问层的关键组件,Spring Data JPA 极大简化了 Java 持久层开发。本文将深入探讨其架构设计、核心接口、查询派生机制、事务管理以及与 Spring 框架的集成方式,并通过实际示例展示如何高效地使用这一技术。本文档约1500字,适合有一定 Spring 和 JPA 基础的开发者阅读。
641 0
|
7月前
|
存储 NoSQL Java
探索Spring Boot的函数式Web应用开发
通过这种方式,开发者能以声明式和函数式的编程习惯,构建高效、易测试、并发友好的Web应用,同时也能以较小的学习曲线迅速上手,因为这些概念与Spring Framework其他部分保持一致性。在设计和编码过程中,保持代码的简洁性和高内聚性,有助于维持项目的可管理性,也便于其他开发者阅读和理解。
225 0
|
8月前
|
前端开发 Java API
Spring Cloud Gateway Server Web MVC报错“Unsupported transfer encoding: chunked”解决
本文解析了Spring Cloud Gateway中出现“Unsupported transfer encoding: chunked”错误的原因,指出该问题源于Feign依赖的HTTP客户端与服务端的`chunked`传输编码不兼容,并提供了具体的解决方案。通过规范Feign客户端接口的返回类型,可有效避免该异常,提升系统兼容性与稳定性。
571 0
|
8月前
|
SQL Java 数据库连接
Spring、SpringMVC 与 MyBatis 核心知识点解析
我梳理的这些内容,涵盖了 Spring、SpringMVC 和 MyBatis 的核心知识点。 在 Spring 中,我了解到 IOC 是控制反转,把对象控制权交容器;DI 是依赖注入,有三种实现方式。Bean 有五种作用域,单例 bean 的线程安全问题及自动装配方式也清晰了。事务基于数据库和 AOP,有失效场景和七种传播行为。AOP 是面向切面编程,动态代理有 JDK 和 CGLIB 两种。 SpringMVC 的 11 步执行流程我烂熟于心,还有那些常用注解的用法。 MyBatis 里,#{} 和 ${} 的区别很关键,获取主键、处理字段与属性名不匹配的方法也掌握了。多表查询、动态
234 0