• 概述
  • converter
    • Step 1 实现Converter接口
    • Step 2 SpringMVC配置文件中配置bean及设置conversion-service属性
    • 小Demo
  • formatter
    • Step 1 实现Formatter接口
    • Step 2 SpringMVC配置文件中配置bean及设置conversion-service属性
  • 用registrar注册formatter
    • Step 1 编写MyFormatterRegistrar ,注册自定义Formatter
    • Step 2 编写自定义Formatter
    • Step 3 SpringMVC配置文件中配置bean及设置conversion-service属性
  • converter or formatter 小结
  • 源码

概述

Spring MVC-05循序渐进之数据绑定和form标签库(上) 和 Spring MVC-05循序渐进之数据绑定和form标签库(下) 实战从0到1 我们已经学习了数据绑定,见识了数据绑定的方便性。

但是Spring的数据绑定并非没有任何限制, 比如Spring总是试图使用more的语言区域将日期输入绑定到java.uti.Date上,假设我们想让Spring使用不同的格式日期,就需要一个Converter或者Formatter来协助完成了。

本篇博文将重点讨论ConverterFormatter的内容。 这两者均可以用于将一种对象类型转换成另外一种对象类型。 Converter是通用元件,可以在应用程序的任意层使用,而Formatter则是专门为Web层设计的


converter

Spring 的Converter是可以将一种类型转换成另外一种类型的一个对象。

举个例子,用户输入的日期格式可能有许多种,比如“January 10,2018”、“10/01/2018”、“2018-01-10”,这些都表示同一个日期。 默认情况下,Spring会将期待用户输入的日期样式和当前语言区域的日期样式相同。

比如US用户,就是月/日/年的格式。 如果希望Spring在将输入的日期字符串绑定到Date时使用不同的日期格式,则需要编写一个Converter,才能将字符串转换成日期。

Step 1 实现Converter接口

为了创建自定义的Converter需要实现 org.springframework.core.convert.converter.Converter接口

我们来看下该接口

package org.springframework.core.convert.converter;/*** A converter converts a source object of type {@code S} to a target of type {@code T}.** <p>Implementations of this interface are thread-safe and can be shared.** <p>Implementations may additionally implement {@link ConditionalConverter}.** @author Keith Donald* @since 3.0* @param <S> the source type* @param <T> the target type*/
public interface Converter<S, T> {/*** Convert the source object of type {@code S} to target type {@code T}.* @param source the source object to convert, which must be an instance of {@code S} (never {@code null})* @return the converted object, which must be an instance of {@code T} (potentially {@code null})* @throws IllegalArgumentException if the source cannot be converted to the desired target type*/T convert(S source);}

这里的泛型 S表示源类型, 泛型T表示目标类型。 比如为了创建一个可以将String转为Date的Converter,可以像下面这样声明

public class MyConverter implements Converter<String, Date> {}

当然了要重写convert方法。

@Overridepublic Date convert(String source){}

该例中的代码如下

MyConverter.java

package com.artisan.converter;import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;import org.springframework.core.convert.converter.Converter;
/***
* @ClassName: MyConverter
* @Description: 自定义Converter,将String类型的数据转换为指定格式的Date
* @author Mr.Yang
* @date 2018年2月10日
**/
public class MyConverter implements Converter<String, Date> {private String datePattern;private Date targetFormateDate;/*** * 创建一个新的实例 MyConverter. 默认构造函数**/public MyConverter() {super();}/*** * 创建一个新的实例 MyConverter. 实例化时指定日期格式* * @param datePattern*/public MyConverter(String datePattern) {super();this.datePattern = datePattern;}/*** 重写convert方法*/@Overridepublic Date convert(String source) {try {SimpleDateFormat sdf = new SimpleDateFormat(datePattern);// 是否严格解析日期,设置false禁止SimpleDateFormat的自动计算功能sdf.setLenient(false);targetFormateDate = sdf.parse(source);} catch (ParseException e) {// the error message will be displayed when using <form:errors>e.printStackTrace();throw new IllegalArgumentException("invalid date format. Please use this pattern\"" + datePattern + "\"");}return targetFormateDate;}}/*** 如果设置为true,假设你输入的日期不合法,它会先进行一定的计算.计算出能有合法的值,就以计算后的值为真正的值.* * 比如说当你使用的时候有2012-02-31,2012-14-03这样数据去format,* 如果setLenient(true).那么它就会自动解析为2012-03-02和2013-02-03这样的日期.* 如果setLenient(false),2012-14-03就会出现解析异常,因为去掉了计算,而这样的数据又是不合法的* */

Step 2 SpringMVC配置文件中配置bean及设置conversion-service属性

为了在Spring MVC中使用自定义的Converter,需要在SpringMVC的配置文件中配置一个conversionService ,该Bean的名字必须为
org.springframework.context.support.ConversionServiceFactoryBean 。同时必须包含一个converters属性,它将列出要在应用程序中使用的所有定制的Converter.

紧接着要给annotation-driven元素的conversion-service属性赋bean名称。

完整配置文件如下:

<?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:p="http://www.springframework.org/schema/p"xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsd     http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!-- 扫描控制层的注解,使其成为Spring管理的Bean --><context:component-scan base-package="com.artisan.controller"/><!-- 静态资源文件 --><!-- (2)将自定义的convert设置给conversion-service属性 --><mvc:annotation-driven  conversion-service="conversionService"/><mvc:resources mapping="/css/**" location="/css/"/><mvc:resources mapping="/*.jsp" location="/"/><!-- 视图解析器 --><bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/jsp/"/><property name="suffix" value=".jsp"/></bean><!-- (1)自定义converter --><bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"><property name="converters"><list><bean class="com.artisan.converter.MyConverter"><constructor-arg type="java.lang.String" value="MM-dd-yyyy"/></bean></list></property></bean></beans>

小Demo

Domain类

package com.artisan.domain;import java.io.Serializable;
import java.util.Date;public class Artisan implements Serializable {private static final long serialVersionUID = -908L;private long id;private String firstName;private String lastName;private Date birthDate;private int salaryLevel;public long getId() {return id;}public void setId(long id) {this.id = id;}public String getFirstName() {return firstName;}public void setFirstName(String firstName) {this.firstName = firstName;}public String getLastName() {return lastName;}public void setLastName(String lastName) {this.lastName = lastName;}public Date getBirthDate() {return birthDate;}public void setBirthDate(Date birthDate) {this.birthDate = birthDate;}public int getSalaryLevel() {return salaryLevel;}public void setSalaryLevel(int salaryLevel) {this.salaryLevel = salaryLevel;}}

Controller

package com.artisan.controller;import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;import com.artisan.domain.Artisan;/***
* @ClassName: ArtisanController
* @Description: @Controller标注的Artisan控制层
* @author Mr.Yang
* @date 2018年2月10日
**/
@Controller
public class ArtisanController {private Logger logger = Logger.getLogger(ArtisanController.class);@RequestMapping(value="/artisan_input")public String inputArtisan(Model model) {model.addAttribute(new Artisan());return "ArtisanForm";}@RequestMapping(value="/artisan_save")public String saveArtisan(@ModelAttribute Artisan artisan, BindingResult bindingResult,Model model) {// 如果输入错误,跳转到ArtisanForm页面if (bindingResult.hasErrors()) {FieldError fieldError = bindingResult.getFieldError();logger.info("Code:" + fieldError.getCode() + ", field:" + fieldError.getField());return "ArtisanForm";}// save Artisan heremodel.addAttribute("artisan", artisan);return "ArtisanDetails";}
}

前台JSP

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE HTML>
<html>
<head>
<title>Add Artisan Form</title>
<style type="text/css">@import url("<c:url value="/css/main.css"/>");</style>
</head>
<body><div id="global">
<form:form commandName="artisan" action="artisan_save" method="post"><fieldset><legend>Add an Artisan</legend><p><label for="firstName">First Name: </label><form:input path="firstName" tabindex="1"/></p><p><label for="lastName">Last Name: </label><form:input path="lastName" tabindex="2"/></p><p><!-- 接收显示错误信息 --><form:errors path="birthDate" cssClass="error"/></p><p><label for="birthDate">Date Of Birth: </label><form:input path="birthDate" tabindex="3" /></p><p id="buttons"><input id="reset" type="reset" tabindex="4"><input id="submit" type="submit" tabindex="5" value="Add Artisan"></p></fieldset>
</form:form>
</div>
</body>
</html>

展示页面

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE HTML>
<html>
<head>
<title>Save Artisan</title>
<style type="text/css">@import url("<c:url value="/css/main.css"/>");</style>
</head>
<body>
<div id="global"><h4>The Artisan details have been saved.</h4><p><h5>Details:</h5>First Name: ${artisan.firstName}<br/>Last Name: ${artisan.lastName}<br/>Date of Birth: ${artisan.birthDate}</p>
</div>
</body>
</html>


formatter

Formatter就像Converter一样,也是将一种类型转换为另外一种类型,但是Formatter的源类型必须是String,而Converter的源类型可以是任意类型。

Formatter更加适合Web层,而Converter则可以在任意层中。

为了转换SpringMVC应用程序中的表单的用户输入,始终应该选择Formatter而不是Converter

Step 1 实现Formatter接口

我们先看下
org.springframework.format.Formatter的源码

public interface Formatter<T> extends Printer<T>, Parser<T> {}
public interface Printer<T> {/*** Print the object of type T for display.* @param object the instance to print* @param locale the current user locale* @return the printed text string*/String print(T object, Locale locale);}
public interface Parser<T> {/*** Parse a text String to produce a T.* @param text the text string* @param locale the current user locale* @return an instance of T* @throws ParseException when a parse exception occurs in a java.text parsing library* @throws IllegalArgumentException when a parse exception occurs*/T parse(String text, Locale locale) throws ParseException;}

可以知道需要重写两个方法

  • parse方法利用指定Locale将一个String解析为目标类型

  • print方法与之相反,它是返回目标对象的字符串表示法

来看下具体的用法

编写自定义Formatter类

package com.artisan.converter;import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;import org.springframework.format.Formatter;public class MyFormatter implements Formatter<Date> {private String datePattern;private SimpleDateFormat dateFormat;public MyFormatter(String datePattern) {this.datePattern = datePattern;dateFormat = new SimpleDateFormat(datePattern);dateFormat.setLenient(false);}@Overridepublic String print(Date date, Locale locale) {return dateFormat.format(date);}@Overridepublic Date parse(String s, Locale locale) throws ParseException {try {return dateFormat.parse(s);} catch (ParseException e) {e.printStackTrace();// the error message will be displayed when using <form:errors>throw new IllegalArgumentException("invalid date format. Please use this pattern\"" + datePattern + "\"");}}}

Step 2 SpringMVC配置文件中配置bean及设置conversion-service属性

注册配置文件

<?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:p="http://www.springframework.org/schema/p"xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsd     http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!-- 扫描控制层的注解,使其成为Spring管理的Bean --><context:component-scan base-package="com.artisan.controller"/><!-- 静态资源文件 --><!-- (2)将自定义的convert设置给conversion-service属性 --><mvc:annotation-driven  conversion-service="conversionService"/><mvc:resources mapping="/css/**" location="/css/"/><mvc:resources mapping="/*.jsp" location="/"/><!-- 视图解析器 --><bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/jsp/"/><property name="suffix" value=".jsp"/></bean><!-- (1)自定义fromatter --><bean id="conversionService"class="org.springframework.format.support.FormattingConversionServiceFactoryBean"><property name="formatters"><set><bean class="com.artisan.converter.MyFormatter"><constructor-arg type="java.lang.String" value="MM-dd-yyyy" /></bean></set></property></bean></beans>

为了在Spring中使用Formatter,需要注册org.springframework.format.support.FormattingConversionServiceFactoryBean这个bean。
这个bean与converter的
org.springframework.context.support.ConversionServiceFactoryBean 不同,FormattingConversionServiceFactoryBean可以用一个formatters属性注册Formatter,也可以用converters属性注册converter

测试结果同上。


用registrar注册formatter

注册Formatter的另外一种方式是使用Registrar.

Step 1 编写MyFormatterRegistrar ,注册自定义Formatter

package com.artisan.converter;import org.springframework.format.FormatterRegistrar;
import org.springframework.format.FormatterRegistry;public class MyFormatterRegistrar implements FormatterRegistrar {private String dataPattern;public MyFormatterRegistrar(String dataPattern) {super();this.dataPattern = dataPattern;}@Overridepublic void registerFormatters(FormatterRegistry registry) {registry.addFormatter(new MyFormatter(dataPattern));// u can registry more formatters here }}

Step 2 编写自定义Formatter

package com.artisan.converter;import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;import org.springframework.format.Formatter;public class MyFormatter implements Formatter<Date> {private String datePattern;private SimpleDateFormat dateFormat;public MyFormatter(String datePattern) {this.datePattern = datePattern;dateFormat = new SimpleDateFormat(datePattern);dateFormat.setLenient(false);}@Overridepublic String print(Date date, Locale locale) {return dateFormat.format(date);}@Overridepublic Date parse(String s, Locale locale) throws ParseException {try {return dateFormat.parse(s);} catch (ParseException e) {e.printStackTrace();// the error message will be displayed when using <form:errors>throw new IllegalArgumentException("invalid date format. Please use this pattern\"" + datePattern + "\"");}}}

修改SpringMVC配置文件

有了Registrar,就不用再SpringMVC配置文件中注册任何Formatter了,只要在SpringMVC配置文件中注册Registrar就可以了

Step 3 SpringMVC配置文件中配置bean及设置conversion-service属性

<?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:p="http://www.springframework.org/schema/p"xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsd     http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!-- 扫描控制层的注解,使其成为Spring管理的Bean --><context:component-scan base-package="com.artisan.controller"/><!-- 静态资源文件 --><!-- (2)将自定义的convert设置给conversion-service属性 --><mvc:annotation-driven  conversion-service="conversionService"/><mvc:resources mapping="/css/**" location="/css/"/><mvc:resources mapping="/*.jsp" location="/"/><!-- 视图解析器 --><bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/jsp/"/><property name="suffix" value=".jsp"/></bean><!-- (1)自定义fromatter --><bean id="conversionService"class="org.springframework.format.support.FormattingConversionServiceFactoryBean"><property name="formatterRegistrars"><set><bean class="com.artisan.converter.MyFormatterRegistrar"><constructor-arg type="java.lang.String" value="MM-dd-yyyy" /></bean></set></property></bean></beans>

测试结果同上。


converter or formatter 小结

Converter 是一般工具 ,可以将将一种类型转换为另外一种类型,比如将String 转为Date , Long 转为Date .既可以适应在Web层,也可以使用在其他层中。

Formatter的源类型必须是String,比如将String 转为Date , 但是不能将Long 转为Date

**为了转换SpringMVC应用程序中的表单的用户输入,始终应该选择Formatter而不是Converter**Formatter更加使用Web层。


源码

代码已提交到github

https://github.com/yangshangwei/SpringMvcTutorialArtisan

Spring MVC-06循序渐进之Converter和Formatter相关推荐

  1. Spring MVC自定义类型转换器Converter、参数解析器HandlerMethodArgumentResolver

    文章目录 一.前言 二.类型转换器Converter 1.自定义类型转换器 三.参数解析器 1.自定义分页参数解析器 2.自定义注解参数解析器 一.前言 Spring MVC源码分析相关文章已出: S ...

  2. 【Java学习路线之JavaWeb】Spring MVC框架入门教程

    文章目录 读者 阅读条件 MVC设计模式简介 JSP+JavaBean Servlet+JSP+JavaBean MVC优缺点 优点 缺点 Spring MVC是什么 Spring MVC优点 第一个 ...

  3. 【720科技SpringMVC】第五次课:Converter 和 Formatter

    内容关键词:Converter 和 Formatter.转换器与格式化 知识来源:720科技(张森鹏) 一.知识笔记     Converter 和 Formatter,可以利用它们来引导 Sprin ...

  4. Spring MVC Formatter(数据格式化)详解

    Spring MVC 框架的 Formatter<T> 与 Converter<S,T> 一样,也是一个可以将一种数据类型转换成另一种数据类型的接口.不同的是,Formatte ...

  5. spring mvc的DataBinder、Validator、BeanWrapper、ConversionService、Formatter

    很多人对spring mvc的请求处理流程都不陌生,今天我们要展开讲解的是请求体数据body的绑定.验证.格式化.类型转换,它是怎样实现的呢?其实就是大家熟悉的HandlerAdapter干的事情. ...

  6. Spring MVC Converter(类型转换器)详解

    Spring MVC 框架的 Converter<S,T> 是一个可以将一种数据类型转换成另一种数据类型的接口,这里 S 表示源类型,T 表示目标类型.开发者在实际应用中使用框架内置的类型 ...

  7. Spring MVC更多家族成员----文件上传---06

    Spring MVC更多家族成员----文件上传---06 本节导读 文件上传与MultipartResolver 使用MultipartResolver进行文件上传的简单分析 StandardSer ...

  8. Spring MVC-03循序渐进之Spring MVC

    概述 前面两篇介绍了模型2架构的优势以及如何构建一个模型2应用.但是Spring MVC框架可以帮助我们快速的开发MVC应用. Spring MVC体系概述 若基于某个框架来开发一个模型2的应用程序, ...

  9. spring mvc返回页面显示空白_Spring 框架基础(06):Mvc架构模式简介,执行流程详解...

    一.SpringMvc框架简介 1.Mvc设计理念 MVC是一种软件设计典范,用一种业务逻辑.数据.界面显示分离的方法组织代码,将业务逻辑聚集到一个组件里面,在改进和个性化定制界面及用户交互的同时,不 ...

最新文章

  1. eosjs-ecc中文文档
  2. jsp页面修改成html页面
  3. 时频分析:短时傅里叶变换实现(1)
  4. hp laser103 属性没有配置项_(常见解决方法)UEditor报错“后端配置项没有正常加载,上传插件不能正常使用”...
  5. 工程勘察设计收费标准2002修订版_全过程工程咨询收费模式超全解析
  6. 产品认知:看清事物本质的核心思维——效率思维
  7. javascript中addEventListener与removeEventListener
  8. Selenium UI自动化测试(六)WebDriver常用操作方法
  9. delphi idtcpclient 发送十六进制00_91413足球推荐分析 法甲 04:00 南特 VS 巴黎圣日尔曼...
  10. AD小技巧:更改器件封装
  11. springboot项目PageHelper分页插件的使用
  12. python中的json.loads_Python json模块dumps、loads操作示例
  13. 计算机的音频管理器在哪里打开,Realtek高清晰音频管理器怎么找不到打开教程...
  14. 60秒轻松计算出任意一年任意一天星期几?
  15. 分区字段VALUES LESS THAN时间格式及转换
  16. (1)ENVI-met项目介绍
  17. 爬虫 403 增加header和代理ip也没用?有可能是cloudflare在搞事情
  18. Processing 案例 | 郭锐文先生的 worms
  19. Java学习-面向对象进阶
  20. 【数值分析实验MATLAB】数值积分:梯形公式、辛普森公式、复化梯形公式、复化辛普森公式、龙贝格算法、自适应求积方法

热门文章

  1. C++虚继承下的内存模型(二)
  2. CUDA编程之快速入门
  3. 基于xgboost 的贷款风险预测
  4. nio2 java_java NIO2(file io)
  5. 复随机变量及高斯熵的概念
  6. 7、Reverse Integer(python)
  7. PYTORCH笔记 actor-critic (A2C)
  8. 深究 ElasticSearch 查询的秘密
  9. Python安装、配置图文详解
  10. 远程计算机未能及时反应,Win10无法打开软件提示“服务器没有及时响应或控制请求”怎么办...