springboot mybatis自定义枚举enum转换

原文链接: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;
}
}

原文地址:https://www.cnblogs.com/fswhq/p/9783959.html

时间: 2024-10-15 00:28:55

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

mybatis自定义枚举转换类

mybatis提供了 EnumTypeHandler和EnumOrdinalTypeHandler完成枚举类型的转换,两者的功能已经基本满足了日常的使用.但是可能有这 样的需求:由于某种原因,我们不想使用枚举的name和ordinal作为数据存储字段.mybatis的自定义转换类出现了. 示例 使用一段代码,将枚举类EnumStatus中的code属性存储到数据库对应字段statusCustom. 自定义转换类 package com.sg.util.typehandler; import ja

mybatis 自定义枚举转换类

最近在搭建maven多模块项目: http://git.oschina.net/alexgaoyh/MutiModule-parent 项目整体代码部分在上文链接的git中,下面的代码段落只是部分个人觉得比较重要的段落 在选择持久化DAO部分的时候,选择了mybatis,实体中变量的定义,想来来使用Enum代替常量的某些好处.所以才有下文的这些功能: package com.alexgaoyh.MutiModule.domain; import java.io.Serializable; imp

Springboot整合Mybatis使用TypeHandler来转换数据库中的数据

TypeHandler转换指定数据库中数据为Enum枚举 在一些时候,我们的数据库需要存放一些例如状态信息的数据,通常的我们使用int整型来保存,例如(0:失败,1:成功)等,用这样的数据是可以的,但对于前端的编程是不友好的,所以我们可以使用TypeHandler来进行一个转换,将其转化成一个枚举型. 一.数据库中的数据定义 这里的user_state和user_priority表示了一些状态信息(范围是整数0~5),接下来我们要将这个转化为枚举型 二.创建枚举Enum类 以User_state

C++和Java中枚举enum的用法

在C++和java中都有枚举enum这个关键字,但是它们之间又不太一样.对于C++来说,枚举是一系列命名了的整型常量,而且从枚举值转化为对应的整型值是在内部进行的.而对于Java来说,枚举更像一个类的命名的实例,你可以自定义枚举的成员,枚举值转化为对应的整型值是再外部进行的.下面以我之前的一篇博客8.1 Implement Blackjack 实现21点纸牌来说明,里面有一个扑克牌花色的枚举类: // C++ defination enum Suit {Club, Diamond, Heart,

Lua 与C/C++ 交互系列:动态注册枚举enum到Lua Code中,在运行时在Lua Code中获取内省信息

在Lua 5.1 Reference Manual  对于Lua 值和类型的介绍.Lua是一个动态语言,在Lua中变量仅仅有值而没有类型.所以在Lua中的变量不需要声明.所以的值本身包含类型. 其实Lua 包含一种运行时类型识别,通过type()函数,可以在运行时获取值的类型. 信息来自: Lua 5.1 Reference Manual  Values and Types Lua is a dynamically typed language. This means that variable

枚举enum学习小记

参考文献: [1]C++程序设计语言(特别版), 裘宗燕译, 机械工业出版社 [2]C++ Primer (3rd Ed.), S.B. Lippman and J. Lajoie, 人民邮电出版社   1.枚举enum的用途浅例       写程序时,我们常常需要为某个对象关联一组可选alternative属性.例如,学生的成绩分A,B,C,D等,天气分sunny, cloudy, rainy等等.       更常见的,打开一个文件可能有三种状态:input, output和append.

SpringBoot+MyBatis+MySQL读写分离(实例)

? 1. 引言 读写分离要做的事情就是对于一条SQL该选择哪个数据库去执行,至于谁来做选择数据库这件事儿,无非两个,要么中间件帮我们做,要么程序自己做.因此,一般来讲,读写分离有两种实现方式.第一种是依靠中间件(比如:MyCat),也就是说应用程序连接到中间件,中间件帮我们做SQL分离:第二种是应用程序自己去做分离.这里我们选择程序自己来做,主要是利用Spring提供的路由数据源,以及AOP. 然而,应用程序层面去做读写分离最大的弱点(不足之处)在于无法动态增加数据库节点,因为数据源配置都是写在

validation统一表单验证(含自定义枚举验证)

一般我们对前端传输的参数做判断时,可能都是以以下方式进行判断,如果再加上字段的长度.正则等校验的话就会显得代码很累赘了. // 新增/修改通用参数非空校验 if (StringUtil.isBlank(menu.getParentId())) { throw new LsException(ResultEnum.PARAM_MISSING_ERROR, "父级菜单ID不能为空!"); } if (StringUtil.isBlank(menu.getMenuName())) { thr

SpringBoot+Mybatis+MybatisPlus整合实现基本的CRUD操作

SpringBoot+Mybatis+MybatisPlus整合实现基本的CRUD操作 1> 数据准备 -- 创建测试表 CREATE TABLE `tb_user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', `user_name` varchar(20) NOT NULL COMMENT '用户名', `password` varchar(20) NOT NULL COMMENT '密码', `name` varchar