这几天工作的时候遇到这样一个需求,需要以用户的维度对列表展示的内容实现可自定义配置列功能,并且后端返回的值没有冗余值。由于系统之前并没有此设计,需要短期实现又不想大动代码,功能基本实现;但是在后台返回列表数据没有冗余的时候发现基本每个返回列表的接口都需要有所修改,而且都是一些重复的修改,所以就想到通过AOP使前置增强后置增强,在通过注解的方式告知哪些方法需要增强,并通过注解的方式传参;因此此处简单记录下实现过程以及具体的代码逻辑;
步骤1:创建Spring boot项目
此步骤此处就不在赘述;
步骤2:
2.1由于此处使用了Springboot的aop功能,所以maven需要引入AOP的依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
2.2 定义自定义注解
@Target(ElementType.METHOD) //定义是用在方法上 @Retention(RetentionPolicy.RUNTIME) // 定义是在运行时生效 public @interface ZlTest { String param() default ""; //定义参数,默认为空 }
步骤3:定义切面
3.1先上代码
package com.zl.demo.aspect; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.zl.concurrency.annoations.ZlTest; import com.zl.demo.unit.SpelParser; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.core.LocalVariableTableParameterNameDiscoverer; import org.springframework.stereotype.Component; import java.lang.reflect.Method; /** * 定义一个切面,用于统计指定注解的方法调用时间 * * @author zl * @ProjectName: MapDemo * @create 2018-12-13 10:08 * @Version: 1.0 * <p>Copyright: Copyright (zl) 2018</p> **/ @Component @Aspect @Slf4j public class ZlAspect { @Around("serviceStatistics(zlTest)") public Object doAround(ProceedingJoinPoint joinPoint, ZlTest zlTest) throws Throwable { System.out.println("beginning----"); /** * 获取方法参数值 */ String key = getKey(zlTest.param(), joinPoint); log.info("参数是:{}",key); /** * 运行doSth(),执行方法的具体业务,并获取返回值,用一个Object类型来接收 */ Object object = joinPoint.proceed(); /** * 该方法的后置增强,可以修改返回值 */ object = 10; return object; } private String getKey(String param, ProceedingJoinPoint joinPoint) { Method method = ((MethodSignature)joinPoint.getSignature()).getMethod(); //获取方法的形参 String [] parameterNames = new LocalVariableTableParameterNameDiscoverer().getParameterNames(method); return SpelParser.getKey(param, "", parameterNames, joinPoint.getArgs()); } }
3.2 此处使用的是环绕增强
@Around注解,后面加上具体需要扫描的方法,这里是扫描我们自定义注解的方法
doAround方法的两个参数:ProceedingJoinPoint:是指具体的切面点,通过该对象可以获取到切面点的所有的方法,方法的属性,方法的形参;ZlTest指的就是我们自定的注解,通过这里可以获取到注解的参数值信息;
3.3 getKey()方法
getkey方法是我们自定义的一个方法,主要是通过EL表达式获取到方法的形参,此处不再赘述,可以查看 https://www.aliyun.com/jiaocheng/529697.html一文,此处只是根据注解的参数和方法的参数信息获取到方法的指定参数的值;
步骤4:定义我们需要注解的方法
package com.zl.demo.controller;
@Slf4j @Controller @RequestMapping("threadLocal") public class ThreadLocalController { @Autowired private Validator validator; @RequestMapping("test") @ResponseBody @ZlTest(param = "#id") public long test(String id, String name){ return RequestHolder.getId(); } }
这里通过#id占位,获取方法的id参数的值
步骤5:执行结果如下
这里通过Object获取到方法的返回值,可以修改该返回值
步骤6:demo代码git地址
git@github.com:zlAdmin/didactic-enigma.git
注意:项目中有本人写的其他测试demo,请注意该demo的路径;