Java通过注解实现AOP字典转换

一、需求描述:

某一字段在数据库中存储的为数值,而在返回前端时想将它转换为对应的文字,从而不需要前端去维护。

这是在字典表里面具体代表的文字,1代表推送成功,0代表推送失败。

二、解决方案:

1、编写方法注解DictCovert 

作用于controller方法上,用于获取返回的数据

import java.lang.annotation.*;

@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DictCovert {

}

2、编写字段注解Dict 

作业于需要转换的字段上,用于后续找到该需要转换的字段

import java.lang.annotation.*;

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Dict {

    /**
     * 字典类型名称
     */
    String dictTypeName() default "";

    /**
     * 字典存放后缀
     * 默认 "Text"
     * 例 原始字段名:type  翻译储存的字段名:typeText
     **/
    String suffix() default "Text";

}

3、编写字典转换工具类DictUtil 

DictUtil自行适当修改

import cn.hutool.core.util.ObjectUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import javax.annotation.PostConstruct;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@Component
public class DictUtil {

    /**
     * 使用个缓存,避免列表数据多次进行字典查询
     */
    private static ThreadLocal<Map<String,Map<String,String>>> cache  = ThreadLocal.withInitial(ConcurrentHashMap::new);

    //mapper查询数据库,查询字典数字对应的文字
    @Autowired
    private DictionariesItemMapper dictionariesItemMapper;

    private static DictUtil dictUtil;

    @PostConstruct
    public void init() {
        dictUtil = this;
        dictUtil.dictionariesItemMapper = this.dictionariesItemMapper;
    }

    public static Object parseResult(Object result) throws Exception {
        //判断空
        if (Objects.isNull(result)) {
            return null;
        }
        //判断结果类型
        if (result instanceof List) {
            //LIST类型
            List<Object> list = Lists.newArrayList();
            for (Object obj : (List<Object>) result) {
                list.add(parseDict(obj));
            }
            return list;
        } else if (result instanceof TableDataInfo) {
            //自定义的分页返回结果集类型  实际结果在 list字段中。 处理和LIST一致
            TableDataInfo tableDataInfo = (TableDataInfo) result;
            List<Object> list = Lists.newArrayList();
            for (Object obj : tableDataInfo.getRows()) {
                list.add(parseDict(obj));
            }
            //分页数据中 重新放入结果
            tableDataInfo.setRows(list);
            return tableDataInfo;
        } else if (result instanceof AjaxResult){
            //自定义的返回结果集类型  实际结果在 data字段中。 处理和LIST一致
            AjaxResult ajaxResult = (AjaxResult) result;
            Object data = ajaxResult.get("data");
            return AjaxResult.success(parseDict(data));
        } else {
            //单实例对象
            return parseDict(result);
        }
        //.....根据自己的需求判断相应的类型
    }

    /**
     * 字典转换
     *
     * @param obj
     */
    private static Object parseDict(Object obj) throws NoSuchFieldException, IllegalAccessException {
        Field[] fields = obj.getClass().getDeclaredFields();
        //非空判断
        if (ObjectUtil.isEmpty(fields)) {
            return null;
        }
        for (Field field : fields) {
            //判断每一个字典是否有Dict注解
            if (Objects.nonNull(field.getAnnotation(Dict.class))) {
                handleDict(obj, field);
            }
        }
        return obj;
    }


    /**
     * 处理字典注解的字段
     *
     * @param obj
     * @param field
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    private static void handleDict(Object obj, Field field) throws NoSuchFieldException, IllegalAccessException {
        Dict dict = field.getAnnotation(Dict.class);
        String dictTypeName = dict.dictTypeName();
        String suffix = dict.suffix();
        Map<String, String> dictitemValMap = getDictmap(dictTypeName);

        Field name = obj.getClass().getDeclaredField(field.getName() + suffix);

        field.setAccessible(true);
        Object key = field.get(obj);

        name.setAccessible(true);
        name.set(obj, dictitemValMap.get(key.toString()));

        name.setAccessible(false);
        field.setAccessible(false);
    }

    private static Map<String, String> getDictmap(String dictTypeName) {
        Map<String, Map<String, String>> dictMap = cache.get();
        if(dictMap.containsKey(dictTypeName)){
            return dictMap.get(dictTypeName);
        }

        List<DictionariesItem> dictionariesItemList = dictUtil.dictionariesItemMapper.getDictionariesItemMap(dictTypeName);
        Map<String, String> dictItemMap = new HashMap<>();
        if (CollectionUtils.isEmpty(dictionariesItemList)) {
            return dictItemMap;
        }
        for (DictionariesItem dictionariesItem : dictionariesItemList) {
            dictItemMap.put(dictionariesItem.getItemValue(), dictionariesItem.getItemName());
        }
        dictMap.put(dictTypeName,dictItemMap);
        cache.set(dictMap);
        return dictItemMap;
    }


    /**
     * 清除缓存
     */
    public static void clearCache(){
        cache.remove();
    }

}

4、编写AOP类DictAspect

import com.jl.pfs.utils.DictUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.annotation.Configuration;


@Aspect
@Configuration
public class DictAspect {

    @Pointcut("@annotation(com.jl.pfs.aop.dict.DictCovert)")
    public void dictCovert() {
    }

    @Around("dictCovert()")
    public Object process(ProceedingJoinPoint joinPoint) throws Throwable {
        //1.执行原方法
        Object proceed = joinPoint.proceed();
        //2.拿到原方法的原返回值 调用parseResult进行字典转换
        Object result = DictUtil.parseResult(proceed);
        DictUtil.clearCache();
        return result;
    }
}

5、将相应的注解放在相应的地方

@DictCovert作用于Controller上

@Dict作用于属性上

三、实现效果:

统一实现返回时增加的字段显示对应的文字,当字典修改时,返回的文字也会跟着修改

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Java中,可以通过自定义注解实现AOP(面向切面编程)。AOP是一种编程思想,它可以在不修改原有代码的情况下,通过在关注点(例如日志、事务、安全性等)周围插入代码实现特定的功能。 要实现AOP,首先需要创建一个自定义注解。在Spring Boot中,可以使用元注解`@Target`和`@Retention`来指定注解的使用范围和生命周期。然后,可以使用`@interface`关键字来定义注解,并在其中加入相关的元数据,如下所示: ```java @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation { // 自定义注解的元数据 } ``` 在上面的例子中,`@Target(ElementType.METHOD)`表示该注解可以用于方法上,`@Retention(RetentionPolicy.RUNTIME)`表示该注解在运行时仍然可用。 接下来,可以将该注解应用于目标方法上,例如: ```java @MyAnnotation public void myMethod() { // 方法逻辑 } ``` 然后,可以使用AOP框架(如Spring AOP)来拦截带有自定义注解的方法,并在其周围插入额外的代码。这些额外的代码可以实现各种功能,比如日志打印、统计方法耗时等。 总结起来,要实现Java自定义注解实现AOP,需要以下步骤: 1. 创建一个自定义注解,并通过元注解指定其使用范围和生命周期。 2. 将自定义注解应用于目标方法上。 3. 使用AOP框架拦截带有自定义注解的方法,并在其周围插入额外的代码实现特定功能。 通过这种方式,可以实现各种定制化的需求,并且在不修改原有代码的情况下为方法添加额外的功能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Java AOP自定义注解](https://blog.csdn.net/baidu_28340727/article/details/128319277)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值