文档章节

6.盘点springmvc的常用接口之Converter(中篇)

_Core
 _Core
发布于 2016/07/05 15:36
字数 1063
阅读 736
收藏 0

6.盘点springmvc的常用接口之Converter(中篇)###

上一章简单介绍了Converter接口的使用,Converter接口是用于明确原类型和目标类型之间的转换。

那么怎么才能从原类型转换到某一类的目标类型呢?比如字符串转枚举类型,我有PersonType和PersonStatus两个枚举类型,那么就得有两个转换器PersonTypeConverterPersonStatusConverter,枚举类型再多点,Converter也跟着多。所以Spring提供了一个工厂接口org.springframework.core.convert.converter.ConverterFactory

接口说明

public interface ConverterFactory<S, R> {

	<T extends R> Converter<S, T> getConverter(Class<T> targetType);

}

其中泛型S是source原类型,R是目标类型, T是R的子类型。

和一般的工厂模式一样,这就是提供给我们一个根据子类型返回相应转换器的工具。

如果按Converter的思路做,代码应该是这样子:

public class StringToPersonStatusConverter implements Converter<String, PersonStatus> {  
  
   @Override  
   public PersonStatus convert(String source) {  
       if (Objects.isNull(source)) {  
          return null;  
       }  
       return PersonStatus.valueOf(source);  
   }  
    
}  
public class StringToPersonTypeConverter implements Converter<String, PersonType> {  
  
   @Override  
   public PersonType convert(String source) {  
       if (Objects.isNull(source)) {  
          return null;  
       }  
       return PersonType.valueOf(source);  
   }  
    
}  

每个枚举都要写转换器也太麻烦了,我们可以使用ConverterFactory抽象出转换过程。


package org.springframework.core.convert.support;

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

@SuppressWarnings({"unchecked", "rawtypes"})
final class StringToEnumConverterFactory implements ConverterFactory<String, Enum> {

	@Override
	public <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) {
		Class<?> enumType = targetType;
		while (enumType != null && !enumType.isEnum()) {
			enumType = enumType.getSuperclass();
		}
		if (enumType == null) {
			throw new IllegalArgumentException(
					"The target type " + targetType.getName() + " does not refer to an enum");
		}
		return new StringToEnum(enumType);
	}


	private class StringToEnum<T extends Enum> implements Converter<String, T> {

		private final Class<T> enumType;

		public StringToEnum(Class<T> enumType) {
			this.enumType = enumType;
		}

		@Override
		public T convert(String source) {
			if (source.length() == 0) {
				// It's an empty enum identifier: reset the enum value to null.
				return null;
			}
			return (T) Enum.valueOf(this.enumType, source.trim());
		}
	}
}

这就是Spring内置的StringToEnumConverterFactory源码。

下面这个org.springframework.core.convert.converter.GenericConverter接口是所有的Converter接口中最灵活也是最复杂的一个类型转换接口。之前介绍的Converter接口只支持从一个原类型转换为一个目标类型;ConverterFactory接口只支持从一个原类型转换为一个目标类型对应的子类型;而GenericConverter接口支持在多个不同的原类型和目标类型之间进行转换。

接口说明

public interface GenericConverter {
	//返回这个GenericConverter能够转换的原类型和目标类型的组合
	Set<ConvertiblePair> getConvertibleTypes();
	//用于进行类型转换
	Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
}

其中ConvertiblePair是一对原类型和目标类型的封装。

假设我们有个需求是用person的id或fullname转换成对应的Person对象,可以通过下面的

GenericConverter 实现。

package com.demo.mvc.component;

import java.util.HashSet;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.GenericConverter;

import com.demo.domain.Person;
import com.demo.service.PersonService;

public class PersonGenericConverter implements GenericConverter {

	@Autowired
	private PersonService personService;

	@Override
	public Set<ConvertiblePair> getConvertibleTypes() {
		// 构建原类型和目标类型对
		Set<ConvertiblePair> pairs = new HashSet<ConvertiblePair>();
		pairs.add(new ConvertiblePair(Integer.class, Person.class));
		pairs.add(new ConvertiblePair(String.class, Person.class));
		return pairs;
	}

	@Override
	public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
		if (source == null) {
			return null;
		}
		Person person = null;
		if (sourceType.getType() == Integer.class) {
			// 根据id查询person
			person = personService.findPersonById((Integer) source);
		} else if (sourceType.getType() == String.class) {
			// 根据fullname查询person
			person = personService.findPersonByFullname((String) source);
		}
		return person;
	}
}

getConvertibleTypes方法中添加了两组转换的组合,Integer到Person和String到Person。然后我们给PersonGenericConverter注入了一个PersonService,在convert方法根据参数的类型来决定查询的方法。

GenericConverter还有一个子类接口org.springframework.core.convert.converter.ConditionalGenericConverter 它另外继承了ConditionalConverter

public interface ConditionalGenericConverter extends GenericConverter, ConditionalConverter {

}
public interface ConditionalConverter {

	boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType);

}

顾名思义就是多了matches方法用于条件判断,使得转换器不仅在满足类型匹配时可以转换,还要满足此条件。看一下Spring内置的StringToArrayConverter就好理解了,它实现了ConditionalGenericConverter。在字符串转换到数组的过程中,不仅要原类型为String,目标类型是数组,还有目标类型数组的元素类型也要匹配。

final class StringToArrayConverter implements ConditionalGenericConverter {

	private final ConversionService conversionService;

	public StringToArrayConverter(ConversionService conversionService) {
		this.conversionService = conversionService;
	}

	@Override
	public Set<ConvertiblePair> getConvertibleTypes() {
		return Collections.singleton(new ConvertiblePair(String.class, Object[].class));
	}

	@Override
	public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
		//此处还需判断数组的元素类型是否匹配	
      return this.conversionService.canConvert(sourceType, targetType.getElementTypeDescriptor());
	}

	@Override
	public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
		if (source == null) {
			return null;
		}
		String string = (String) source;
		String[] fields = StringUtils.commaDelimitedListToStringArray(string);
		Object target = Array.newInstance(targetType.getElementTypeDescriptor().getType(), fields.length);
		for (int i = 0; i < fields.length; i++) {
			String sourceElement = fields[i];
			Object targetElement = this.conversionService.convert(sourceElement.trim(), sourceType, targetType.getElementTypeDescriptor());
			Array.set(target, i, targetElement);
		}
		return target;
	}
}

友情链接

盘点springmvc的常用接口目录

© 著作权归作者所有

_Core
粉丝 22
博文 12
码字总数 14027
作品 0
嘉兴
程序员
私信 提问
盘点springmvc的常用接口

springmvc是如今非常流行的web开发框架之一。我个人非常喜欢它约定优于配置的理念。它暴露出非常多的接口,可以让用户自定义自己的实现,从而可以满足大家的各种各样的需求。 而springmvc也不...

_Core
2016/07/02
2.1K
2
7.盘点springmvc的常用接口之Converter(下篇)

前两章介绍了、以及衍生出来的、,最后附录罗列了Spring自带的各种转换器。这么多的转换器,我们开发者可不想在要使用转换器时还自己来查找转换器使用。所以为了统一调用进行类型转换,Sprin...

_Core
2016/07/05
577
0
3.盘点springmvc的常用接口之HttpMessageConverter

前言 举例: POST http://localhost:8080/demo3 传入富文本数据流:Bill Gates 在controller中获得Person对象并响应Person内容:Bill Gates 原始写法: 可以看到原始写法把实体的序列化反序列...

_Core
2016/07/02
788
0
5.盘点springmvc的常用接口之Converter(上篇)

前言 上一章讲完了已淘汰的转换器,那么这一章隆重介绍新的转换器。(别看这接口也叫Converter,和前几章讲到的那个不是同一个东西,千万不要搞混了-_-)。 的缺点其实很明显,它只能实现从S...

_Core
2016/07/04
2.3K
4
4.盘点springmvc的常用接口之PropertyEditor

严格上来说,其实并不能算spring框架的接口,很明显看包名就明白此类是JDK自带的。是Sun所制定的一套JavaBean规范,是为IDE图形化界面准备设置属性值的接口。看接口源码上的说明: 这接口原本...

_Core
2016/07/04
1K
0

没有更多内容

加载失败,请刷新页面

加载更多

代理模式之JDK动态代理 — “JDK Dynamic Proxy“

动态代理的原理是什么? 所谓的动态代理,他是一个代理机制,代理机制可以看作是对调用目标的一个包装,这样我们对目标代码的调用不是直接发生的,而是通过代理完成,通过代理可以有效的让调...

code-ortaerc
今天
5
0
学习记录(day05-标签操作、属性绑定、语句控制、数据绑定、事件绑定、案例用户登录)

[TOC] 1.1.1标签操作v-text&v-html v-text:会把data中绑定的数据值原样输出。 v-html:会把data中值输出,且会自动解析html代码 <!--可以将指定的内容显示到标签体中--><标签 v-text=""></......

庭前云落
今天
8
0
VMware vSphere的两种RDM磁盘

在VMware vSphere vCenter中创建虚拟机时,可以添加一种叫RDM的磁盘。 RDM - Raw Device Mapping,原始设备映射,那么,RDM磁盘是不是就可以称作为“原始设备映射磁盘”呢?这也是一种可以热...

大别阿郎
今天
12
0
【AngularJS学习笔记】02 小杂烩及学习总结

本文转载于:专业的前端网站☞【AngularJS学习笔记】02 小杂烩及学习总结 表格示例 <div ng-app="myApp" ng-controller="customersCtrl"> <table> <tr ng-repeat="x in names | orderBy ......

前端老手
昨天
16
0
Linux 内核的五大创新

在科技行业,创新这个词几乎和革命一样到处泛滥,所以很难将那些夸张的东西与真正令人振奋的东西区分开来。Linux内核被称为创新,但它又被称为现代计算中最大的奇迹,一个微观世界中的庞然大...

阮鹏
昨天
20
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部