08.SpringMVC_数据绑定的流程

1.当我们提交表单,将表单中的数据绑定的方法的入参的对象中时,会涉及到数据绑定的流程,数据绑定的流程分为:数据类型转换、数据格式化、数据校验
08.SpringMVC_数据绑定的流程
  1. 数据类型转换
  • SpringMVC默认为我们装配了以下类型转换器:
  • 如果SpringMVC默认的类型转换器不能满足我们的需求,我们可以自定义类型转换器,如:将一个字符串转换为Employee对象
    • 创建一个类实现Converter<S,T>接口
public class MyConverter implements Converter<String, Employee> {
   // [email protected]-1-101 这种格式的写法转换
    @Override
    public Employee convert(String arg0) {
         Employee employee  = null;
         if(arg0 != null){
             String[] split = arg0.split("-");
             if(split != null && split.length == 4){
                 //获取姓名
                 String lastName = split[0];
                 //获取邮箱
                 String email = split[1];
                 //获取性别
                 int gender = Integer.parseInt(split[2]);
                 //获取部门的id
                 int deptId = Integer.parseInt(split[3]);
                 //创建Employee对象
                 employee  = new Employee();
                 employee.setLastName(lastName);
                 employee.setEmail(email);
                 employee.setGender(gender);
                 employee.setDepartment(new DepartmentDao().getDepartment(deptId));
             }
         }
         return employee;
    }
}
  • 在SpringMVC配置文件中配置自定义的类型转换器
 <!-- 配置类型转换器 -->
     <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
             <set>
                 <bean class="com.atguigu.springmvc.converter.MyConverter"></bean>
             </set>
        </property>
     </bean>
     <mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
这个必须写在<mvc:annotation-driven></mvc:annotation-driven>之前才行
// 测试自定义转换器
    @RequestMapping(value = "/testMyConverter", method = RequestMethod.POST)
    public String testMyConverter(@RequestParam("employee") Employee employee) {
       // 保存该员工
       System.out.println(employee);
       employeeDao.save(employee);
       return "redirect:/getEmployees";
    
  • 备注:
   在Handler中通过 @InitBinder这个标签在数据绑定的过程不允许给某一个属性赋值
 @InitBinder
    public void initGender(WebDataBinder dataBinder){
        //数据绑定的过程不允许给性别赋值
        dataBinder.setDisallowedFields("gender");
    }
  • @InitBinder方法不能有返回值,它必须声明为void。
  • @InitBinder方法的参数通常是 WebDataBinder

  • 备注:
<mvc:annotation-driven/>配置在什么时候必须配置?
  1. 直接配置响应的页面:无需经过控制器来执行结果 ;但会导致其他请求路径失效,需要配置mvc:annotation-driven标签<mvc:view-controller path="/success" view-name="success"/>
  2. 通过jQuery执行delete请求时,找不到静态资源,需要配置mvc:annotation-driven标签   
  3. 配置类型转换器服务时,需要指定转换器服务引用<mvc:annotation-driven conversion-service=“conversionService”/> 会将自定义的ConversionService 注册到 Spring MVC 的上下文中
  4. 数据验证,也需要配置 
3.数据的格式化
  • 我们可以通过@DateTimeFormat和@NumberFormat注解对应日期和数据进行格式化,只需要在要格式化的类的属性上添加以上注解即可
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date birthday;
    @NumberFormat(pattern="#,###,###.##")
    private double salary;
  • 要使@DateTimeFormat和@NumberFormat注解起作用,必须配置<mvc:annotation-driven></mvc:annotation-driven>
<mvc:annotation-driven></mvc:annotation-driven>
配置,配置时不能指定conversion-service属性,否则,依然报错400。要把<mvc:annotation-driven conversion-service="conversionService"/>注掉才行
备注:
FormattingConversionService 实现类,既具有类型转换的功能,又具有格式化的功能
  • <mvc:annotation-driven/> 默认创建的 ConversionService 实例即为
 DefaultFormattingConversionService
4.数据校验
  • 我们可以通过Hibernate Validator进行数据校验,使用它需要到导入以下jar包
    classmate-0.8.0.jar
    hibernate-validator-5.0.0.CR2.jar
    hibernate-validator-annotation-processor-5.0.0.CR2.jar
    jboss-logging-3.1.1.GA.jar
    validation-api-1.1.0.CR1.jar
  • 然后在要校验的属性上添加对应的注解
    @NotEmpty
    private String lastName;
    
    @Email
    private String email;
    
    @Past
    private Date birthday;
  • 在要校验的属性对应的对象的前面添加@Valid注解,同时紧挨着该对象传入BindingResult类型的入参,通过它获取异常信息
// 添加新员工
    @RequestMapping(value = "/emp", method = RequestMethod.POST)
    public String addEmployee(@Valid Employee employee , BindingResult result) {
         //BindingResult结果集对象必须紧挨着被校验的employee对象,中间不能有其他参数
//       System.out.println(employee);
         int errorCount = result.getErrorCount();
         if(errorCount > 0){
             //证明有错误信息
             List<FieldError> fieldErrors = result.getFieldErrors();
             for (FieldError fieldError : fieldErrors) {
                 //获取出现异常的属性
                 String field = fieldError.getField();
                 //获取异常信息
                 String message = fieldError.getDefaultMessage();
                 System.out.println(field+":"+message);
             }
             //转发到输入用户信息的页面
             return "input";
         }
         // 保存用户
         employeeDao.save(employee);
         return "redirect:/emps";
    }
  • 要想当校验的注解起作用,必须配置<mvc:annotation-driven></mvc:annotation-driven>
<mvc:annotation-driven></mvc:annotation-driven>
  • 通过<form:errors></form:errors>表单在前端页面显示错误信息
 <!-- SpringMVC提供的表单默认表单中的数据是必须要回显的,默认情况下,SpringMVC会以command 作为key从request域中
          查询模型数据,然后回显,找不到则会抛出异常。我们可以通过form表单的modelAttribute属性来指定在request域中放的模型数据的key
      -->
     <form:form modelAttribute="employee">
          <!-- 如果path的值为通配符*,将显示所有的错误信息,如果要显示对应的错误信息,将该值设置为属性名即可-->
<%--         <form:errors path="*"></form:errors> --%>
        <!-- path属性就相当于input中的name属性 -->
          <!-- 当员工的id为null,即在添加新员工时再显示姓名 -->   
          <c:if test="${empty requestScope.employee.id }">   
             姓名:<form:input path="lastName"/><form:errors path="lastName"></form:errors><br>
          </c:if> 
        <!-- 对应更新来说,需要将POST请求转换为PUT请求,所以需要传一个请求参数_method --> 
        <c:if test="${!empty requestScope.employee.id }">
             <form:hidden path="id"/>
             <input type="hidden" name="_method" value="put">
        </c:if>
        邮箱:<form:input path="email"/><form:errors path="email"></form:errors><br>
        性别:<form:radiobutton path="gender" value="1" label="男"/>
             <form:radiobutton path="gender" value="0" label="女"/><br>
        部门:<form:select path="department.id" items="${requestScope.depts }" itemValue="id" itemLabel="departmentName"></form:select>
             <br>
        生日:<form:input path="birthday"/><form:errors path="birthday"></form:errors><br>
        期望薪资:<form:input path="salary"/><br>
             <input type="submit">
     </form:form>
  • 国际化错误信息
    • 在SpringMVC的配置文件中配置国际化资源文件
<!-- 配置国际化资源文件 -->
     <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basename" value="i18n"></property>
     </bean>
  • 国际化资源文件(i18n_zh_CN.properties)
NotEmpty.employee.lastName=\u7528\u6237\u540D\u4E0D\u80FD\u4E3A\u7A7A
Email.employee.email=\u90AE\u7BB1\u683C\u5F0F\u4E0D\u6B63\u786E
Past.employee.birthday=\u4EB2\u7231\u7684\uFF0C\u4F60\u51FA\u751F\u7684\u65F6\u95F4\u8FD8\u6CA1\u5230\uFF0C\u5728\u4F60\u5988\u5988\u809A\u5B50\u91CC\u518D\u5446\u4E9B\u65F6\u65E5\u5427\uFF01\uFF01\uFF01