最近遇到一个小伙伴问前端枚举转换问题,才意识到可以通过转换器(Converter)自动将前端传入的字段值使用枚举接收。

我自己捣鼓了一番,现在记录笔记分享一下!有兴趣的小伙伴可以自己尝试一下!
这里使用的是 MyBatis-Plus 和 SpringBoot 2.3.4.RELEASE
配置转换器
- /**
 - * @author liuzhihang
 - * @date 2021/8/31 16:29
 - */
 - @Configuration
 - public class WebConfig implements WebMvcConfigurer {
 - @Override
 - public void addFormatters(FormatterRegistry registry) {
 - registry.addConverterFactory(new ConverterFactory
 - @Override
 - public
 Converter - T[] enums = targetType.getEnumConstants();
 - return source -> {
 - for (T e : enums) {
 - if (e.getCode().equals(source)) {
 - return e;
 - }
 - }
 - throw new IllegalArgumentException("枚举 Code 不正确");
 - };
 - }
 - });
 - }
 - }
 
直接在 WebMvcConfigurer 里实现 addFormatters 方法即可,然后 new 一个 ConverterFactory。
WebMvcConfigurer 相信大家都不陌生,一般添加一些拦截器,通用校验 token、日志等等都会用到。具体可以参考这篇文章:几行代码轻松实现跨系统传递 traceId,再也不用担心对不上日志了!,里面有一些其他的应用。
就这些,很简单的实现。下面介绍下项目的内容和代码,方便理解。
项目代码
- POST http://localhost:8818/user/listByStatus
 - Content-Type: application/json
 - {
 - "orderStatus": 1
 - }
 
- /**
 - * @author liuzhihang
 - * @date 2021/8/30 11:08
 - */
 - @Slf4j
 - @RestController
 - @RequestMapping("/user")
 - public class UserController {
 - @Autowired
 - private OrderService orderService;
 - @PostMapping(value = "/listByStatus")
 - public ResultVO
 listByStatus(@Validated @RequestBody UserRequest request) { - log.info("请求参数:{}", request);
 - List
 orderList = orderService.getByOrderStatus(request.getOrderStatus()); - UserResponse response = new UserResponse();
 - response.setRecords(orderList);
 - log.info("返回参数:{}", response);
 - return ResultVO.success(response);
 - }
 - }
 
- @Data
 - public class UserRequest {
 - private OrderStatusEnum orderStatus;
 - private ViewStatusEnum viewStatus;
 - }
 - @Data
 - public class UserResponse {
 - private List
 records; - }
 
Web 传入 orderStatus 为 1,而后端接收对象是 UserRequest 的 orderStatus 字段是个 OrderStatusEnum 类型的枚举。
这里就需要自动将数字类型的字段转换为枚举字段。这个枚举会直接通过 MyBatis-Plus 查询。
为什么要这么用呢?
其实原因很简单,使用枚举限制数据库字段的类型,比如数据库状态只有 0、1、2,那就和代码里的枚举对应起来。防止传入其他值。
- public interface BaseEnum {
 - Object getCode();
 - }
 
- public enum OrderStatusEnum implements BaseEnum {
 - INIT(0, "初始状态"),
 - SUCCESS(1, "成功"),
 - FAIL(2, "失败");
 - @EnumValue
 - @JsonValue
 - private final int code;
 - private final String desc;
 - OrderStatusEnum(int code, String desc) {
 - this.code = code;
 - this.desc = desc;
 - }
 - @Override
 - public Integer getCode() {
 - return code;
 - }
 - public String getDesc() {
 - return desc;
 - }
 - }
 
这里先声明接口 BaseEnum,所有的枚举都继承这个接口,并实现 getCode 方法。
@EnumValue:MyBatis-Plus 的枚举,和数据库字段映射用的
@JsonValue:返回给前端时,这个枚举字段序列化时,返回参数只显示 code。
这样就可以实现效果,请求参数为数字,接收对象字段为枚举,返回字段也是 code。
效果
测试结果
测试结果经过验证,是可以胜任传入数值和字符串的。
也可以结合异常处理器,返回通用异常。具体怎么用查一查 @ExceptionHandler 就知道了。
具体说明
在 addFormatters 方法中可以看到 registry.addConverterFactory() 接收的是一个 ConverterFactory 对象。
- public interface ConverterFactory
 {Converter getConverter(ClasstargetType); - }
 
在 ConverterFactory 的 getConverter 方法则需要返回一个实际的转换器 Converter
- @FunctionalInterface
 - public interface Converter
 {- @Nullable
 - T convert(S source);
 - }
 
convert 方法的入参是一个 source,就是要转换为什么类型的,这里就是数字/字符串,然后返回一个枚举即可。
注意这里加了 @FunctionalInterface 就意味着这里是可以用 lambda 表达式的。
一般 WebConfig 中除了实现 addFormatters 方法外,还会实现 addInterceptors 等等,这样写难免会很长,所以可以改为下面这种。
- @Configuration
 - public class WebConfig implements WebMvcConfigurer {
 - @Autowired
 - private LogInterceptor logInterceptor;
 - @Autowired
 - private AppTokenInterceptor appTokenInterceptor;
 - @Autowired
 - private EnumConverterFactory enumConverterFactory;
 - @Override
 - public void addInterceptors(InterceptorRegistry registry) {
 - // 日志
 - registry.addInterceptor(logInterceptor)
 - .addPathPatterns("/**");
 - // app token校验
 - registry.addInterceptor(appTokenInterceptor)
 - .addPathPatterns("/app/**");
 - }
 - @Override
 - public void addFormatters(FormatterRegistry registry) {
 - // 枚举转换
 - registry.addConverterFactory(enumConverterFactory);
 - }
 - }
 
这种就需要咱们创建 EnumConverterFactory 类并实现 ConverterFactory 接口了,还得注入到 Spring 容器中
- @Component
 - public class EnumConverterFactory implements ConverterFactory
 - @Override
 - public
 Converter - return new EnumConverter<>(targetType);
 - }
 - }
 - public class EnumConverter
 implements Converter - private final Class
 targetType; - public EnumConverter(Class
 targetType) { - this.targetType = targetType;
 - }
 - @Override
 - public T convert(Object source) {
 - for (T e : targetType.getEnumConstants()) {
 - if (e.getCode().equals(source)) {
 - return e;
 - }
 - }
 - throw new IllegalArgumentException("枚举 Code 不正确");
 - }
 - }
 
当然这里也有一些其他的优化点,比如可以使用缓存将 Convert 缓存起来。
不过我也遇到一个其他的问题,就是我 debug 断点竟然一直没有断到转换器中,不知道有没有小伙伴尝试过?
                标题名称:SpringBoot使用转换器将前端参数转换为枚举
                
                本文来源:http://www.csdahua.cn/qtweb/news13/351363.html
            
网站建设、网络推广公司-快上网,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 快上网