枚举转换踩坑

记录下在服务调用之下,存在几种枚举转换的情况,如有问题,请多指正。

流程分析

  1. 前端发起请求时,例如传入sex(性别)为1(男)的参数,在接收到请求时,后端采用SexType sex枚举类型进行接收,那么此时会发生一次枚举转换即枚举的反序列化,将1转为SexType.MAN

    • 如果请求方式是Get、DELETE,会调用Spring提供的函数进行转换
    • 如果请求方式是POST、PUT,会调用默认的json解析框架(JackSon)进行转换
  2. 后端会调用服务(OpenFeign)接口,在MyFeignConfig中配置请求拦截会将第一步中的请求头参数传递到服务接收方的请求头中,然后执行第一步中的转换。

  3. 使用对象拷贝hutool的BeanUtil.copyProperties函数将VO类转为实体类,进行数据库的查询,在对象拷贝过程中可能会发生枚举类转整形的情况,这时会调用hutool提供的转换器

  4. 在执行数据库查询时,传入QueryWrapper中,指定sexSexType.MAN。生成sql时会调用mybatis-plus的类型转换器,将枚举转为具体的值(MybatisEnumTypeHandler

    setParameter:57, CompositeEnumTypeHandler

  5. 数据库查询后,再次调用MybatisEnumTypeHandler转换器将原始值转为枚举

  6. 所有步骤执行完成需要将数据返给服务调用方

    1. 如果被JEECG字典切面拦截,那么会先调用jackson提供的objectMapper.writeValueAsString将对象转为json格式的字符串,此时枚举值变成了原始值,再后续字典翻译的流程,流程结束后返回的对象为JSONObject类型,再执行下面序列化的流程.

    2. 对于增加了@ResponseBody注解的方法,会调用默认JSON工具objectWriter.writeValue(generator, value),对最终的响应进行JSON序列化。

  7. open-feign接收到请求响应后,会将响应结果转化为指定返回值类型,此时会使用fastjson库进行枚举的反序列化。

  8. 再执行一次第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进行转换)

相关推荐
金銀銅鐵28 分钟前
[Java] JDK 9 新变化之 Convenience Factory Methods for Collections
java·后端
微小冷41 分钟前
Rust图形界面教程:egui基础组件的使用
后端·rust·gui·egui·button·panel·用户图形界面
javadaydayup1 小时前
同样是简化代码,Lambda 和匿名内部类的核心原理是什么?
后端
Yeats_Liao1 小时前
时序数据库系列(六):物联网监控系统实战
数据库·后端·物联网·时序数据库
金銀銅鐵1 小时前
[Java] 用 Swing 生成一个最大公约数计算器
java·后端
brzhang1 小时前
我觉得可以试试 TOON —— 一个为 LLM 而生的极致压缩数据格式
前端·后端·架构
苏三的开发日记1 小时前
库存预扣减之后,用户订单超时之后补偿库存的方案
后端
知其然亦知其所以然2 小时前
这波AI太原生了!SpringAI让PostgreSQL秒变智能数据库!
后端·spring·postgresql
观望过往3 小时前
Spring Boot 集成 EMQ X 4.0 完整技术指南
java·spring boot·后端·emqx