10【SpringMVC的转换器】

文章目录

  • 四、转换器
    • 4.1 转换器的使用
      • 4.1.1 转换器简介
      • 4.1.2 转换器使用
        • 1)引入Maven依赖:
        • 2)实体类:
        • 3)表单:
        • 4)Controller:
        • 5)定义转换器:
        • 6)注册转换器
    • 4.2 转换器与日期的映射
      • 4.2.1 日期映射问题
      • 4.2.2 定义String转Date转换器:
      • 4.2.3 配置SpringMVC
      • 4.2.4 @DateTimeFormat
      • 4.2.5 Json格式数据提交
      • 4.2.6 转换总结


四、转换器

4.1 转换器的使用

4.1.1 转换器简介

我们知道 http 表单中的所有请求参数都是 String 类型的,如果Controller中的方法参数是一些普通类型(基本数据类型+包装类+String),适配器(HandlerAdapter)可以自动完成数据转换;

但如果参数是其他数据类型,比如:格式化字符串等,适配器是不能自动将 String 类型转换为 Date 类型或者其他JavaBean 的,这时就需要开发者手动的创建自定义数据转换器。

4.1.2 转换器使用

搭建一个新的项目,测试转换器的使用;

1)引入Maven依赖:

<dependencies>
    <dependency>
        <groupId>org.springframeworkgroupId>
        <artifactId>spring-webmvcartifactId>
        <version>5.2.9.RELEASEversion>
    dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.coregroupId>
        <artifactId>jackson-databindartifactId>
        <version>2.9.8version>
    dependency>
    <dependency>
        <groupId>org.apache.tomcatgroupId>
        <artifactId>tomcat-apiartifactId>
        <version>8.5.41version>
    dependency>
    <dependency>
        <groupId>org.projectlombokgroupId>
        <artifactId>lombokartifactId>
        <version>1.18.18version>
    dependency>
dependencies>

2)实体类:

package com.dfbz.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private Integer id;
    private String name;
    private Integer age;
    private Date birthday;
}

3)表单:

Demo01.jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    Title


学生信息:

4)Controller:

package com.dfbz.controller;

import com.dfbz.entity.Student;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @author lscl
 * @version 1.0
 * @intro: @PathVariable注解
 */
@Controller
@RequestMapping("/demo01")
public class Demo01Controller {

    /**
     * 处理表单提交请求
     * @param student
     * @return
     * @throws Exception
     */
    @ResponseBody
    @RequestMapping(value = "/demo01")
    public Student demo01(Student student) throws Exception {
        System.out.println("【Student】: " + student);
        return student;
    }
}

如果demo01方法的形参是String类型(demo01(String student))则SpringMVC提供的适配器组件就可以帮我们完成自动映射;但是demo01方法的形参是Student类型;SpringMVC提供的适配器并不能帮我们完成String类型到Student类型的转换;但好在SpringMVC支持我们自定义转换器;

5)定义转换器:

package com.dfbz.converter;

import com.dfbz.entity.Student;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;

import java.text.ParseException;
import java.text.SimpleDateFormat;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
@Component              // 放入IOC容器
public class StringToStudentConverter
        implements Converter<String, Student> {           // String: 什么参数需要转换   Student: 转换为什么类型


    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

    /**
     * 前端只要传递了String类型的表单
     *
     * @param str
     * @return
     */
    @Override
    public Student convert(String str) {
        // id:name:age:birthday--->1:zhangsan:20:birthday

        try {
            String[] studentInfo = str.split(":");

            Student student = new Student();
            student.setId(Integer.parseInt(studentInfo[0]));
            student.setName(studentInfo[1]);
            student.setAge(Integer.parseInt(studentInfo[2]));
            student.setBirthday(sdf.parse(studentInfo[3]));

            return student;
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }
}

6)注册转换器

在springmvc.xml注册我们自己的转换器:


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <context:component-scan base-package="com.dfbz"/>

    
    <mvc:default-servlet-handler/>

    
    <bean id="conversionService"
          class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <ref bean="stringToStudentConverter"/>
            set>
        property>
    bean>
    
    
    <mvc:annotation-driven conversion-service="conversionService"/>
beans>

访问Demo01.jsp,准备提交数据:

1:zhangsan:20:2000-10-10

10【SpringMVC的转换器】_第1张图片

控制台输出:

10【SpringMVC的转换器】_第2张图片

4.2 转换器与日期的映射

4.2.1 日期映射问题

我们前面测试过@RequestBody可以将一个JSON字符串转换为Java实体对象,但如果有些特殊情况下,我们必须自定义转换的规则;

注意:默认情况下,表单提交日期格式为yyyy/MM/dd才可以映射到后台的Date类型上,json方式提交默认为yyyy-MM-dd,如果不是指定格式的日期字符串则提交数据时出现400错误;

  • Controller:
package com.dfbz.controller;

import com.dfbz.entity.Student;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
@Controller
@RequestMapping("/demo02")
public class Demo02Controller {

    /**
     * 处理表单提交请求
     *
     * @param student
     * @return
     * @throws Exception
     */
    @ResponseBody
    @RequestMapping(value = "/demo01")
    public Student demo01(Student student) throws Exception {
        System.out.println("【Student】: " + student);
        return student;
    }

    /**
     * 处理ajax请求
     *
     * @param student
     * @return
     * @throws Exception
     */
    @ResponseBody
    @RequestMapping(value = "/demo02")
    public Student demo02(@RequestBody Student student) throws Exception {
        System.out.println("【Student】: " + student);
        return student;
    }
}
  • Demo02.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Titletitle>
    <script src="/js/jquery-3.5.1.min.js">script>
head>
<body>
<form action="/demo02/demo01" method="post">
    学生ID:<input type="text" name="id" value="1">
    学生姓名:<input type="text" name="name" value="zhangsan">
    学生年龄:<input type="text" name="age" value="20">
    出生日期:<input type="text" name="birthday" value="2000-10-10">

    <input type="submit">
form>

<hr>

<button id="btn">ajax提交studentbutton>

<script>
    $(function () {

        $("#btn").click(function () {

            var json = {id: 1, name: "张三", age: 21, birthday: "1996/10/24"};

            // 将json对象转换为json字符串
            var jsonStr = JSON.stringify(json);
            $.post({
                url: "/demo02/demo02",
                data: jsonStr,
                contentType: "application/json",
                success: function (res) {
                    alert(JSON.stringify(res))
                }
            })
        })
    })
script>
body>
html>

使用表单提交测试:

10【SpringMVC的转换器】_第3张图片

我们可以将前端提交的日期字符串的格式改为:yyyy/MM/dd,也可以通过自定义转换器来实现不同日期的格式化;

4.2.2 定义String转Date转换器:

package com.dfbz.converter;

import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
@Component          // 配置到IOC容器
public class StringToDateConverter
        implements Converter<String, Date> {        // String转Date

    private SimpleDateFormat sdf=new SimpleDateFormat("yyyy/MM/dd");

    @Override
    public Date convert(String str) {
        try {
            return sdf.parse(str);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }
}

4.2.3 配置SpringMVC


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <context:component-scan base-package="com.dfbz"/>

    
    <mvc:default-servlet-handler/>

    
    <mvc:annotation-driven conversion-service="conversionService"/>

    
    <bean id="conversionService"
          class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                
                <ref bean="stringToDateConverter"/>
                
                
                <ref bean="stringToStudentConverter"/>
            set>
        property>
    bean>
beans>

再次使用表单提交数据数据,发现成功;

Tips:转换器只针对表单提交有效;

4.2.4 @DateTimeFormat

除了可以使用转换器来进行日期的格式化外,还可以使用@DateTimeFormat注解进行日期的转换

10【SpringMVC的转换器】_第4张图片

注释掉Converter之后,发现@DateTimeFormate也可以完成日期的格式化;

注意:如果同时配置了Converter和@DateTimeFormate时,以Converter优先(优先级高);

4.2.5 Json格式数据提交

刚刚我们使用的Converter和@DateTimeFormate对日期的格式化都是针对于表单提交的数据,如果前端使用json格式(application/json)数据提交时Converter和@DateTimeFormate都将失效;

注意:默认情况下,json格式数据提交时,前端传递yyyy-MM-dd类似的日期字符串后端是可以映射成Date的;

  • 准备一个按钮,绑定点击事件:
<button id="btn">ajax提交studentbutton>

<script>
    $(function () {

        $("#btn").click(function () {

            var json = {id: 1, name: "张三", age: 21, birthday: "1996/10/24"};

            // 将json对象转换为json字符串
            var jsonStr = JSON.stringify(json);
            $.post({
                url: "/demo01/demo02",
                data: jsonStr,
                contentType: "application/json",
                success: function (res) {
                    alert(JSON.stringify(res))
                }
            })
        })
    })
script>

在提交json格式数据时,必须借助@JsonFormate注解来规定json数据提交时,字符串日期转换为Date的规则;

Tips:@JsonFormate不仅可以在响应数据到前端时格式化日期,还可以在前端提交后端的时候来格式化日期;

  • 添加@JsonFormate注解:

10【SpringMVC的转换器】_第5张图片

再次测试json数据提交,发现成功;

4.2.6 转换总结

  • 1)@JsonFormate:提交json(application/json)有效,表单(application/x-www-form-urlencoded)提交无效;

  • 2)@DateTimeFormate:json提交无效,表单提交有效,权重比Converter低;

  • 3)自定义Converter:json提交无效、表单提交有效;

  • 4)当没有配置转换时:

    • 如果是json方式提交:yyyy-MM-dd格式的字符串提交能够被Date接收
    • 如果是表单方式提交:yyyy/MM/dd格式的字符串提交能够被Date接收

我们一般配置如下就行:

@JsonFormat(pattern = "yyyy-MM-dd")			// 处理json提交(顺便处理Date转字符串问题)
@DateTimeFormat(pattern = "yyyy-MM-dd")		// 处理表单提交
private Date birthday;

你可能感兴趣的:(#,《SSM框架系列》,java,servlet,spring,springmvc)