Java注解动态解析获取方法参数值

在这里插入图片描述

应用场景

当记录日志时, 不仅是需要文字的描述, 而且要动态获取数据, 拼接到文字上

比如: 创建用户操作 应该要写成 ==> 创建了用户: #{user.username}

其中#{user.username} 就应该从形参中去获取

那么就涉及到了 在注解中动态解析形参中的值

# 1. 使用方式
- 提供resolverContent方法进行解析内容
- 比如解析 
String contextEL = "用户名:+#{user.username}+,用户密码:+#{user.password}+,用户年龄:+#{map.age}+,手机号:+#{map.phone.number}"
- 注入使用即可
`proceedingJoinPoint 是环绕切面中的参数, 带入即可`
@Autowired
private ResolverKit resolverKit;

// 解析后的数据
String content = resolverKit.resolverContent(contextEL, proceedingJoinPoint));
# 2. 解析注意
- 支持map对象获取key `#{map.key}`  key是具体的值
- 但是不支持在对象中嵌套map `#{user.map.key}`   key是具体的值
- 最多支持三个变量, 比如 `#{user.phone.number}`
/**
 * @author wangdi
 * @date 21-9-2
 */
@Component
@Slf4j
public class ResolverKit {

    private static final String PREFIX = "#{";
    private static final String SUBFIX = "}";


    /**
     * @param contextEL           带表达式的内容
     *                            举例:"用户名:+#{user.username}+,用户密码:+#{user.password}+,用户年龄:+#{user.age}+,手机号:+#{user.phone.number}"
     *                            注意:支持map对象获取key(map.key),但是不支持在对象中嵌套map(user.map.key)
     * @param proceedingJoinPoint
     * @return
     */
    public StringBuffer resolverContent(String contextEL, ProceedingJoinPoint proceedingJoinPoint) {
        try {
            StringBuffer context = new StringBuffer();
            /**
             *  文字+#{map.name}+,+#{map.age}+#{map.abc}+.
             *  拆分
             *
             *  文字
             *  #{map.name}
             *  ,
             *  #{map.age}
             *  #{map.abc}
             *  .
             */
            if (contextEL.contains(PREFIX) && contextEL.contains(SUBFIX) && contextEL.contains("+")) {

                List<String> strings = Arrays.asList(contextEL.split("\\+"));
                for (String s : strings) {
                    if (s.contains(PREFIX) && s.contains(SUBFIX)) {
                        // 解析表达式
                        String spel = s.substring(s.indexOf(PREFIX) + PREFIX.length(), s.lastIndexOf(SUBFIX));
                        context.append(resolverExpression(spel, proceedingJoinPoint));
                    } else {
                        // 不需要解析
                        context.append(s);
                    }
                }

            } else {
                context.append(contextEL);
            }
            return context;
        } catch (Exception e) {
            log.error("表达式解析错误, 请检查@Log注解");
            return null;
        }
    }


    /**
     * 解析表达式(可嵌套两层)
     *
     * @param expression          举例: #{user.username}  #{map.key}  #{user.phone.number}
     * @param proceedingJoinPoint
     * @return
     */
    private String resolverExpression(String expression, ProceedingJoinPoint proceedingJoinPoint) throws NoSuchFieldException, IllegalAccessException {
        String first = null;
        String second = null;
        String third = null;
        if (expression.contains(".")) {
            List<String> list = Arrays.asList(expression.split("\\."));
            if (list.size() > 3) throw new RuntimeException("不支持三个变量以上的表达式: " + expression);
            for (int i = 0; i < list.size(); i++) {
                if (0 == i) first = list.get(i);
                if (1 == i) second = list.get(i);
                if (2 == i) third = list.get(i);
            }
        } else {
            first = expression;
        }

        //获取参数值
        Object[] args = proceedingJoinPoint.getArgs();
        //获取运行时参数的名称
        Method method = ((MethodSignature) proceedingJoinPoint.getSignature()).getMethod();
        //获取参数值类型
        Class<?>[] parameterTypes = method.getParameterTypes();
        //获取参数值的数据
        String[] parameterNames = new DefaultParameterNameDiscoverer().getParameterNames(method);
        for (int i = 0; i < parameterNames.length; i++) {
            Class<?> parameterType = parameterTypes[i];
            String parameterName = parameterNames[i];
            Object parameterValue = args[i];

            if (first.equals(parameterName)) {
                if (null == second) {
                    return (String) parameterValue;
                }
                if (null != second) {
                    // map.name      user.username
                    if (parameterValue instanceof Map<?, ?>) {
                        return (String) ((Map) parameterValue).get(second);
                    } else {
                        return (String) getFieldValue(parameterValue, second + (null != third ? "." + third : ""));
                    }
                }
            }
        }
        return null;
    }


    /**
     * 通过反射取对象指定字段(属性)的值
     *
     * @param target    目标对象
     * @param fieldName 字段的名字
     * @return 字段的值
     */
    private Object getFieldValue(Object target, String fieldName) throws NoSuchFieldException, IllegalAccessException {
        Class<?> clazz = target.getClass();
        String[] fs = fieldName.split("\\.");

        try {
            for (int i = 0; i < fs.length - 1; i++) {
                Field f = clazz.getDeclaredField(fs[i]);
                f.setAccessible(true);
                target = f.get(target);
                 if (null == target) {
                    // 嵌套内容中为null的返回null, 防止报错
                    return null;
                }
                clazz = target.getClass();
            }

            Field f = clazz.getDeclaredField(fs[fs.length - 1]);
            f.setAccessible(true);
            return f.get(target);
        } catch (Exception e) {
            throw e;
        }
    }
}
  • 3
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值