优雅地在Java应用中实现全局枚举处理的方法

2019-09-13 11:24:06王冬梅

下面是枚举接口和一个枚举示例:

public interface Enumerable<E extends Enumerable> {

 /**
  * 获取在i18n文件中对应的 key
  * @return key
  */
 @Nonnull
 String getKey();

 /**
  * 获取最终保存到数据库的值
  * @return 值
  */
 @Nonnull
 int getValue();

 /**
  * 获取 key 对应的文本信息
  * @return 文本信息
  */
 @Nonnull
 default String getText() {
  return I18nMessageUtil.getMessage(this.getKey(), null);
 }
}
public enum GenderEnum implements Enumerable {

 /** 男 */
 MALE(1, "male"),

 /** 女 */
 FEMALE(2, "female");

 private int value;

 private String key;

 GenderEnum(int value, String key) {
  this.value = value;
  this.key = key;
 }

 @Override
 public String getKey() {
  return this.key;
 }

 @Override
 public int getValue() {
  return this.value;
 }
}

我们要做的就是,每个我们编写的枚举类,都需要按这样的方式进行编写,按照规范定义的枚举类方便下面统一编写。

2、我们分析下controller层面的数据进和出,从而处理好枚举类和int值的转换,在Spring MVC中,框架帮我们做了数据类型的转换,所以我们以 Spring MVC作为切入点。前台发送到服务端的请求,一般有参数在url中和body中两种方式为主,分别以get请求和post请求配合@RequestBody为代表。

【入参】get方法为代表,请求的MediaType为"application/x-www-form-urlencoded",此时将 int 转换成枚举,我们注册一个新的Converter,如果spring MVC判断到一个值要转换成我们定义的枚举类对象时,调用我们设定的这个转换器

@Configuration
public class MvcConfiguration implements WebMvcConfigurer, WebBindingInitializer {

 /**
  * [get]请求中,将int值转换成枚举类
  * @param registry
  */
 @Override
 public void addFormatters(FormatterRegistry registry) {
  registry.addConverterFactory(new EnumConverterFactory());
 }
}

public class EnumConverterFactory implements ConverterFactory<String, Enumerable> {

 private final Map<Class, Converter> converterCache = new WeakHashMap<>();

 @Override
 @SuppressWarnings({"rawtypes", "unchecked"})
 public <T extends Enumerable> Converter<String, T> getConverter(@Nonnull Class<T> targetType) {
  return converterCache.computeIfAbsent(targetType,
    k -> converterCache.put(k, new EnumConverter(k))
  );
 }

 protected class EnumConverter<T extends Enumerable> implements Converter<Integer, T> {

  private final Class<T> enumType;

  public EnumConverter(@Nonnull Class<T> enumType) {
   this.enumType = enumType;
  }

  @Override
  public T convert(@Nonnull Integer value) {
   return EnumUtil.of(this.enumType, value);
  }
 }
}

【入参】post为代表,将 int 转换成枚举。这块我们和前台达成一个约定( Ajax中applicationType),所有在body中的数据必须为json格式。同样后台@RequestBody对应的参数的请求的MediaType为"application/json",spring MVC中对于Json格式的数据,默认使用 Jackson2HttpMessageConverter。在Jackson转换成实体时候,有@JsonCreator和@JsonValue两个注解可以用,但是感觉还是有点麻烦。为了统一处理,我们需要修改Jackson对枚举类的序列化和反序列的支持。配置如下: