记录下在服务调用之下,存在几种枚举转换的情况,如有问题,请多指正。
流程分析
-
前端发起请求时,例如传入
sex
(性别)为1(男)的参数,在接收到请求时,后端采用SexType sex
枚举类型进行接收,那么此时会发生一次枚举转换即枚举的反序列化,将1转为SexType.MAN
。- 如果请求方式是Get、DELETE,会调用Spring提供的函数进行转换
- 如果请求方式是POST、PUT,会调用默认的json解析框架(
JackSon
)进行转换
-
后端会调用服务(
OpenFeign
)接口,在MyFeignConfig
中配置请求拦截会将第一步中的请求头参数传递到服务接收方的请求头中,然后执行第一步中的转换。 -
使用对象拷贝
hutool的BeanUtil.copyProperties
函数将VO
类转为实体类,进行数据库的查询,在对象拷贝过程中可能会发生枚举类转整形的情况,这时会调用hutool
提供的转换器 -
在执行数据库查询时,传入
QueryWrapper
中,指定sex
为SexType.MAN
。生成sql时会调用mybatis-plus
的类型转换器,将枚举转为具体的值(MybatisEnumTypeHandler
)setParameter:57, CompositeEnumTypeHandler
-
数据库查询后,再次调用
MybatisEnumTypeHandler
转换器将原始值转为枚举 -
所有步骤执行完成需要将数据返给服务调用方
-
如果被JEECG字典切面拦截,那么会先调用
jackson
提供的objectMapper.writeValueAsString
将对象转为json
格式的字符串,此时枚举值变成了原始值,再后续字典翻译的流程,流程结束后返回的对象为JSONObject
类型,再执行下面序列化的流程. -
对于增加了
@ResponseBody
注解的方法,会调用默认JSON
工具objectWriter.writeValue(generator, value)
,对最终的响应进行JSON
序列化。
-
-
open-feign
接收到请求响应后,会将响应结果转化为指定返回值类型,此时会使用fastjson
库进行枚举的反序列化。 -
再执行一次第6步的流程后,请求结束。
注册转换器
SpringMvc
:
- 枚举序列化(出参):委托
jackson
进行序列化,往下看。 - 枚举反序列化(入参):Get请求通过注册转换器
WebMvcConfig
,POST请求委托jackson
进行反序列化 - 获取转换器:通过双重循环遍历类型树匹配到转换器
jackson
:
jackson
支持通过@JsonValue
注解在枚举上标识序列化和反序列化的字段。
-
默认枚举序列化:
JsonValueSerializer.serialize
-
默认枚举反序列化:
EnumDeserializer.deserialze
-
获取转换器:通过当前类型查找,没有则通过枚举类型查找一次
如果默认枚举解析器功能不满足,可以再自定义全局枚举解析器。序列化解析器需要继承
JsonSerializer
,反序列化需要继承JsonDeserializer
,simpleModule.addSerializer(Enum.class, new BaseEnumSerializer());
再注册进
objectMapper
中。值得一提的是,jackson
是支持在注册时不指定具体的枚举类型,这就会对系统中所有枚举生效。
fastjson
:
未查询到类似@JsonValue
注解,必须得自定义枚举解析器。jackson,也是支持对所有枚举类进行指定。可以直接重写获取枚举的函数。
mybatis-plus
mybatis-plus
支持通过@EnumValue
注解在枚举上标识序列化和反序列化的字段。通过实现mybatis
提供的TypeHandler
接口可以实现自定义解析器,mybatis-plus
也是通过MybatisEnumTypeHandler
来支持@EnumValue
注解的。
自定义枚举转换器,在配置文件中进行配置
hutool
使用hutool
提供的BeanUtil.copyProperties
属性拷贝工具。在进行属性拷贝的过程中,可能会出现枚举转化的情况。
但并hutool
未提供可标识字段的注解,且默认的枚举转换器cn.hutool.core.convert.impl.EnumConverter
基本不可用,所以需要自定义转换器。
- 序列化:枚举转
字符串
或者数值
,需要重写CharacterConverter
或者NumberConverter
来处理枚举的情况。 - 反序列化:其他类型转枚举,需要遍历系统中所有存在的枚举类型,挨个进行注册
ConverterRegistry.getInstance().putCustom(clazz, new EnumLabelConverter<>(clazz))
- 获取转换器:对枚举没有做特殊处理 ,需要手动对系统中的所有枚举进行手动注册,官方文档有注册转换器的文章。
easy-excel
和hutool
类似,并未对枚举进行特殊处理,只能对每个枚举进行注册,推荐在实体字段上增加注解来手动指定转换器(根据label进行转换)