拦截注解修改注解属性

本文介绍了一个自定义注解和拦截器的实现,展示了如何在方法执行前后修改注解的属性值,并提供了两种策略:一种是永久修改,另一种是使用后恢复原值。通过Spring AOP实现,适用于ResponseExcel等场景。
摘要由CSDN通过智能技术生成

自定义注解

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

/**
 * Created by krun on 2017/9/18.
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Foo {
	String value();
}

自定义拦截器

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Date;
import java.util.Map;

/**
 * 监听注解,并修改注解属性
 *
 * @author author
 */
// @Slf4j
@Aspect
@Component
public class MyAspect {
	
	/**
	 * 获取注解参数当做方法入参
	 *
	 * @param joinPoint           切点方法
	 * @param annotationParameter 注解参数,要拦截的注解类型
	 * @return 方法执行的返回值
	 */
	@Around("@annotation(annotationParameter)")
	@SuppressWarnings("unchecked")
	public Object doAround(ProceedingJoinPoint joinPoint, Foo annotationParameter) {
		try {
			// 获取注解value属性的原值
			String beforeValue = annotationParameter.value();
			System.out.println("beforeValue = " + beforeValue);
			// 获取注解参数的调用处理器
			InvocationHandler handler = Proxy.getInvocationHandler(annotationParameter);
			// AnnotationInvocationHandler 实现 InvocationHandler,
			// 通过调用处理器获取AnnotationInvocationHandler的memberValues字段,该字段存储注解实例的所有属性键值对
			Field memberValuesField = handler.getClass().getDeclaredField("memberValues");
			memberValuesField.setAccessible(true);
			// 获取该实例的所有属性键值对
			Map memberValues = (Map) memberValuesField.get(handler);
			// 为注解实例的value属性赋新值
			memberValues.put("value", beforeValue + new Date().toString());
		} catch (Exception e) {
			System.out.println("赋值失败");
			throw new RuntimeException("赋值失败");
		}
		
		Object proceed;
		try {
			proceed = joinPoint.proceed();
		} catch (Throwable throwable) {
			throw new RuntimeException(throwable);
		}
		return proceed;
	}
}

在这里插入图片描述
使用实例

import com.itheima.spring.Foo;
import org.springframework.stereotype.Controller;
@Controller("clientController")
public class ClientController {

    @Foo(value = "2")
    public void test() {
    }
}

日志结果
在这里插入图片描述
修复拦截器bug
上述拦截器会将修改后的值永久保存给注解属性,再次访问该方法时,会在第一次修改完的基础上再次修改,多次使用将无限叠加,如果想每次使用完恢复原值,可以使用下面的拦截器

import com.pig4cloud.plugin.excel.annotation.ResponseExcel;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Map;

/**
 * 拦截ResponseExcel注解,并修改name属性
 *
 * @author zhaoliyan
 * @date 2021/9/2 08:55
 */
@Slf4j
@Aspect
@Component
public class ResponseExcelAnnotationAspect {

	/**
	 * 拦截ResponseExcel注解,并修改name属性
	 *
	 * @param annotationParameter ResponseExcel注解实例
	 */
	@Before("@annotation(annotationParameter)")
	public void doBefore(ResponseExcel annotationParameter) {
		try {
			// 获取ResponseExcel注解name属性的原值
			String beforeValue = annotationParameter.name();
			setName(annotationParameter, beforeValue + LocalDate.now().format(DateTimeFormatter.ofPattern("_yyyyMMdd")));
		} catch (Exception e) {
			log.error("ResponseExcel注解name属性赋新值失败");
			throw new RuntimeException("ResponseExcel注解name属性赋新值失败");
		}

	}

	/**
	 * 拦截ResponseExcel注解,并恢复name属性
	 *
	 * @param annotationParameter ResponseExcel注解实例
	 */
	@After("@annotation(annotationParameter)")
	public void doAfter(ResponseExcel annotationParameter) {
		try {
			// 获取ResponseExcel注解name属性修改后的值
			String afterValue = annotationParameter.name();
			setName(annotationParameter, afterValue.substring(0, afterValue.lastIndexOf("_")));
		} catch (Exception e) {
			log.error("ResponseExcel注解name属性恢复原值失败");
			throw new RuntimeException("ResponseExcel注解name属性恢复原值失败");
		}

	}

	/**
	 * 修改ResponseExcel注解name属性值
	 *
	 * @param annotationParameter ResponseExcel注解实例
	 * @param value               name属性新值
	 */
	@SuppressWarnings("unchecked")
	private void setName(ResponseExcel annotationParameter, String value) throws NoSuchFieldException, IllegalAccessException {
		// 获取注解参数的调用处理器
		InvocationHandler handler = Proxy.getInvocationHandler(annotationParameter);
		// AnnotationInvocationHandler 实现 InvocationHandler,
		// 通过调用处理器获取AnnotationInvocationHandler的memberValues字段,该字段存储注解实例的所有属性键值对
		Field memberValuesField = handler.getClass().getDeclaredField("memberValues");
		memberValuesField.setAccessible(true);
		// 获取该实例的所有属性键值对
		Map<String, Object> memberValues = (Map<String, Object>) memberValuesField.get(handler);
		// 为注解实例的name属性赋新值
		memberValues.put("name", value);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值