当前位置: 首页 > 科技观察

SpringBoot使用转换器将前端参数转换为枚举

时间:2023-03-14 19:49:39 科技观察

前言最近遇到小伙伴问前端枚举转换,实现前端传入的字段值可以是通过转换器(Converter)通过枚举自动接收。自己弄了很多麻烦,现在记录下来分享一下!有兴趣的朋友可以自己试试!这里我使用MyBatis-Plus和SpringBoot2.3.4.RELEASE1实现进程配置转换器/***@authorliuzhihang*@date2021/8/3116:29*/@ConfigurationpublicclassWebConfigimplementsWebMvcConfigurer{@OverridepublicvoidaddFormatters(FormatterRegistryregistry){registry.addConverterFactory(newConverterFactory(){@OverridepublicConvertergetConverter{T[]enums=targetType.getEnumConstants();返回源->{for(Te:enums){if(e.getCode().equals(source)){returne;}}thrownewIllegalArgumentException("枚举代码不正确");};}});}}直接在WebMvcConfigurer中实现addFormatters方法,然后新建ConverterFactory。WebMvcConfigurer相信大家都不陌生。一般会加一些拦截器,一般会用到验证token,日志等。具体可以参考这篇文章:几行代码,轻松跨系统传递traceId,再也不用担心日志匹配不上了!里面还有一些其他的应用。仅此而已,实现起来非常简单。下面介绍项目的内容和代码,方便理解。项目代码请求参数:POSThttp://localhost:8818/user/listByStatusContent-Type:application/json{"orderStatus":1}Controller/***@authorliuzhihang*@date2021/8/3011:08*/@Slf4j@RestController@RequestMapping("/user")publicclassUserController{@AutowiredprivateOrderServiceorderService;@PostMapping(value="/listByStatus")publicResultVOlistByStatus(@Validated@RequestBodyUserRequestrequest){log.info("请求参数:{}",request);ListorderList=orderService.getByOrderStatus(request.getOrderStatus());UserResponseresponse=newUserResponse();response.setRecords(orderList);log.info("返回参数:{}",response);returnResultVO.success(response);}}Entity@DatapublicclassUserRequest{privateOrderStatusEnumorderStatus;privateViewStatusEnumviewStatus;}@DatapublicclassUserResponse{privateListrecords;}Web传入orderStatus为1,后端接收对象的orderStatus字段为OrderStatusEnum类型枚举。这里需要将数值类型的字段自动转换为枚举字段。这个枚举将直接通过MyBatis-Plus查询。为什么要这样使用呢?其实原因很简单。使用枚举来限制数据库字段的类型。比如数据库状态只有0、1、2,所以对应代码中的枚举。防止传入其他值。EnumerationpublicinterfaceBaseEnum{ObjectgetCode();}publicenumOrderStatusEnumimplementsBaseEnum{INIT(0,"InitialState"),SUCCESS(1,"Success"),FAIL(2,"Failure");@EnumValue@JsonValueprivatefinalintcode;privatefinalStringdesc;OrderStatusEnum(intcode,Stringdesc){this.code=code;this.desc=desc;}@OverridepublicIntegergetCode(){returncode;}publicStringgetDesc(){returndesc;}}这里先声明接口BaseEnum,所有枚举继承该接口并实现getCode方法。@EnumValue:MyBatis-Plus枚举,@JsonValue用于数据库字段映射:返回到前端时,这个枚举字段序列化时,返回参数只显示代码。这样就可以达到效果了。请求参数是一个数字,接收对象字段是一个枚举,返回字段也是code。效果测试结果测试结果已经过验证,适合传入值和字符串。它还可以与异常处理程序结合使用以返回一般异常。您可以通过查看@ExceptionHandler了解如何使用它。具体来说,在addFormatters方法中,可以看到registry.addConverterFactory()接收到一个ConverterFactory对象。publicinterfaceConverterFactory{ConvertergetConverter(ClasstargetType);}S是传入的字段类型(number,string)R是要转换成的类型(枚举)T继承R,其实就是参数对象中字段的类型。ConverterFactory的getConverter方法需要返回一个实际的转换器Converter@FunctionalInterfacepublicinterfaceConverter{@NullableTconvert(Ssource);}convert方法的入参是一个source,就是转换成什么类型??,这里是数字/字符串,然后返回一个枚举。注意这里加上@FunctionalInterface就意味着这里可以使用lambda表达式。2优化一般WebConfig中除了实现addFormatters方法外,还会实现addInterceptors等,难免会很长,可以改成下面这样。@ConfigurationpublicclassWebConfigimplementsWebMvcConfigurer{@AutowiredprivateLogInterceptorlogInterceptor;@AutowiredprivateAppTokenInterceptorappTokenInterceptor;@AutowiredprivateEnumConverterFactoryenumConverterFactory;@OverridepublicvoidaddInterceptors(InterceptorRegistryregistry){//日志registry.addInterceptor(logInterceptor).addPathPatterns("/**");//apptoken校验registry.addInterceptor(appTokenInterceptor).addPathPatterns("/app/**");}@OverridepublicvoidaddFormatters(FormatterRegistryregistry){//枚举转换registry.addConverterFactory(enumConverterFactory);}}这需要我们创建EnumConverterFactory类并实现ConverterFactory接口,我们必须注入到Spring容器中@ComponentpublicclassEnumConverterFactoryimplementsConverterFactory{@OverridepublicConvertergetConverter(ClasstargetType){returnnewEnumConverter<>(targetType);}}publicclassEnumConverterimplementsCo变频器{privatefinalClasstargetType;publicEnumConverter(ClasstargetType){this.targetType=targetType;}@OverridepublicTconvert(Objectsource){for(Te:targetType.getEnumConstants()){if(e.getCode().equals(source)){returne;}}thrownewIllegalArgumentException("TheenumerationCodeisincorrect");}}3总结当然这里还有一些其他的优化点,比如使用缓存来缓存Convert,但是我也遇到了另外一个问题就是我的debug断点还没有被打破到转换器。不知道有没有人试过?