前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringMVC数据类型转换器与国际化配置

SpringMVC数据类型转换器与国际化配置

作者头像
端碗吹水
发布2020-09-23 14:10:04
3720
发布2020-09-23 14:10:04
举报
文章被收录于专栏:程序猿的大杂烩

SpringMVC数据类型转换器

我们都知道在浏览器中,访问网页都是通过url访问的。所以在web开发中,我们经常会通过url来传递数据。如果我要在url参数上传递一个日期数据,我们是无法在后端通过声明一个Date类型的参数来接收的,会报空指针错误。想要接收日期数据,就得用到SpringMVC中的数据类型转换器了。

在SpringMVC转换中有三种方式可以转换数据类型:

1.在控制中加入一个方法,在该方法上写上@InitBinder注解,并且在方法参数上声明一个WebDataBinder类型参数。这个方法会在控制器中其他方法之前调用,所以在该方法中就可以预先处理数据类型的转换。这里我们需要使用一个实现了PropertyEditor接口或者继承了PropertyEditorSupport类的自定义类型转换器来进行类型的转换。如下示例:

代码语言:javascript
复制
package org.zero01.test;

import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

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

@Controller
public class TestController {

    @RequestMapping("test.do")
    @ResponseBody
    public String test(Date date) {
        System.out.println("我被调用了-test");
        return date.toString();
    }

    @InitBinder
    public void initDate(WebDataBinder webDataBinder) {
        System.out.println("我被调用了-initDate");
        SimpleDateFormat sig = new SimpleDateFormat("yyy-MM-dd");
        // 第一个参数是DataDateFormat类型的对象,第二个参数指定是否允许为空
        CustomDateEditor cue = new CustomDateEditor(sig, true);
        // 注册自定义的日期转换格式
        webDataBinder.registerCustomEditor(Date.class, cue);
    }
}

浏览器访问http://localhost:8080/test.do?date=2018-01-01,输出结果如下:

代码语言:javascript
复制
Mon Jan 01 00:00:00 CST 2018

控制台打印结果如下:

代码语言:javascript
复制
我被调用了-initDate
我被调用了-test

以上这种转换数据类型的方式只是局部的,也就是说只能在一个控制器中使用,如果希望是全局有效的话,我们就需要在Spring配置文件中注册一个转换器了。但是在这之前我们需要先自定义一个类并实现一个Formatter接口,如下示例:

代码语言:javascript
复制
package org.zero01.test;

import org.springframework.format.Formatter;

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

// 接口的泛型用于指定转换成什么类型
public class MyDataFormatter implements Formatter<Date> {

    // 在parse定义转换的格式
    public Date parse(String s, Locale locale) throws ParseException {
        SimpleDateFormat sig = new SimpleDateFormat("yyyy-MM-dd");
        return sig.parse(s);
    }

    public String print(Date date, Locale locale) {
        return null;
    }
}

在Spring配置文件中注册formatters转换器:

代码语言:javascript
复制
<mvc:annotation-driven conversion-service="myDateFormatters"/>

<bean id="myDateFormatters" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <property name="formatters">
        <set>
            <bean class="org.zero01.test.MyDataFormatter" />
        </set>
    </property>
</bean>

控制器代码如下:

代码语言:javascript
复制
package org.zero01.test;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.Date;

@Controller
public class TestController {

    @RequestMapping("test.do")
    @ResponseBody
    public String test(Date date) {
        return date.toString();
    }
}

浏览器访问http://localhost:8080/test.do?date=2018-03-28,输出结果如下:

代码语言:javascript
复制
Mon Jan 02 00:00:00 CST 2018

通过实现Formatter接口来实现类型的转换有一个缺点就是无法自定义来源类型,Formatter接口默认的来源类型都是String,而目标类型则可以自定义。如果希望能够自定义来源类型的话,就需要实现Converter接口,通过该接口我们可以指定来源类型以及转换后的目标类型。如下示例:

代码语言:javascript
复制
package org.zero01.test;

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

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

public class MyDateConvert implements Converter<String, Date> {
    public Date convert(String s) {
        SimpleDateFormat sig = new SimpleDateFormat("yyyy-MM-dd");
        try {
            return sig.parse(s);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }
}

同样的需要注册转换器,在Spring配置文件中注册converters转换器:

代码语言:javascript
复制
<mvc:annotation-driven conversion-service="myDateConvert"/>

<bean id="myDateConvert" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <property name="converters">
        <set>
            <bean class="org.zero01.test.MyDateConvert" />
        </set>
    </property>
</bean>

控制器代码和之前一样,略。浏览器访问http://localhost:8080/test.do?date=2018-03-28,输出结果如下:

代码语言:javascript
复制
Mon Jan 02 00:00:00 CST 2018

HttpMessageConverter接口

说到转换器,这里不得不再介绍一个HttpMessageConverter,这是Spring3.x中引入的接口,在底层中它作为一个消息转换器存在。SpringMVC使用消息转换器(HttpMessageConverter)实现将请求信息转换为对象、将对象转换为响应信息。

我们在使用SpringMVC时经常会使用到@RequestBody和@ResponseBody两个注解,例如上面的代码就用到了@ResponseBody注解。它们分别完成请求报文到对象和对象到响应报文的转换,底层这种灵活的消息转换机制,就是HttpMessageConverter的应用,通过不同的HttpMessageConverter实现类就可以进行不同类型的转换。

默认情况下@ResponseBody注解会把返回的数据转换成普通的文本数据进行处理,而我们如果配置了JSON的转换器的话,就会按照JSON格式进行转换。这也是抽象了HttpMessageConverter接口的好处,可以在不同类型的数据间进行转换。

HttpMessageConverter消息转换器最高层次的接口抽象,描述了一个消息转换器的一般特征,我们可以来看一下HttpMessageConverter接口的源码:

代码语言:javascript
复制
public interface HttpMessageConverter<T> {  

    //判断数据类型是否可读  
    boolean canRead(Class<?> clazz, MediaType mediaType);  

    //判断数据是否可写  
    boolean canWrite(Class<?> clazz, MediaType mediaType);  

    //获取支持的数据类型  
    List<MediaType> getSupportedMediaTypes();  

    //对参数值进行读,转换为需要的类型  
    T read(Class<? extends T> clazz, HttpInputMessage inputMessage)  
            throws IOException, HttpMessageNotReadableException;  

    //将返回值发送给请求者  
    void write(T var1, MediaType var2, HttpOutputMessage var3) throws IOException, HttpMessageNotWritableException;

}  

如果我们的控制器中有这样一个方法:

代码语言:javascript
复制
@RequestMapping(value="/string", method=RequestMethod.POST)
public @ResponseBody String readString(@RequestBody String string) {
    return "Read string '" + string + "'";
}

在SpringMVC进入readString方法前,会根据@RequestBody注解选择适当的HttpMessageConverter实现类来将请求参数解析到string变量中,具体来说是使用了StringHttpMessageConverter类,它的canRead()方法返回true,然后它的read()方法会从请求中读出请求参数,绑定到readString()方法的string变量中。

当SpringMVC执行readString方法后,由于返回值标识了@ResponseBody,SpringMVC将使用StringHttpMessageConverter的write()方法,将结果作为String值写入响应报文,当然,此时canWrite()方法返回true。

我们可以用下面的图,简单描述一下这个过程:


springMVC国际化配置和使用

有些时候我们可能会有不同语言之间切换的需求,通过SpringMVC国际化配置,可以实现简单的语言切换,下面使用一个小demo演示一下如何进行国际化的配置。

web.xml文件配置如下:

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <welcome-file-list>
        <welcome-file>/WEB-INF/index.jsp</welcome-file>
    </welcome-file-list>

    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/</url-pattern>
    </filter-mapping>
    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/applicationContext*.xml,classpath*:applicationContext*.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>
    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>
</web-app>

在Spring配置文件中加入以下内容:

代码语言:javascript
复制
<!-- 默认国际化语言配置  -->
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
    <property name="defaultLocale" value="zh_CN"/>
</bean>

<!-- 区域解析类 自动解析 -->
<bean id="ahr" class="org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver"/>

<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <property name="basename" value="/WEB-INF/i18n/message"/>
</bean>

然后创建不同语言的资源文件:

文件内容:

代码语言:javascript
复制
message_en_US.properties文件内容如下:
username=UserName
password=Password

message_zh_CN.properties文件内容如下:
username=\u7528\u6237\u540d
password=\u5bc6\u7801

message_zh_TW.properties文件内容如下:
username=\u7528\u6236\u540d
password=\u5bc6\u78bc

编写控制器代码如下:

代码语言:javascript
复制
package org.zero01.test;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;

import javax.servlet.http.HttpSession;
import java.util.Locale;

@Controller
public class TestController {

    @RequestMapping("test.do")
    public String testLocation(String lang, HttpSession session) {
        Locale locale = null;
        if (lang.equals("en") || lang.equals("us")) {
            locale = new Locale("en", "US");
        } else if (lang.equals("tw")) {
            locale = new Locale("zh", "TW");
        } else {
            locale = new Locale("zh", "CN");
        }

        session.setAttribute(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME, locale);

        return "index";
    }
}

index.jsp文件内容如下:

代码语言:javascript
复制
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<html>
<head>
    <title>Title</title>
</head>
<style>
    .link{
        color: #888;
        text-decoration: none;
    }
    .link:hover{
        color: #e60023;
    }
</style>
<body>
    <div>
        <spring:message code="username"/> |
        <spring:message code="password"/><br>
        [<a href="test.do?lang=us" class="link"> 英文</a>]
        [<a href="test.do?lang=zh" class="link">中文</a>]
        [<a href="test.do?lang=tw" class="link">繁体</a>]
    </div>
</body>
</html>

运行效果,中文:

英文:

繁体:

这样我们就能实现不同语言之间的切换了。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018/03/29 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • SpringMVC数据类型转换器
  • HttpMessageConverter接口
  • springMVC国际化配置和使用
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档