原文链接: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. 【OpenCV】基于图像处理和模式识别的火灾检测方法

    学期末一直忙考试,大作业,很久没来CSDN耕耘了... 虽然考试都结束了,手头还是累积了不少活儿要补,不多写了,晒个小项目,之前一直做的,后来当做模式识别课程的大作业交了. 大体框架如下: 还是之前的 ...

  2. 2016.5.30让窗口处于最顶层的方法,比TopMost灵活

    最简单的方法Form. Activate() 稍复杂的方法用API,目前没有看出比第一种方法有什么好处(可操作其它窗口,这就是好处2016.7.31) [System.Runtime.InteropS ...

  3. Nginx配置文件中文注释详解

    Nginx ("engine x") 是一个高性能的 HTTP 和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 代理服务器. Nginx 是由 Igor Sysoev ...

  4. Java中自动装箱代码初探

    <深入理解Java虚拟机>中讲语法糖时,提到了下面这个例子(不是原文中的例子,我自己改过): public class AutoBoxingTest { /** * @param args ...

  5. 11-24网页基础--Js框架及学习思路

    第一部分 基本语法: 1.数据类型(字符串.小数.整数.布尔.时间日期)var s="3.14" var n=parsefloat(s) s+=5;var s="abc3 ...

  6. jdbc.properties 文件的配置

    jdbc.properties文件的配置   使用配置文件访问数据库的优点是: 一次编写随时调用,数据库类型发生变化只需要修改配置文件. 配置文件的设置: 在配置文件中,key-value对应的方式编 ...

  7. 复选框操作checked选中为true,反之为False,也可以赋值为true,false

  8. 第2章 构建springboot工程 2-1 构建SpringBoot第一个demo

    以后的趋势肯定是以一个微服务为主导的, Spring-Boot的指导 Maven整个环境构建之前的整个项目其实是一个很普通的J2SE项目,它构建完之后会进行重构,重构为Maven的一个项目路径.可以看 ...

  9. cocos2d中setBlendFunc设置颜色混合方案

    CCSprite有一个ccBlendFunc类型的blendFunc_结构体成员,可以用来设置描绘时的颜色混合方案.ccBlendFunc包含了一个src和一个dst,分别表示源和目标的运算因子. 如 ...

  10. 100722E The Bookcase

    传送门 题目大意 给你一些书的高度和宽度,有一个一列三行书柜,要求放进去书后,三行书柜的高的和乘以书柜的宽度最小.问这个值最小是多少. 分析 我们可以先将所有书按照高度降序排好,这样对于每一层只要放过 ...