6.盤點springmvc的經常使用接口之Converter(中篇)

6.盤點springmvc的經常使用接口之Converter(中篇)###

上一章簡單介紹了Converter接口的使用,Converter接口是用於明確原類型和目標類型之間的轉換。java

那麼怎麼才能從原類型轉換到某一類的目標類型呢?好比字符串轉枚舉類型,我有PersonType和PersonStatus兩個枚舉類型,那麼就得有兩個轉換器PersonTypeConverterPersonStatusConverter,枚舉類型再多點,Converter也跟着多。因此Spring提供了一個工廠接口org.springframework.core.convert.converter.ConverterFactoryspring

接口說明

public interface ConverterFactory<S, R> {

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

}

其中泛型S是source原類型,R是目標類型, T是R的子類型。數組

和通常的工廠模式同樣,這就是提供給咱們一個根據子類型返回相應轉換器的工具。mvc

若是按Converter的思路作,代碼應該是這樣子:dom

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抽象出轉換過程。ide

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接口支持在多個不一樣的原類型和目標類型之間進行轉換。this

接口說明

public interface GenericConverter {
	//返回這個GenericConverter可以轉換的原類型和目標類型的組合
	Set<ConvertiblePair> getConvertibleTypes();
	//用於進行類型轉換
	Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
}

其中ConvertiblePair是一對原類型和目標類型的封裝。.net

假設咱們有個需求是用person的id或fullname轉換成對應的Person對象,能夠經過下面的code

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的經常使用接口目錄

相關文章
相關標籤/搜索