通过 Spring AOP + 自定义注解 + 反射 的方式,完成值集转换

本文介绍了如何在Java项目中利用AOP和自定义注解,实现在返回结果中将值集字段的code编码自动转换为中文名称。通过创建EnumValue注解和EnumValueAspect切面,展示了如何通过反射遍历字段并进行转换操作。
摘要由CSDN通过智能技术生成

前言:

     本次通过AOP + 自定义注解 + 反射,完成实际项目中值集转换成名称的操作。

目的:

     在Java Bean 中,给某个值集字段,增加一个注解后,返回给前台的结果 Json 中,自动将 code编码 转换成 code编码中文名称

思路:

      1. 自定义一个注解;

      2. 通过AOP中的 @AfterReturning,在返回值被返回前进行数据处理;

      3. 通过反射拿到类中的所有字段,判断字段上是否有自定义注解,如果有,则进行值集转换处理。

代码位置:

      https://gitee.com/jin_0611/java-custom-annotation

下面只展示部分代码,所有的代码都放在了gitee中,有需要可以实际运行一下,加以改造,可以投入到实际项目中。

自定义注解涉及的知识点,请参考:https://blog.csdn.net/zt15732625878/article/details/100061528

1. 自定义一个注解;

package com.duzq.common.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 值集转换注解
 *
 * 使用该注解的Bean对象需要继承 com.duzq.common.entity.BaseEntity
 * @author duzq
 * @date 2021-03-24 14:51:45
 */
// @Target,注解应用的范围(注解可以写到什么地方)
// ElementType.FIELD,应用与属性上(Java Bean的字段,例如:private String name;)
@Target(ElementType.FIELD)
// @Retention,注解的生命周期(什么时候有效)
// RetentionPolicy.RUNTIME,代码编译后可以看到,class文件在JVM中的时候也可以被看到
@Retention(RetentionPolicy.RUNTIME)
public @interface EnumValue {

    /**
     * 枚举
     */
    String enumType() default "";

    /**
     * 将转换后的值赋值到哪个变量上面
     * 不传入值,使用添加了该注解的字段后面拼接 xxxName
     */
    String targetField() default "";
}

 2. 通过AOP中的 @AfterReturning,在返回值被返回前进行数据处理;

 3. 通过反射拿到类中的所有字段,判断字段上是否有自定义注解,如果有,则进行值集转换处理。

package com.duzq.common.aop;

import com.duzq.common.annotation.EnumValue;
import com.duzq.common.entity.BaseEntity;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;

/**
 * 值集转换注解 aop
 *
 * @author duzq
 * @date 2021-03-24 14:51:45
 */
@Component
@Aspect
public class EnumValueAspect {

    /**
     * 在返回之前进行拦截
     */
    @AfterReturning(value = "execution(* com.duzq.controller..*.*(..))", returning = "result")
    public Object enumValue(Object result) {

        // 空返回直接返回
        if (Objects.isNull(result)) {
            return null;
        }

        // list,特殊处理一下
        if (result instanceof List) {
            List list = (List) result;
            for (Object o : list) {
                setEnumValue(o, o.getClass());
            }
            return result;
        }

        // 项目中单个的自定义Bean对象,进行处理
        setEnumValue(result, result.getClass());
        return result;
    }

    /**
     * 开始根据注解,转换值
     *
     * @param result
     */
    private void setEnumValue(Object result, Class clazz) {

        // 不是自己项目中的 bean 直接返回
        if (!(result instanceof BaseEntity)) {
            return;
        }
        // 如果当前的类是 BaseEntity,则不执行后续操作
        if (BaseEntity.class.getName().equals(result.getClass().getName())) {
            return;
        }

        // 1. 获取当前对象的所有字段
        Field[] fields = clazz.getDeclaredFields();
        if (fields == null || fields.length == 0) {
            return;
        }
        // 2. 遍历字段上是否有自定义注解
        for (Field field : fields) {
            try {
                EnumValue annotation = field.getAnnotation(EnumValue.class);
                if (annotation == null) {
                    continue;
                }
                if (Objects.isNull(annotation.enumType())) {
                    continue;
                }
                // 通过设置可以访问私有变量的值
                field.setAccessible(true);
                if (Objects.isNull(field.get(result))) {
                    continue;
                }
                // 获取跟CODE编码的名称
                String codeName = getCodeName(annotation.enumType(), field.get(result));
                if (Objects.isNull(codeName)) {
                    continue;
                }
                // 编辑set方法名称
                String setMethodName = null;
                if (!"".equals(annotation.targetField())) {
                    setMethodName = "set" +
                            annotation.targetField().substring(0, 1).toUpperCase() +
                            annotation.targetField().substring(1);
                } else {
                    setMethodName = "set" +
                            field.getName().substring(0, 1).toUpperCase() +
                            field.getName().substring(1) +
                            "Name";
                }
                // 执行set方法
                Method method = result.getClass().getMethod(setMethodName, String.class);
                if (Objects.isNull(method)) {
                    continue;
                }
                method.invoke(result, codeName);
            } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
                e.printStackTrace();
            }
        }
        // 递归获取父类的属性
        setEnumValue(result, clazz.getSuperclass());
    }

    /**
     * 获取跟CODE编码的名称
     *
     * @param enumType
     * @param code
     * @return
     */
    private String getCodeName(String enumType, Object code) {
        // TODO: 查询缓存、或者查询数据库,每个项目不一致,需要维护成自己项目中的代码
        // TODO: 只是为了梳理自定义注解使用的场景,返回值写了固定值。
        return "查询缓存、或者查询数据库";
    }

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值