SpringMVC---数据转换

发现问题?

  • 此时有这么一个表单页面
<body>
<form:form action="${pageContext.request.contextPath}/emp" method="POST" modelAttribute="employee">
    雇员名称:<form:input path="lastName"/><br/>
    雇员邮箱<form:input path="email"/><br/>

    <%
        Map<String, String> genders = new HashMap<>();
        genders.put("0", "女");
        genders.put("1", "男");
        request.setAttribute("genders", genders);
    %>
    性别:<form:radiobuttons path="gender" items="${genders}"/><br/>
    部门:<form:select path="department.id" items="${departments}" itemLabel="departmentName" itemValue="id"></form:select>
    <br/>
    <input type="submit" value="提交"/>
</form:form>
</body>
  • 这个表单对应的实体类对象为:
package mao.shu.springmvc.crud.vo;

public class Employee {
    private Integer id;
    private String lastName;
    private String email;
    private Integer gender;//1表示男,0表示女
    private Department department;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Integer getGender() {
        return gender;
    }

    public void setGender(Integer gender) {
        this.gender = gender;
    }

    public Department getDepartment() {
        return department;
    }

    public void setDepartment(Department department) {
        this.department = department;
    }
}

  • 此时思考一个问题,在表单中填写数据,是如何转换为实体类中对应的参数?
  • 表单中填写的数据都为String类型,而实体类中的对应的数据可能是其他数据类型,例如:Date,Integer,Double
    • 那么SpringMVC是如何将String类型的数据自动转换为正确的数据类型?
  • 在进行数据填写的时候,往往会存在一些逻辑上的限制,例如一个人的年龄一般不会太高(例如:2000岁),也不应该是负数等等
    • 那么SpringMVC中要如何进行数据的判断?

数据绑定流程

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • SpringMVc数据转换流程
    1. 调用binderRequestParames()方法进行数据转换和数据验证操作
    2. 调用conversionService进行数据转换和格式化
    3. 调用validates()进行数据验证处理

自定义类型转换器

  • SpringMVC提供的转换器

在这里插入图片描述

  • SpringMVC提供了大量的转换器,一般情况下足够开发使用,如果需要特殊的数据转换,可以自定义转换器

在这里插入图片描述

  • 自定义转换器需要实现SpringMVC的接口

在这里插入图片描述

示例:定义一个自定义类型转换器

  • 定义EmployeeConverter
    • 这个转换器使用@Component注解交由SpringMVC的IOC容器管理
    • 约定传入的字符串组成为:“雇员名称”-“雇员邮编”-“性别标识符数据”-“部门编号”
package mao.shu.springmvc.converter;
import mao.shu.springmvc.crud.vo.Department;
import mao.shu.springmvc.crud.vo.Employee;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;

@Component
public class EmployeeConverter implements Converter<String, Employee> {
    @Override
    public Employee convert(String s) {
        //约定传入的字符串组成为:"雇员名称"-"雇员邮编"-"性别标识符数据"-"部门编号"
        String[] temp = s.split("-");
        if (temp != null && temp.length == 4) {
            
            Employee employee = new Employee();
            employee.setLastName(temp[0]);
            employee.setEmail(temp[1]);
            employee.setGender(Integer.parseInt(temp[2]));

            Department dept = new Department();
            dept.setId(Integer.parseInt(temp[3]));
            employee.setDepartment(dept);
            
            System.out.println(s+"--converter--"+employee);
            return employee;
        }
        return null;
    }
}

  • 编写SpringMVC的配置文件

    <!--配置SpringMVC的数据转换器-->
    <bean id="conversionServiceFactoryBean" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <!--添加自定义的转换器-->
                <ref bean="employeeConverter"/>
            </set>
        </property>
    </bean>

    <!--配置conversion-service属性 指向SpringMVC的数据转换器-->
    <mvc:annotation-driven  conversion-service="conversionServiceFactoryBean"></mvc:annotation-driven>
  • 编写一个表单进行Employe类型的数据添加操作
  <form action="testConverter" method="post">
    添加的雇员信息格式为:"雇员名称"-"雇员邮编"-"性别标识符数据"-"部门编号"<br/>
    添加雇员信息:<input type="text" name="employee"/>
    <input type="submit" value="提交"/>
  </form>
  • 在控制器中编写请求映射方法

 @RequestMapping(value="/testConverter",method=RequestMethod.POST)
 public String testConverter(@RequestParam("employee") Employee employee){
     this.employeeDAO.add(employee);
	 return "redirect:empList";
 }
  • 测试

在这里插入图片描述

在这里插入图片描述

  • 后台输出

在这里插入图片描述

annotation-driven配置

为什么使用annotation-driven

在这里插入图片描述

通过源码解析annotation-driven注解使用过程

在这里插入图片描述

  • 在SpringMVC中不配置<mvc:default-servlet-handler>和<mvc:annotation-driven>注解
  • 在实体类的Setter方法上打上断点

在这里插入图片描述

  • 执行一个请求映射方法

在这里插入图片描述

  • 当代码停住时,选择DespatcherServlet中的976行,查看当前类中的变量情况
    在这里插入图片描述

  • 此时DispatcherServlet中的handerAdapters对象数组中包含三个变量

    1. 其中AnnotationMethodHanderAdapter 就支持@RequestMapping 注解映射的路径.但是这个AnnotationMethodHanderAdapter类在SpringMVC4.0之后已经过期不建议使用
      在这里插入图片描述
  • 启动 <mvc:default-servlet-handler/>配置的时候

    • 此时handlerAdapters变量中没有AnnotationMethodHandlerAdapter对象,这样就无法使 @RequestMapping 注解配置映射路径生效,那么也就无法访问页面

在这里插入图片描述

在这里插入图片描述

  • 当同时启动<mvc:default-servlet-handler>和<mvc:annotation-driven>的时候
  • 发现使用了一个新的对象:RequestMappingHandlerAdapter

在这里插入图片描述

  • 此时的映射请求可以被正确处理

在这里插入图片描述

@initBinder 注解

在这里插入图片描述

在这里插入图片描述

@initBinder注解的作用

  • 通过使用InitBinder注解定义的方法,可以用于控制DataBinder对Web数据到JavaBean数据的转换操作控制.
  • 例如:一个雇员表单提交之后转换为一个Employee类实例化对象,可以通过使用@InitBinder注解控制Employee类中的哪个属性不进行赋值
  • 示例:设置Employee类中的lastName属性不进行赋值操作
@InitBinder
public void setLastName(WebDataBinder webDataBinder){
    //不设置lastName属性
    webDataBinder.setDisallowedFields("lastName");
}
  • 在执行添加操作之后,lastName属性对应的字段将不会被赋值

在这里插入图片描述

数据格式化

在这里插入图片描述

在这里插入图片描述

  • 示例:SpringMVC的配置文件
 <mvc:annotation-driven ></mvc:annotation-driven>

在这里插入图片描述

    • 示例:进行日期转换
  • 在Employee类中添加一个birthday 字段描述雇员的生日
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date birthday;

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
  • 在表单中添加一个日期填写项
    雇员生日:<form:input path="birthday" />
    <br/>
  • 在添加的方法中输出雇员信息
    @RequestMapping(value = "/emp", method = RequestMethod.POST)
    public String save(Employee vo) {
        System.out.println("添加的雇员:"+vo);
        this.employeeDAO.add(vo);
        return "redirect:/empList";
    }
  • 测试

在这里插入图片描述

  • 后台的得到的数据

在这里插入图片描述

在这里插入图片描述

  • 示例:进行数值格式化
  • 实体类
    // 将存款字符串格式化的数值:[亿][千万][百万],[十万][万][千],[百][十][元].[角][分]
    @NumberFormat(pattern="###,###,###.##")
    private Integer salary;

    public Integer getSalary() {
        return salary;
    }

    public void setSalary(Integer salary) {
        this.salary = salary;
    }
  • 控制层
    @RequestMapping(value = "/emp", method = RequestMethod.POST)
    public String save(Employee vo) {
        System.out.println("添加的雇员:"+vo);
        System.out.println("雇员工资"+vo.getSalary());
        this.employeeDAO.add(vo);
        return "redirect:/empList";
    }
  • 表单页面
    雇员工资<form:input path="salary"/><br/>
  • 测试

在这里插入图片描述

  • 后台数据

在这里插入图片描述

  • 如果希望使用SpringMVC提供的转换器的同时也是用自定义的转换器,那么可以在SpringMVC配置文件中配置FormattingConversionServiceFactoryBean 的Bean
<!--配置SpringMVC的数据转换器-->
<bean id="conversionServiceFactoryBean" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <property name="converters">
        <set>
        <!--    添加自定义的转换器-->
            <ref bean="employeeConverter"/>
        </set>
    </property>
</bean>

<!--配置conversion-service属性 指向SpringMVC的数据转换器-->
<mvc:annotation-driven conversion-service="conversionServiceFactoryBean"></mvc:annotation-driven>

数据的校验

如何进行数据验证?

  1. 使用JSR 303 进行数据验证
    在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

示例:进行javaBean的参数验证

  1. 在SpringMVC的配置文件中配置"<mvc:annotation-driven>"标签
    • 加入<mvc:annotation-driven>"标签的时候默认会加载LocalValidatorFactoryBean
<mvc:annotation-driven ></mvc:annotation-driven>
  1. 加入hibernate validate 验证框架的jar包

在这里插入图片描述
3. 在java类参数中加入注解

@Email
private String email;

@Past
private java.util.Date birthday;

@Min(3000)
private Double salary;
  1. 在目标方法上使用 @Valid 注解修饰要验证的入参,并且添加BindingResult 参数接收验证结果
@RequestMapping(value = "/emp", method = RequestMethod.POST)
public String save(@Valid Employee vo, BindingResult bandingResult) {
    //如果有错误
    if(bandingResult.getErrorCount() > 0){
        for (FieldError error:bandingResult.getFieldErrors()){
            System.out.println("参数名称: "+error.getField()+"错误信息 "+error.getDefaultMessage());
        }
    }
    this.employeeDAO.add(vo);
    return "redirect:/empList";
}
  • 测试:填写错误的数据

在这里插入图片描述

  • 后台输出

在这里插入图片描述

出现错误返回指定页面

  • 使用Map集合保存数据,SpringMVC会自动进行表单的回显操作
    @RequestMapping(value = "/emp", method = RequestMethod.POST)
    public String save(@Valid Employee vo, BindingResult bandingResult,Map<String,Object> map) {
        //如果有错误
        if(bandingResult.hasErrors()){
            for (FieldError error:bandingResult.getFieldErrors()){
                System.out.println("参数名称: "+error.getField()+"错误信息 "+error.getDefaultMessage());
            }
            //如果出现错误,将错误的数据保存到map集合中
            map.put("employee",vo);
            map.put("departments", this.departmentDAO.getAll());
            return "emp_input";
        }
        this.employeeDAO.add(vo);
        return "redirect:/empList";
    }
  • 输入错误后,自动跳转到目标页

在这里插入图片描述

页面显示错误信息

  • SrpingMVC会将数据的验证结果保存在页面中的request属性中,可以使用<form:errors>标签显示错误信息

在这里插入图片描述

  • 如果使用 <form:errors path="*">,path属性值取"*"的情况下,默认是显示所有的错误信息

  • 如果要显示单个的错误信息,则path属性的取值就是实体类中的属性名称
    在这里插入图片描述

  • 示例:显示错误提示信息

    雇员邮箱<form:input path="email"/>
    <form:errors path="email"/>
    <br/>
    雇员生日<form:input path="birthday"/>
        <form:errors path="birthday" />
    <br/>
    雇员工资<form:input path="salary" />
        <form:errors path="salary"/>
    <br/>
  • 测试

在这里插入图片描述

  • 显示信息

在这里插入图片描述

定制提示信息

  • 要定制提示信息,需要编写properties文件,文件中key的值的格式为:
"校验注解名"."属性类名"."属性名"="提示信息"

在这里插入图片描述

在这里插入图片描述

  • 示例:实现错误信息国际化
  • 实体类中使用JSR 303 注解验证的属性
@NotEmpty
private String lastName;

@Email
private String email;

@NotEmpty
private Integer gender;//1表示男,0表示女

@Past
private java.util.Date birthday;

@Min(3000)
private Double salary;
  • 定义i18n.properties文件
NotEmpty.employee.lastName=雇员姓名不能够为空
Email.employee.email=请输入正确的电子邮箱
Past.employee.birthday=不能够输入未来的日期时间
Min.employee.salary=雇员工资最小为3000
typeMismatch.employee.birthday=请输入正确的时间格式,例如"2018-10-16"
  • 在SpringMvc的配置文件中配置国际化资源文件
<!--配置国际化资源文件-->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
    <property name="basename" value="i18n"/>
</bean>
  • 测试

在这里插入图片描述

处理JSON

  • 注意:不同版本的SpringMVC于jacksonjar包可能会有冲突
  • 本次使用的是SpringMVC-4.3.1
  • jackson.2.9.7

在这里插入图片描述

在这里插入图片描述

  • 示例:返回json数据
@ResponseBody
@RequestMapping("/testJSON")
public Collection<Employee> testJSON(){
    return this.employeeDAO.getAll();
}

在这里插入图片描述

HttpMessageConverter原理

在这里插入图片描述

  • HttpMessageConverter工作原理

在这里插入图片描述

  • HttpInputMessage接口中定义的getBody()方法,用于将请求信息转换为InputStream对象

在这里插入图片描述

  • HttpOutputMessage接口中的getBody()方法负责将回应内容转换为OutputStream对象

在这里插入图片描述

  • HttpMessageConverter接口的默认实现子类

在这里插入图片描述

  • SpringMVC默认装配的实现子类有6个

在这里插入图片描述

  • 当我将jackson的jar包导入到项目中时,会自动增加MappingJackson2HttpMessageConverter

在这里插入图片描述

使用HttpMessageConverter

在这里插入图片描述

示例:使用"@RequestBody"和"@ResponseBody"注解

	/**
	 * 使用ResponseBody注解,将方法的返回值转换为普通的String类型
	 * 返回的字符串将会直接打印在客户端页面上
	 * 
	 * 使用@RequestBody修饰 file 入参,将会把请求的内容转换为 String类型最为方法的参数
	 * @param file
	 * @return
	 */
	@ResponseBody
	@RequestMapping("/testMessageConverter")
	public String testMessageConverter(@RequestBody String file){
	    System.out.println("上传文件: "+file);
	    return "上传成功 "+new Date();
	}
  • 测试请求:

在这里插入图片描述

  • 后台输出

在这里插入图片描述

  • 回应内容

在这里插入图片描述

HttpEntity和ResponseEntity使用示例

  • 使用HttpEntity和ResponseEntity最为一个对象为参数或者返回值可以接收或返回更多的信息.

在这里插入图片描述

  • 示例:返回一个文件信息
  • 返回的文件

在这里插入图片描述

   @RequestMapping("/testResponseEntity")
    public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException {
        //将一个静态文件转换为一个InputStream对象
        InputStream guidaoImg =session.getServletContext().getResourceAsStream("/img/guidao.jpg");
        //创建InputStream对象长度的 byte[] 字节数组
        byte[] guidaoByte = new byte[guidaoImg.available()];
        //将InputStream 对象中的内容保存到 字节数组中
        guidaoImg.read(guidaoByte);

        //设置请求头
        HttpHeaders  httpHeaders = new HttpHeaders();
        httpHeaders.add("Content-Disposition","attachment;filename=guidao.jpg");
        //HttpStatus.OK 描述的是请求的状态码 HttpStatus.OK = 200
        HttpStatus httpStatus = HttpStatus.OK;
        //将字节数组最为请求回应的内容
        ResponseEntity<byte[]> file = new ResponseEntity<>(guidaoByte,httpHeaders,httpStatus);
        return file;
    }
  • 测试请求:
<a href="testResponseEntity">文件下载测试</a>
  • 成功下载

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值