原文链接:https://blog.csdn.net/u014527058/article/details/62883573

一、概述

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

清单1:枚举定义

public enum Gender {
MALE, FEMALE;
}

那么,只要客户端在发送请求时,将参数的值设为MALE或FEMALE即可。请求类似如下形式:
http://localhost:8080/handle/enum?gender=MALE

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

二、枚举与接口定义

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

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

package org.fhp.springbootdemo.entity;

import java.util.HashMap;
import java.util.Map; public enum Gender implements BaseEnum {
MALE(1), FEMALE(2); private int value;
private static Map<Integer, Gender> valueMap = new HashMap<>(); static {
for(Gender gender : Gender.values()) {
valueMap.put(gender.value, gender);
}
} Gender(int value) {
this.value = value;
} @Override
public int getValue() {
return value;
} public static Gender getByValue(int value) {
Gender result = valueMap.get(value);
if(result == null) {
throw new IllegalArgumentException("No element matches " + value);
}
return result;
}
}

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

package org.fhp.springbootdemo.entity;

public interface BaseEnum {
int getValue();
}

三、Converter接口

好在Spring为我们提供了一个类型自动转换接口Converter<S, T>,可以实现从一个Object转为另一个Object的功能。除了Converter接口之外,实现ConverterFactory接口和GenericConverter接口也可以实现我们自己的类型转换逻辑。

我们先来看一下Converter接口的定义:

清单4:Converter接口定义

public interface Converter<S, T> { 

T convert(S source); 

}

我们可以看到这个接口是使用了泛型的,第一个类型表示原类型,第二个类型表示目标类型,然后里面定义了一个convert方法,将原类型对象作为参数传入进行转换之后返回目标类型对象。当我们需要建立自己的converter的时候就可以实现该接口。
下面给出一个字符串转换为Gender枚举的converter实现。需要注意的是,在Spring MVC和Spring Boot中,由于从客户端接收到的请求都被视为String类型,所以只能用String转枚举的converter。

清单5:String转Gender的Converter实现

package org.fhp.springbootdemo.converter;

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

public class StringToGenderConverter implements Converter<String, Gender> {

    @Override
public Gender convert(String source) {
return Gender.getByValue(Integer.parseInt(source));
}
}

四、ConverterFactory接口

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

清单6:ConverterFactory的接口定义

public interface ConverterFactory<S, R> { 

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

}

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

清单7:ConverterFactory转换

package org.fhp.springbootdemo.converter;

import org.fhp.springbootdemo.entity.BaseEnum;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory; import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap; public class UniversalEnumConverterFactory implements ConverterFactory<String, BaseEnum> { private static final Map<Class, Converter> converterMap = new WeakHashMap<>(); @Override
public <T extends BaseEnum> Converter<String, T> getConverter(Class<T> targetType) {
Converter result = converterMap.get(targetType);
if(result == null) {
result = new IntegerStrToEnum<T>(targetType);
converterMap.put(targetType, result);
}
return result;
} class IntegerStrToEnum<T extends BaseEnum> implements Converter<String, T> {
private final Class<T> enumType;
private Map<String, T> enumMap = new HashMap<>(); public IntegerStrToEnum(Class<T> enumType) {
this.enumType = enumType;
T[] enums = enumType.getEnumConstants();
for(T e : enums) {
enumMap.put(e.getValue() + "", e);
}
} @Override
public T convert(String source) {
T result = enumMap.get(source);
if(result == null) {
throw new IllegalArgumentException("No element matches " + source);
}
return result;
}
}
}

五、集成至Spring Boot

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

清单8:在配置中绑定ConverterFactory

package org.fhp.springbootdemo;

import org.fhp.springbootdemo.converter.UniversalEnumConverterFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @Configuration
public class MyWebAppConfigurer extends WebMvcConfigurerAdapter { @Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverterFactory(new UniversalEnumConverterFactory());
}
}

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

清单9:在Controller中的用法

package org.fhp.springbootdemo.controller;

import org.fhp.springbootdemo.entity.Gender;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import java.util.HashMap;
import java.util.Map; @RestController
public class HandleEnumController { @RequestMapping("/handle/enum")
public Object handleEnum(@RequestParam("gender") Gender gender) {
Map<String, Object> dataMap = new HashMap<>();
dataMap.put("data", gender.name());
return dataMap;
}
}

springboot mybatis自定义枚举enum转换的更多相关文章

  1. 解决mybatis使用枚举的转换

    解决mybatis使用枚举的转换 >>>>>>>>>>>>>>>>>>>>> ...

  2. mybatis自定义枚举转换类

    转载自:http://my.oschina.net/SEyanlei/blog/188919 mybatis提供了EnumTypeHandler和EnumOrdinalTypeHandler完成枚举类 ...

  3. SpringBoot Mybatis EnumTypeHandler自定义统一处理器

    需求 mybatis目前已经内嵌入了springboot中了,这说明其目前在数据访问层的绝对优势.而我们在开发的过程中,往往会在程序中使用枚举(enum) 来表示一些状态或选项,而在数据库中使用数字来 ...

  4. Mybatis中使用自定义的类型处理器处理枚举enum类型

    知识点:在使用Mybatis的框架中,使用自定义的类型处理器处理枚举enum类型 应用:利用枚举类,处理字段有限,可以用状态码,代替的字段,本实例,给员工状态字段设置了一个枚举类 状态码,直接赋值给对 ...

  5. 学习Spring Boot:(十二)Mybatis 中自定义枚举转换器

    前言 在 Spring Boot 中使用 Mybatis 中遇到了字段为枚举类型,数据库存储的是枚举的值,发现它不能自动装载. 解决 内置枚举转换器 MyBatis内置了两个枚举转换器分别是:org. ...

  6. MyBatis 查询映射自定义枚举

    背景                  MyBatis查询若想映射枚举类型,则需要从 EnumTypeHandler 或者 EnumOrdinalTypeHandler 中选一个来使用         ...

  7. mybatis枚举自动转换(通用转换处理器实现)

    https://blog.csdn.net/fighterandknight/article/details/51520595 https://blog.csdn.net/fighterandknig ...

  8. QMetaEnum利用Qt元数据实现枚举(enum)类型值及字符串转换

    版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:QMetaEnum利用Qt元数据实现枚举(enum)类型值及字符串转换     本文地址:ht ...

  9. Java分享笔记:自定义枚举类 & 使用enum关键字定义枚举类

    在JDK1.5之前没有enum关键字,如果想使用枚举类,程序员需要根据Java语言的规则自行设计.从JDK1.5开始,Java语言添加了enum关键字,可以通过该关键字方便地定义枚举类.这种枚举类有自 ...

随机推荐

  1. Mybatis 一对一(OneToOne)关系映射__INSERT

    今天测试Ibatis的一对一的关联映射时总是出现错误,其中很多的错误都是自己不小心写错的..现把整个Ibatis源代码记录下来,以便以后熟记: 1.数据库脚本: CREATE TABLE t_pers ...

  2. Microsoft Sync Framework下的快速开发同步程序

    Microsoft Sync Frameworks简称MSF,是一个综合的同步平台,MSF支持应用程序,服务,设备的在线以及离线同步.MSF主要有以下几个部件组成:     * Sync Servic ...

  3. [MySQL]修改mysql数据库的root密码的方法

    方法1: 用SET PASSWORD命令 mysql -u root mysql> SET PASSWORD FOR 'root'@'localhost' = PASSWORD('newpass ...

  4. springmvc 中异常处理

    springmvc 中异常处理常见三种处理方式: 1:SimpleMappingExceptionResolver处理的是处理器方法里面出现的异常 2 3.自定义异常处理器:处理的是处理器方法里面出现 ...

  5. js中的toString

    返回对象的字符串表示 objectname.toString([radix])参数 objectname 必选项.要得到字符串表示的对象. radix 可选项.指定将数字值转换为字符串时的进制 说明 ...

  6. 详解CSS float属性(转)

    详解CSS float属性   阅读目录 基础知识 float的详细细节 float特殊情况 clear属性 清除浮动 float的应用 总结 CSS中的float属性是一个频繁用到的属性,对于初学者 ...

  7. 客户注册功能,发短信功能分离 通过ActiveMQ实现

    客户注册功能,发短信功能分离 通过ActiveMQ 配置链接工厂, 配置session缓存工厂(引入链接工厂) 2.配置模板对象JmsTemplate 引入缓存工厂    指定消息模式(队列,发布和订 ...

  8. cmake中设置ELF文件加载动态库的位置

    1. 三个文件 1. world.c #include<stdio.h> void world(void) { printf("world.\n"); } 2. hel ...

  9. 数字图像处理实验(7):PROJECT 04-03 , Lowpass Filtering 标签: 图像处理MATLAB 2017-05-25 09:30 109人

    实验要求: Objective: To observe how the lowpass filtering smoothes an image. Main requirements: Ability ...

  10. ZROI #88

    传送门 分析 我们考虑把每个A[i]考虑为山峰的高度,每次的B考虑为海平面 于是我们知道对于A[i]和A[i-1],如果A[i-1]<A[i]则在A[i-1]<B<=A[i]时会使陆 ...