自定义注解结合切面实现参数值的自动注入

自定义注解结合切面实现参数值的自动注入

一.自定义注解

/**
 * 创建时间的注解
 **/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CreateDateTime {
}

/**
 * 创建人名,当前用户名
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CreatePerson {
}

/**
 * 是否需要通过切面自动注入属性  切面找到就是这个注解
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NeedAutoSetParam {
}

二.定义切面

@Aspect
@Component
public class AutoSetValueAspect {

    /**
     * 切入点 所有标有RestController类下的方法都会进入
     */
    @Pointcut("execution(* com.xxx..*(..)) && @within(org.springframework.web.bind.annotation.RestController)")
    public void declareJoinPointExpression(){}

    /**
     * 切面的具体处理过程
     * @param pjd
     * @return
     * @throws Throwable
     */
    //@Around("declareJoinPointExpression()") // 这个则是切了所有的Controller类中的方法
    @Around("@annotation(autoSet)")  // 切入点是 NeedAutoSetParam  注解
    public Object aroundMethod(ProceedingJoinPoint pjd,NeedAutoSetParam autoSet) throws Throwable {
        Object result = null;
        try {
            // 获取当前用户信息  项目中会将用户存储在ThreadLocal中, 这里直接过去当前用户 
            UserInfo userInfo = UserInfoContext.getUser();
            // 遍历所有参数
            for (Object argObj : pjd.getArgs()) {
                // 初始化值
                this.setBaseInfo(argObj, argObj.getClass(), userInfo);
            }
            result = pjd.proceed();
        } catch (Throwable e) {
            throw e;
        }
        return result;
    }

    /**
     * 将指定标签的属性赋值
     * @param obj
     * @param clazz
     * @param userInfo
     */
    private void setBaseInfo(Object obj, Class clazz, UserInfo userInfo) {
        if (!isTargetObj(obj)) {
            return;
        }
        // 如果是集合,则循环执行
//        if (obj instanceof Collection) {
//            for (Object item : (List) obj) {
//                if (isTargetObj(item)) {
//                    setBaseInfo(item, item.getClass(), userInfo);
//                }
//            }
//        }
        // 如果存在父类,则再次执行,用于将父类的属性初始化
//        if (!clazz.getSuperclass().equals(Object.class)) {
//            // 父类setBaseInfo
//            setBaseInfo(obj, clazz.getSuperclass(), userInfo);
//        }
        // 遍历所有属性
        Arrays.stream(obj.getClass().getDeclaredFields())
                .forEach(field -> {
                    Object fieldValue = getFieldValue(obj, field);
                    // 如果存在 引用属性,则再次执行
                    if (isTargetObj(fieldValue)) {
                        setBaseInfo(fieldValue, field.getType(), userInfo);
                    } else {
                        // 判断属性是否包含某些注解,进而初始化不同的值
                        if (field.isAnnotationPresent(CreateDateTime.class) && field.getType().equals(Date.class)) {
                            setFieldValue(obj, field, new Date());
                        } else if (field.isAnnotationPresent(CreatePerson.class) && field.getType().equals(Integer.class)) {
                            setFieldValue(obj, field, userInfo.getUserId());
                        }
                        // 还可以追加其他注解,看情况定 ,这里只写两个实例
                    }
                });
    }

    /**
     * 判断参数是否合法
     * @param object
     * @return
     */
    private boolean isTargetObj(Object object) {
        // null 则不需要初始化值, 前端没有传递参数错误
        if (object == null) {
            return false;
        }
        // 自定义包下的类才需要执行切面
        if (object.getClass().getName().startsWith("com.fqkj")) {
            return true;
        }
//        if (object instanceof Collection) {
//            return true;
//        }
        return false;
    }

    private Object getFieldValue(Object obj, Field field) {
        try {
            field.setAccessible(true);
            return field.get(obj);
        } catch (Exception e) {
        }
        return null;
    }

    private void setFieldValue(Object obj, Field field, Object value) {
        try {
            field.setAccessible(true);
            field.set(obj, value);
            return;
        } catch (Exception e) {
        }
        try {
            char[] tmp = field.getName().toCharArray();
            tmp[0] = Character.toUpperCase(tmp[0]);
            String setter = "set" + new String(tmp);
            obj.getClass().getMethod(setter).invoke(obj, value).toString();
            return;
        } catch (Exception e) {
        }
    }
}

三.使用实例

@Data
public class Test{
    
    /**
     * 创建时间
     */
    @CreateDateTime
    private Date createTime;

    /**
     * 创建人id
     */
    @CreatePerson
    private String createUserId;


// 表明该方法的参数需要自动注入一些属性
@NeedAutoSetParam
@Transactional(rollbackFor = Exception.class)
public int testFun(Test test) {
    System.out.pringln(test.getCreateTime);
    System.out.pringln(test.getCreateUserId);
    return "";
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值