在日常的项目中,往往有很多枚举状态出现,比如性别、账户类型、订单状态等等,在代码编写阶段,对于这种状态类型,使用枚举类是非常方便的,但是由于为了方便与前端或数据库的网络传输、映射和存储,往往会采用约定数字或者特定字符来标识状态,我们有需要将枚举读写为数字或字符,如果用枚举,就要到处添加转换,如果不用枚举,就要头疼会不会写错状态。
怎么解决这个困扰呢?我们先来看最终效果:

只需一个注解,即可配置好让枚举在mybatis存储到数据库时采用数字id,json序列化传给前端时采用字符串,在controller的RequestParam 采用id反序列化为枚举 如果需要也可以通过实现指定接口来详细设定序列化的值
最重要的是一切对于springboot项目都是自动化的,完全可以作为基础组件来在各个项目中引入即可开箱即用
众所周知,在spring中,常见的序列化有3种,分别是 mybatis、json、request
- mybatis 序列化
-
通过
TypeHandler完成java类型和数据库类型互相转换
-
- json序列化(以spring默认json组件 jackson为例)
-
通过
JsonSerializer进行java类的序列化 -
通过
JsonDeserializer进行反序列化为java类
-
- Spring Mvc 中 controller方法的序列化
-
对于
@ResponseBody、@RequestBody注解的值,使用RequestResponseBodyMethodProcessor匹配合适的HttpMessageConverter进行序列化/反序列化,其中常用的HttpMessageConverter为MappingJackson2HttpMessageConverter用以对Accept头为application/json的请求的返回值进行json序列化 -
对于
GET请求中参数方法(简单类型的@RequestParam可以省略),使用RequestParamMethodArgumentResolver并调用TypeConverterDelegate匹配合适的ConversionService进行序列化为方法参数对应的java类型
-
而我们实现这个组件,就需要从这三种序列化中入手
1.首先,我们先写一个注解:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface CustomSerializationEnum {
Type myBatis();
Type json() default Type.NAME;
Type requestParam() default Type.NAME;
enum Type {
NAME,ID,CLASS,TO_STRING
}
}
复制代码
2. 这个注解用于指示这个枚举类如何序列化,稍后我们再详细设置,我们再写一个接口,用于可以详细设置序列化的值,而不是直接使用枚举的原始值,同时,为了更好兼容步骤3中的适配器,我们增加获取原始类和原始对象的方法
import org.springframework.core.annotation.AnnotationUtils;
public interface EnumSerialize<T extends Enum<T> & EnumSerialize<T>> {
default String getSerializationName() {
//noinspection unchecked
return ((Enum<?>) this).name();
}
default Integer getSerializationId() {
//noinspection unchecked
return ((Enum<?>) this).ordinal();
}
/**
* 获取原始类,专门给适配器使用的
*/
default Class<T> getOriginalClass() {
//noinspection unchecked
return (Class<T>) this.getClass();
}
/**
* 获取原始枚举对象,专门给适配器使用的
*/
default Enum<T> getOriginalEnum() {
//noinspection unchecked
return (Enum<T>) this;
}
static <T extends Enum<T> & EnumSerialize<T>> CustomSerializationEnum getAnnotation(Class<T> enumClass) {
return AnnotationUtils.findAnnotation(enumClass, CustomSerializationEnum.class);
}
}
复制代码
3. 那么,想必大家也看出来了,实现这个接口才是正路,那么问题来了,对于没有实现这接口的枚举类怎么办呢?我们把它包装在一个适配器中:
@SuppressWarnings("rawtypes")
public final class EnumSerializeAdapter implements EnumSerialize {
private final Enum<?> enumInstance;
public Enum<?> getEnumInstance() {
return enumInstance;
}
public EnumSerializeAdapter(Enum<?> enumInstance) {
this.enumInstance = enumInstance;
}
@Override
public String getSerializationName() {
return enumInstance.name();
}
@Override
public Integer getSerializationId() {
return enumInstance.ordinal();
}
@Override
public String toString() {
return enumInstance.toString();
}
@Override
public Class<?> getOriginalClass() {
return enumInstance.getClass();
}
@Override
public Enum<?> getOriginalEnum() {
return enumInstance;
}
}
复制代码
4. 这样有了接口,有了适配器,我们就能给一开始注解CustomSerializationEnum中的Type添加具体功能了:
import sun.misc.SharedSecrets;
import java.lang.annotation.*;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
/**
* <H1>指示枚举类自定义序列化的方法,被注解类必须为 <span style="color:#c7c7c7">枚举类</span></H1><br>
* <H1>被注解类通常实现 <

本文介绍了一个巧妙的解决方案,通过自定义注解和接口,实现枚举类在MyBatis、JSON序列化和SpringMVC controller中自动转换。该方案允许在存储时使用数字ID,传输时使用字符串,同时提供了定制化的序列化和反序列化方式。通过注解配置,可以在Spring Boot项目中轻松应用,避免手动转换的繁琐。示例展示了如何在数据库存储、JSON序列化和HTTP请求参数中使用此功能。
最低0.47元/天 解锁文章
979

被折叠的 条评论
为什么被折叠?



