• 10【SpringMVC的转换器】



    四、转换器

    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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    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;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    3)表单:

    Demo01.jsp:

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    
    
        Title
    
    
    
    学生信息:
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    如果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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

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

    1:zhangsan:20:2000-10-10
    
    • 1

    在这里插入图片描述

    控制台输出:

    在这里插入图片描述

    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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    使用表单提交测试:

    在这里插入图片描述

    我们可以将前端提交的日期字符串的格式改为: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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

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

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

    4.2.4 @DateTimeFormat

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

    在这里插入图片描述

    注释掉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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

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

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

    • 添加@JsonFormate注解:

    在这里插入图片描述

    再次测试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;
    
    • 1
    • 2
    • 3

  • 相关阅读:
    处理ElementUI组件默认样式多次重复问题
    RUST与Python对比分析
    【Hadoop】HDFS API 操作大全
    怎么直连某个服务器的dubbo服务
    C语言17---计算机的存储规则
    Kafka如何防止消息丢失+如何防止消息重复消费
    【一篇就够】一些http知识的小总结
    SpringBoot介绍
    vue项目中引入element-plus
    增速冠军 | 超云AI与信创实践典范,引领IDC中国服务器市场
  • 原文地址:https://blog.csdn.net/Bb15070047748/article/details/128105870