一、概述

spring类型转换有两种方式:

  • PropertyEditor:可实现String<--->Object 之间相互转换
  • Converter:可实现任意类型的相互转换

类型转换的过程中,当两者同时存在时,spring首先查找PropertyEditor进行类型转换,如果没有找到,则再查找Converter进行转换

二、PropertyEditor

1、基本介绍

PropertyEditor用于 String<--->Object 之间相互转换,spring内建了一些常用的PropertyEditor,如:

ClassEditor:  String<——>Class
FileEditor: String<——>File
PatternEditor: String<——>Pattern
URLEditor: String<——>URL
ResourceEditor: String<——>Resource

自定义的PropertyEditor须继承自PropertyEditorSupport,示例如下:

实体类

public class UserInfo {
private String name;
private Integer age; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Integer getAge() {
return age;
} public void setAge(Integer age) {
this.age = age;
}
}

转换类

public class UserEditor extends PropertyEditorSupport  {

    public UserEditor() {
System.out.println("UserEditor constructed");
} @Override
public String getAsText() {
UserInfo userInfo = (UserInfo) this.getValue();
return JSON.toJSONString(userInfo);
} @Override
public void setAsText(String text) throws java.lang.IllegalArgumentException {
if (StringUtils.isEmpty(text)) {
return;
} UserInfo userInfo = JSON.parseObject(text, UserInfo.class);
this.setValue(userInfo);
}
}

控制器

@Controller
public class TestController5 { @RequestMapping("/type1")
@ResponseBody
public String testType1(@RequestParam("user") UserInfo userInfo) {
System.out.println(userInfo.getName() + " " + userInfo.getAge());
return "testType1";
} @RequestMapping("/type2")
@ResponseBody
public String testType2() {
     System.out.println("void");
return "testType2";
}

   // 注册UserEditor
@InitBinder
public void initBinder(WebDataBinder binder) {
UserEditor userEditor = new UserEditor();
binder.registerCustomEditor(UserInfo.class, userEditor);
System.out.println("initBinder invoked");
}
}

web.xml与spring-mvc.xml配置略

启动后,先后访问:

http://localhost:8080/myweb/type1?user={"name":"matt","age":30}
http://localhost:8080/myweb/type2
http://localhost:8080/myweb/type1?user={"name":"matt","age":30}

输出:

UserEditor constructed
initBinder invoked
matt 30
void
UserEditor constructed
initBinder invoked
matt 30

从输出结果可以看出,处理方法若包含需要类型转换的参数,每次请求都会调用注册方法;处理方法如不包含则不会调用

2、自定义PropertyEditor的注册

自定义PropertyEditor的注册有三种级别:

  • 控制器级别,使用@InitBinder
  • web级别,使用WebBindingInitializer
  • 应用级别,自定义PropertyEditor与实体类同包,且命名为“实体名 + Editor”

i)控制器级别

控制器级别是在控制器类中使用@InitBinder注解来实现,注册范围为单个控制器,如上例所示

ii)web级别

web级别使用WebBindingInitializer来实现,注册范围为应用的所有控制器(即整个web层),示例:

WebBindingInitializer实现类

public class MyWebBindingInitializer implements WebBindingInitializer {

	public void initBinder(WebDataBinder binder, WebRequest request) {
binder.registerCustomEditor(UserInfo.class, new UserEditor());
System.out.println("initBinder invoked!");
}
}

注册

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="webBindingInitializer">
<bean class="cn.matt.convertor.MyWebBindingInitializer"/>
</property>
</bean>

注释上例控制器中的注册方法,即可测试

该注册方法的调用方式与控制器级别相同,即处理方法若包含需要类型转换的参数,每次请求都会调用注册方法;处理方法如不包含则不会调用

补充:web级别的注册方法还有:1、基于继承的BaseController,2、基于@ControllerAdvice注解,这两种方式更简洁,详细可参考:

SpringMVC中利用@InitBinder来对页面数据进行解析绑定

Spring Boot 系列(八)@ControllerAdvice 拦截异常并统一处理

iii)应用级别(推荐)

应用级别的注册范围为spring层,使用方式:自定义PropertyEditor与实体类同包,且命名为“实体名 + Editor”,示例:UserInfoEditor

该注册方法在每次类型转换时均创建新的实例

三、Converter

1、基本介绍

Converter接口定义:

public interface Converter<S, T> {
T convert(S source);
}

Converter作为类型转换器,用于转换S类型到T类型,其实现必须是线程安全的且可以被共享,内建的常用Converter:

StringToBooleanConverter:  String----->Boolean
StringToEnumConverterFactory: String----->enum类型
EnumToStringConverter: enum类型----->String

ConverterRegistry、ConversionService分别用于Converter的注册和运行支持,接口定义如下:

public interface ConverterRegistry {
void addConverter(Converter<?, ?> converter);
void addConverter(Class<?> sourceType, Class<?> targetType, Converter<?, ?> converter);
void addConverter(GenericConverter converter);
void addConverterFactory(ConverterFactory<?, ?> converterFactory);
void removeConvertible(Class<?> sourceType, Class<?> targetType);
}
public interface ConversionService {
boolean canConvert(Class<?> sourceType, Class<?> targetType);
boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType);
<T> T convert(Object source, Class<T> targetType);
Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
}

Spring提供了两个默认实现(其都实现了ConverterRegistryConversionService接口):

  • DefaultConversionService:默认的类型转换服务实现
  • DefaultFormattingConversionService:带数据格式化支持的类型转换服务实现,一般使用该实现即可

使用示例如下:

转换器

public class StringToUserInfoConverter implements Converter<String, UserInfo> {

    public StringToUserInfoConverter() {
System.out.println("StringToUserInfoConverter constructed");
} public UserInfo convert(String source) {
if (StringUtils.isEmpty(source)) {
return null;
} UserInfo userInfo = JSON.parseObject(source, UserInfo.class);
return userInfo;
}
}

测试

@Test
public void test() {
DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
conversionService.addConverter(new StringToUserInfoConverter());
UserInfo userInfo = conversionService.convert("{\"name\":\"matt\",\"age\":30}", UserInfo.class);
System.out.println(userInfo.getName());
}

2、spring mvc中使用Converter

配置

<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="cn.matt.convertor.StringToUserInfoConverter"/>
</list>
</property>
</bean> <bean id="webBindingInitializer" class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name="conversionService" ref="conversionService"/>
</bean> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="webBindingInitializer" ref="webBindingInitializer" />
</bean>

控制器

@Controller
public class TestController6 {
@RequestMapping("/converter")
@ResponseBody
public String testConverter(@RequestParam("user") UserInfo userInfo) {
System.out.println(userInfo.getName() + " " + userInfo.getAge());
return "testConverter";
}
}

启动后,访问http://localhost:8080/myweb/type1?user={"name":"matt","age":30} 即可

补充:当使用<mvc:annotation-driven />时,配置如下

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

<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="cn.matt.convertor.StringToUserInfoConverter"/>
</list>
</property>
</bean>

参考:

SpringMVC数据类型转换——跟着开涛学SpringMVC

@EnableWebMvc

Spring MVC 使用介绍(八)—— 类型转换的更多相关文章

  1. Spring MVC 使用介绍(十三)数据验证 (一)基本介绍

    一.消息处理功能 Spring提供MessageSource接口用于提供消息处理功能: public interface MessageSource { String getMessage(Strin ...

  2. Spring MVC 使用介绍(十五)数据验证 (二)依赖注入与方法级别验证

    一.概述 JSR-349 (Bean Validation 1.1)对数据验证进一步进行的规范,主要内容如下: 1.依赖注入验证 2.方法级别验证 二.依赖注入验证 spring提供BeanValid ...

  3. Spring MVC 使用介绍(十四)文件上传下载

    一.概述 文件上传时,http请求头Content-Type须为multipart/form-data,有两种实现方式: 1.基于FormData对象,该方式简单灵活 2.基于<form> ...

  4. 2017.3.31 spring mvc教程(八) <mvc:annotation-driven />所做的工作

    学习的博客:http://elf8848.iteye.com/blog/875830/ 我项目中所用的版本:4.2.0.博客的时间比较早,11年的,学习的是Spring3 MVC.不知道版本上有没有变 ...

  5. Spring MVC JSON自己定义类型转换(续)

    前面提到了两种转换类型的方法(Spring MVC JSON自己定义类型转换),这里针对Json转换提供一种更简便的方法. 通过配置全局的日期转换来避免使用麻烦的注解. 首先用到了一个简单的日期工具类 ...

  6. spring mvc绑定参数之 类型转换 有三种方式:

    spring mvc绑定参数之类型转换有三种方式: 1.实体类中加日期格式化注解(上次做项目使用的这种.简单,但有缺点,是一种局部的处理方式,只能在本实体类中使用.方法三是全局的.) @DateTim ...

  7. Spring MVC 使用介绍(五)—— 注解式控制器(一):基本介绍

    一.hello world 相对于基于Controller接口的方式,基于注解方式的配置步骤如下: HandlerMapping 与HandlerAdapter 分别配置为RequestMapping ...

  8. Spring MVC 使用介绍(十二)控制器返回结果统一处理

    一.概述 在为前端提供http接口时,通常返回的数据需要统一的json格式,如包含错误码和错误信息等字段. 该功能的实现有四种可能的方式: AOP 利用环绕通知,对包含@RequestMapping注 ...

  9. spring mvc简单介绍xml版

    spring mvc介绍:其实spring mvc就是基于servlet实现的,只不过他讲请求处理的流程分配的更细致而已. spring mvc核心理念的4个组件: 1.DispatcherServl ...

随机推荐

  1. vue2.x 下载后台传过来的流文件(excel)后乱码问题

    1.接口返回的流和头部: 2.下载流文件的代码 方法一:是用了插件 https://github.com/kennethjiang/js-file-download 方法二:是用了 blob 不管哪种 ...

  2. Windows中通过命令行新建文件夹、新建文件,和一些常用命令

    新建文件 和Linux不太一样,Linux中的touch和vi命令创建新文件的方法都不能用了,在windows命令行下得用type nul>文件名.后缀名来创建: F:\study\vue\wo ...

  3. vue 音乐App QQ音乐搜索列表最新接口跨域设置

    在 webpack.dev.config.js中 'use strict' const utils = require('./utils') const webpack = require('webp ...

  4. 高效遍历匹配Json数据,避免嵌套循环[转]

    工作中经常会遇到这样的需求:1.购物车列表中勾选某些,点击任意一项,前往详情页,再返回购物车依旧需要呈现勾选状态2.勾选人员后,前往别的页面,再次返回,人员依旧程勾选状态3.等等.... 数据结构如下 ...

  5. word中字体大小(pt)和网页中css设置font-size时用的px大小对应关系

    pt与px转换关系为 1px= 0.75pt. 所以word中五号字体(10.5pt)在网页中对应的大小为font-size:14px.(10.5 / 0.75 = 14) 初号44pt 小初36pt ...

  6. 批量删除MSSQL 中主外键约束

    转自: http://www.maomao365.com/?p=813 在制作 MSSQL同步工具的时候,发现由于主外键的约束,导致数据同步异常,所有我们需要把 读数据库里面的主外键约束,进行批量删除 ...

  7. vue 组件开发、vue自动化工具、axios使用与router的使用(3)

    一. 组件化开发 1.1 组件[component] 在网页中实现一个功能,需要使用html定义功能的内容结构,使用css声明功能的外观样式,还要使用js定义功能的特效,因此就产生了一个功能先关的代码 ...

  8. Cloudera Manager(CDH5)内部结构、功能包括配置文件、目录位置等

    1. 相关目录 /var/log/cloudera-scm-installer : 安装日志目录./var/log/* : 相关日志文件(相关服务的及CM的)./usr/share/cmf/ : 程序 ...

  9. 文本分类实战(四)—— Bi-LSTM模型

    1 大纲概述 文本分类这个系列将会有十篇左右,包括基于word2vec预训练的文本分类,与及基于最新的预训练模型(ELMo,BERT等)的文本分类.总共有以下系列: word2vec预训练词向量 te ...

  10. SaaS服务和个性化需求,就不能鱼和熊掌兼得吗?

    随时随地.轻松高效,移动工作让人类的自由度最大化.但企业的移动化过程却不轻松:要综合考虑销售.产品.客服.市场销售.人力资源等错综复杂的流程和需求,以及原有IT系统.数据信息的对接. 千企千面,很难有 ...