SpringAOP面向切面编程。基于注解 的Around通知。在Controller实现切面日志功能,修改入参,修改返回值

SpringAOP面向切面编程。基于注解 的Around通知。在Controller实现切面日志功能,修改入参,修改返回值

基于注解 的Around通知。
在Controller实现切面日志功能,修改入参,修改返回值

基于注解 的Around通知

自定义注解、在需要切面的方法上添加注解,在切面类获取 方法信息

maven依赖

	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-aop</artifactId>
	</dependency>

一、代码如下

1.自定义日志注解

/**
 * 自定义注解实现 切面日志功能
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Loggable {
    boolean isSave() default true;


    String ModelName() default "";

}

2.切面类

@Aspect
@Component
@Slf4j
public class LogAspect {
/**
     * 定义环绕增强.
     *
     * 功能1:记录 方法的 修饰符,名称、参数名称、参数值、返回值。方法的类名
     * 功能2:修改方法的入参,传入方法执行,最后修改方法的返回值
     */
//    @Around("execution(* com.example.demo.controller.*.*(..))")
    @Around("@annotation(Loggable)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        //连接点(JoinPoint)的方法签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();

        String clazzName = signature.getDeclaringType().getSimpleName();//类名
        String className = signature.getDeclaringTypeName();//类名(全限定类名)
        String methodName = signature.getName();//方法名
        String methodModify = Modifier.toString(signature.getModifiers());//方法的修饰符(modifier)

        log.info("切面:方法基本信息:"+className + " ----- " + clazzName + "  " + methodModify + "    " + methodName);


        //注解处理:获取注解值 来控制切面逻辑,比如 isSave决定是否保存,
        Method method = signature.getMethod();
        Annotation[] annotations = method.getAnnotations();
        for (Annotation annotation : annotations) {
            if (annotation instanceof Loggable) {
                Loggable myAnnotation = (Loggable) annotation;
                 boolean isSave= myAnnotation.isSave();
                 String modelName= myAnnotation.ModelName();
                 log.info("切面:日志注解的值:isSave ="+isSave+"    modelName="+modelName);
                break;
            }
        }

        //-------------入参处理
        Object[] args = joinPoint.getArgs();//方法参数值
        String[] parameterNames = signature.getParameterNames();// 方法参数名称
        //入参:遍历参数值和名称
        JSONObject param = new JSONObject(true);
        for (int i = 0; i < args.length; i++) {
            Object argValue = args[i];
            String argName = parameterNames[i];
            param.put(argName, argValue);
        }
        log.info("切面:参数 :"+param.toJSONString());

        //修改入参
        for (int i = 0; i < args.length; i++) {
            Object arg = args[i];
            //String类型或者Integer等包装类,需要对入参数组进行重新赋值
            if (arg instanceof String) {
                args[i] = arg + "aop——update";//修改入参,对 String类型的参数 增加"aop——update"
            } else if (arg instanceof Integer) {
                args[i] = (int) arg + 4;//修改入参,对 int类型的参数 增加4
            } else if (arg instanceof Long) {
                args[i] = (long) arg + 8;//修改入参,对 long类型的参数 增加8
            } else if (arg instanceof Float) {
                args[i] = (float) arg + 8;//修改入参,对 float类型的参数 增加8
            } else if (arg instanceof Double) {
                args[i] = (double) arg + 8;//修改入参,对 double类型的参数 增加8
            }
            //对象类型的入参:直接修改属性
            if (arg instanceof User) {
                User params = (User) arg;
                params.setId(params.getId() * params.getId());//修改入参,user的id
            }
        }

        //传入修改后的入参,执行方法
        Object response = joinPoint.proceed(args);

        //修改返回值
        if (response instanceof Integer) {
            response = (int) response + 100;
        }
        return response;//方法的返回值是around修改后的返回值,而不是原来方法的返回值
    }

}

3.controller


@RestController
@Slf4j
public class ExpertController {

    @Resource
    MyService myService;

    @GetMapping("/aop/annotation/get")
    @Loggable(isSave = true,ModelName = "os")
    public  Integer aopAnnotationGet(
                      @RequestParam("strings")String strings,
                      @RequestParam("integers")Integer integers,
                      @RequestParam("longs")Long longs,
                      @RequestParam("floats")Float floats,
                      @RequestParam("doubles")Double doubles){
        log.info("GET,多个包装类参数,当前方法使用  annotation 标记连接点");
        log.info("参数:strings="+strings+"  integers="+integers+"  longs="+ longs+"   floats="+floats+"  doubles="+doubles);
        Integer result = myService.doSomethingAnnation(strings,integers,longs,floats,doubles);
        log.info("返回值: " + result);
        return  result;
    }

    @PostMapping("/aop/annotation/post")
    @Loggable(isSave = false,ModelName = "manage")
    public  Integer aopAnnotationPost(@RequestBody User user){
        log.info("POST,1个对象参数,当前方法使用  annotation 标记连接点");
        log.info("参数:"+ JSON.toJSONString(user));
        Integer result = myService.doSomethingAnnation(user.getId(), user.getName(), 0L);
        log.info("返回值: " + result);
        return  result;
    }
 }

4.service

@Service
@Slf4j
public class MyService {

    public Integer doSomethingAnnation(String strings,
                                       Integer integers,
                                       Long longs,
                                       Float floats,
                                       Double doubles) {
        return Math.toIntExact(integers + longs);
    }


    public Integer doSomethingAnnation(Integer a,String b,Long c) {
        return Math.toIntExact(a + c);
    }

    public Integer doSomething(Integer a,String b,Long c) {
        return Math.toIntExact(a + c);
    }
}

测试

1.测试GET方法

执行接口请求

http://localhost:6565/aop/annotation/get?strings=example&integers=10&longs=1000&floats=3.14&doubles=2.71828

在这里插入图片描述

在这里插入图片描述

分析日志:

————进入切面
第一行:切面 获取了 全限定类名, 类名,方法的修饰符,方法名称
第二行:切面 获取了 自定义的日志注解的值。
设置参数值来控制切面的逻辑,比如 isSave决定是否保存日志。
第三行:切面获取了 参数名称和参数值(postman中我们设置的参数值)

————进入接口
第四行:接口打印信息
第五行:接口打印入参。对比第三行,明显不一样,因为【切面修改了入参】
我们定义的修改规则是 字符串加后缀,数字加自身类型的字节数
第六行:接口打印返回值1022。1022=14+1008

接口返回结果 :1122 ,对比第六行,多了100,因为【切面中修改了 返回值】
我们定义的修改规则是 如果是Integer类型的返回值,则再加100返回

测试结果

  1. 成功获取方法的基本信息(类名、方法名、入参)
  2. 成功获取了注解
  3. 成功修改了入参
  4. 成功修改了返回值

2.执行POST方法

执行接口请求

http://127.0.0.1:6565/aop/annotation/post

{ “id”: “4”,
“name”: “ww”,
“status”: true
}
在这里插入图片描述

在这里插入图片描述

分析日志:

————进入切面
第一行:切面 获取了 全限定类名, 类名,方法的修饰符,方法名称
第二行:切面 获取了 自定义的日志注解的值。
设置参数值来控制切面的逻辑,比如 isSave决定是否保存日志。
第三行:切面获取了 参数名称和参数值(postman中我们设置的参数值)

————进入接口
第四行:接口打印信息
第五行:接口打印入参。对比第三行,明显不一样,因为【切面修改了入参】
我们定义的修改规则是 id=id*id
第六行:接口打印返回值16。16=16+0

接口返回结果 :116 ,对比第六行,多了100,因为【切面中修改了 返回值】
我们定义的修改规则是 如果是Integer类型的返回值,则再加100返回

测试结果

  1. 成功获取方法的基本信息(类名、方法名、入参)
  2. 成功获取了注解
  3. 成功修改了入参
  4. 成功修改了返回值
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值