10【SpringMVC的转换器】

追求适度,才能走向成功;人在顶峰,迈步就是下坡;身在低谷,抬足既是登高;弦,绷得太紧会断;人,思虑过度会疯;水至清无鱼,人至真无友,山至高无树;适度,不是中庸,而是一种明智的生活态度。

导读:本篇文章讲解 10【SpringMVC的转换器】,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文


四、转换器

4.1 转换器的使用

4.1.1 转换器简介

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

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

4.1.2 转换器使用

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

1)引入Maven依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.2.9.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.9.8</version>
    </dependency>
    <dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>tomcat-api</artifactId>
        <version>8.5.41</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.18</version>
    </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" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="/demo01/demo01" method="post">
    学生信息:<input type="text" name="student" placeholder="格式: id:name:age:birthday">
    <input type="submit">
</form>
</body>
</html>

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注册我们自己的转换器:

<?xml version="1.0" encoding="UTF-8"?>
<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/>

    <!--在SpringMVC提供的converts中加上我们的-->
    <bean id="conversionService"
          class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <ref bean="stringToStudentConverter"/>
            </set>
        </property>
    </bean>
    
    <!-- 指定使用定制的converts-->
    <mvc:annotation-driven conversion-service="conversionService"/>
</beans>

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

1:zhangsan:20:2000-10-10

在这里插入图片描述

控制台输出:

在这里插入图片描述

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>Title</title>
    <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提交student</button>

<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>

使用表单提交测试:

在这里插入图片描述

我们可以将前端提交的日期字符串的格式改为: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

<?xml version="1.0" encoding="UTF-8"?>
<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/>

    <!-- 指定使用定制的converts-->
    <mvc:annotation-driven conversion-service="conversionService"/>

    <!--在SpringMVC提供的converts中加上我们的-->
    <bean id="conversionService"
          class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <!--String转Date-->
                <ref bean="stringToDateConverter"/>
                
                <!--String转Student-->
                <ref bean="stringToStudentConverter"/>
            </set>
        </property>
    </bean>
</beans>

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

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提交student</button>

<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注解:

在这里插入图片描述

再次测试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;

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/131651.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!