时间:2022-11-07 09:38:50 | 栏目:JAVA代码 | 点击:次
最近在写代码时遇到一个需要将entity字段通过字典翻译成真实值的场景,原来的做法是通过主表字段和字典表关联的形式,当一个需要大量翻译的场景时,大量的关联会造成sql阅读的不友好,所以就在想有什么可以偷懒的方法。。。
首先一个想法就是通过注解,实例化entity时就可以同步翻译了。
先自定义注解
@Target({ElementType.FIELD,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface DictCovert { /** * 字典key * @return */ String key() default ""; /** * 是否使用redis * @return */ boolean redis() default false; }
然后在需要转换的entity属性上加上注解和该属性的key
/** * 性别 */ @DictCovert(key = "gender",redis = true) private Integer gender;
有了注解,首先想到的就是通过AOP去切该注解@Pointcut("@annotation(*.*.*.DictCovert)"),捕获到切点时同步处理数据就行
赶紧写好代码运行,发现没有如愿以偿,因为我们自定义的注解加在了entity上,但是entity并没有交给spring管理,所以切点根本没有奏效,草(一种植物)!!。。。。。
于是又想到了通过自定义MessageConverter的形式捕获注解处理,然后依旧是草(一种植物)!!!!
最终最终还是找到通往罗马的路了?
通过注解@ControllerAdvice处理全局的数据,然后继承ResponseBodyAdvice接口重写beforeBodyWrite方法,处理数据
直接贴代码(代码有点长,个人水平有限,轻喷?)
@ControllerAdvice @Slf4j public class DictCovertHandler implements ResponseBodyAdvice { @Autowired private RedisTemplate redisTemplate; @Autowired private ISysDicService sysDicService; private final String DICTDIR = "DICT:"; @Override public boolean supports(MethodParameter returnType, Class converterType) { //直接为true,所有返回结果都应该检验 return true; } @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { try{ Result result = (Result)body; //获取返回值列表 List<?> resList =new ArrayList<>(); Object resValue = result.getData(); //未分页结果 if(resValue instanceof ArrayList){ resList =(ArrayList) resValue; } //分页结果 if(resValue instanceof Page){ resList = ((Page<?>) resValue).getRecords(); } //非查询结果 if(CollectionUtil.isEmpty(resList)){ return body; } List<Map<String,Object>> resultList = new ArrayList(); for (Object entity : resList) { //拿到bean将其转换为map输出 Map<String,Object> map = BeanUtil.beanToMap(entity); //获取字段列表 Field[] fields = entity.getClass().getDeclaredFields(); if(fields.length != 0){ for (Field field : fields) { //存放真实值 String realValue =null; //获取注解列 DictCovert dictCovert = field.getAnnotation(DictCovert.class); if(!Objects.isNull(dictCovert)){ String dictKey = dictCovert.key(); //是否使用redis,default:false boolean redis = dictCovert.redis(); String fieldName = field.getName(); String methodName = "get"+dictKey.substring(0,1).toUpperCase()+dictKey.substring(1,dictKey.length()); Method method = entity.getClass().getMethod(methodName,null); //获取字典原始值 Object value =method.invoke(entity,null); if(Objects.isNull(value)){ continue; } String redisKey= dictKey+"_"+value; //使用redis if(redis){ //从redis加载字典真实信息 realValue = (String) redisTemplate.opsForValue().get(DICTDIR+redisKey); } if(StrUtil.isBlank(realValue)){ SysDic sysDic = sysDicService.getById(Integer.parseInt(value.toString())); if(!Objects.isNull(sysDic)){ realValue = sysDic.getDictLabel(); //将结果塞入redis redisTemplate.opsForValue().set(DICTDIR+redisKey,realValue); } } map.put(fieldName+"String",realValue); } } } resultList.add(map); } result.setData(resultList); return result; }catch (Exception e ){ //翻译失败返回原来的值 log.error("字典翻译失败",e); return body; } } }
最后在返回值中会有一个带有String的属性,那就是翻译后的值