SpringBoot绑定枚举参数

一、概述
在利用Spring进行Web后台开发时,经常会遇到枚举类型的绑定问题。一般情况下,如果Spring接收到的参数值为字符串类型,Spring会根据枚举的值与传入的字符串进行对应。假设有如下枚举

清单1:枚举定义

public enum Season {
	Spring("春"),Summer("夏"),Autumn("秋"),Winter("冬");
}

那么,只要客户端在发送请求时,将参数的值设为MALE或FEMALE即可。请求类似如下形式:

http://localhost:8080/handle/enum?season=Summer

但是,假如客户端传来的参数值不是枚举值对应的字符串,而是诸如整数值之类的值,Spring就没法做自动对应了。这种情况下该如何处理呢?

二、枚举与接口定义
好了,从现在开始,我们将使用如下枚举进行参数绑定。

清单2:需要进行转换的枚举定义

public enum Season implements IBaseEnum{
	Spring("春"),Summer("夏"),Autumn("秋"),Winter("冬");
	
	private static final Map seaMap = new HashMap(); 
	
	static {
		for (Season season : Season.values()) {
			seaMap.put(season.value, season);
		}
	}
	
	private String value;

	private Season(String value) {
		this.value = value;
	}

	@Override
	public String getValue() {
		return this.value;
	}
	/**
	 * 根据值获取枚举
	 * @param value
	 * @return
	 */
	public static Season getEnumByValue(String value) {
		return seaMap.get(value);
	}

}

在这里,我们令所有的枚举都实现IBaseEnum接口,以便转换时使用。IBaseEnum接口定义如下:
清单3:枚举所需的实现接口

public interface IBaseEnum {
		/**
		 *  获取标示
		 * @return
		 */
		String getValue();
}

三、ConverterFactory接口
ConverterFactory的出现可以让我们统一管理一些相关联的Converter。顾名思义,ConverterFactory就是产生Converter的一个工厂,确实ConverterFactory就是用来产生Converter的。我们先来看一下ConverterFactory接口的定义:

清单4:ConverterFactory的接口定义

public interface ConverterFactory {  
     
     Converter getConverter(Class targetType);  
}

我们可以看到ConverterFactory接口里面就定义了一个产生Converter的getConverter方法,参数是目标类型的class。我们可以看到ConverterFactory中一共用到了三个泛型,S、R、T,其中S表示原类型,R表示目标类型,T是类型R的一个子类。
可以看出,ConverterFactory相比ConvertFactory的好处在于,ConverterFactory可以将原类型转换成一组实现了相同接口类型的对象,而Converter则只能转换成一种类型。这样做的坏处在于,假如我们又定义了其他枚举,那么对于每一个枚举,我们都需要实现一个对应的Converter,十分的不方便。而有了ConverterFactory之后,事情就变得简单了不少。现在可以定义一个String到所有实现了IBaseEnum的枚举的ConverterFactory,然后根据目标类型生成对应的Converter来进行转换操作。如清单5所示。

@SuppressWarnings("all")
public class BaseEnumFactory implements ConverterFactory{
	/**
	 * 缓存IBaseEnum实现类
	 */
	private static final Map, Converter> cacheMap = new HashMap<>();

	@Override
	public  Converter getConverter(Class targetType) {
		Converter converter = cacheMap.get(targetType);
		if (converter == null) {
			converter = new BaseEnumImpl(targetType);
			cacheMap.put(targetType, converter);
		}
		return (Converter) converter;
	}
	
	/**
	 * 内部转换类
	 * @author zhaoyong
	 *
	 * @param 
	 */
	private class BaseEnumImpl implements Converter {
		
		private Class clazz;
		
		private Map enumMap = new HashMap<>();
		
		private BaseEnumImpl(Class clazz) {
			this.clazz = clazz;
			T[] enums = clazz.getEnumConstants();
			for (T t : enums) {
				enumMap.put(t.getValue(), t);
			}
		}

		@Override
		public T convert(String source) {
			return enumMap.get(source);
		}
	}
}

四、集成至Spring Boot
在Spring Boot中,可以通过覆盖addFormatter方法来实现对Converter和ConverterFactory的绑定。

清单6:在配置中绑定ConverterFactory

@Configuration
public class MyWebAppConfigurer implements WebMvcConfigurer{

	@Override
	public void addFormatters(FormatterRegistry registry) {
		registry.addConverterFactory(new BaseEnumFactory());
		WebMvcConfigurer.super.addFormatters(registry);
	}
}

当然,也可以通过registry.addConverter()方法来绑定Converter。
在Controller中,采用如下方式来进行接收,和平常接收参数是一样的用法。

清单7:在Controller中的用法

@RestController
public class HandleEnumController {
 
    @RequestMapping("/handle/enum")
    public Object handleEnum(@RequestParam("season") Season season) {
        return season;
    }
}

参考:https://blog.csdn.net/u014527058/article/details/62883573

你可能感兴趣的:(SpringBoot绑定枚举参数)