spring自定义注解

  1. spring自定义注解
    1. 简单查询
    2. 添加日志注释&修改参数和返回值

spring自定义注解

参考: https://blog.csdn.net/qq_37435078/article/details/90523309

简单查询

Springboot为例子, 做一个简单的MVC查询

controller层

package com.example.demo1.controller;

import com.example.demo1.annotation.Log;
import com.example.demo1.entity.User;
import com.example.demo1.sevice.UserService;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @RequestMapping("user/{id}")
    public User findUser(@PathVariable("id") Integer id) {
        return userService.findUserById(id);
    }
}

Dao层:

package com.example.demo1.dao;

import com.example.demo1.entity.User;
import org.springframework.stereotype.Component;

@Component
public class UserDao {

    public User findUserById(Integer id) {
        System.out.println("查询id为[" + id + "]的用户");
        if(id > 10) {
            return null;
        }
        User user = new User(id, "user-" + id);
        System.out.println("返回的用户为[" + user.toString() + "]");
        return user;
    }

}

实体类:

package com.example.demo1.entity;

public class User {
    private Integer id;
    private String name;

    public User() {
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }

    public User(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Service层

package com.example.demo1.sevice;

import com.example.demo1.dao.UserDao;
import com.example.demo1.entity.User;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    private final UserDao userDao;

    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }

    public User findUserById(Integer id) {
        return userDao.findUserById(id);
    }
}

直接访问 localhost:8080/user/6

得到

{
  "id": 6,
  "name": "user-6"
}

添加日志注释&修改参数和返回值

新建Log注解

package com.example.demo1.annotation;

import java.lang.annotation.*;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Log {
    String value() default "";
}

这里注解类上的三个注解称为元注解,其分别代表的含义如下:

@Documented:注解信息会被添加到Java文档中
@Retention:注解的生命周期,表示注解会被保留到什么阶段,可以选择编译阶段、类加载阶段,或运行阶段
@Target:注解作用的位置,ElementType.METHOD表示该注解仅能作用于方法上

在对外接口上添加Log注解

package com.example.demo1.controller;

import com.example.demo1.annotation.Log;
import com.example.demo1.entity.User;
import com.example.demo1.sevice.UserService;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @Log("日志测试")
    @RequestMapping("user/{id}")
    public User findUser(@PathVariable("id") Integer id) {
        return userService.findUserById(id);
    }
}

利用Spring AOP的切面类来处理具体的逻辑, 新建LogAspect切面类

处理参数:

  1. 传入的id传给后端 id -1
  2. 返回给前端的VO.id + 1
package com.example.demo1.annotation;

import com.example.demo1.entity.User;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import javax.jws.soap.SOAPBinding;

@Component
@Aspect
public class LogAspect {

    @Pointcut("@annotation(com.example.demo1.annotation.Log)")
    private void pointcut(){}

    @Around("pointcut() && @annotation(log)")
    public Object advice(ProceedingJoinPoint joinPoint, Log log) {
        System.out.println("["
                + joinPoint.getSignature().getDeclaringType().getSimpleName()
                + "][" + joinPoint.getSignature().getName()
                + "]-日志内容-[" + log.value() + "]");

        Object result = null;

        Object[] args = joinPoint.getArgs();
        for (int i = 0; i < args.length; i++) {
            if(args[i] instanceof Integer) {
                args[i] = (Integer)args[i] - 1;
                break;
            }
        }

        try{
            result = joinPoint.proceed(args);
        }catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        if(result instanceof User) {
            User user = (User) result;
            user.setId(user.getId() + 1);
            return user;
        }
        return result;
    }
}

其中@Pointcut声明了切点(这里的切点是我们自定义的注解类)

@Before("pointcut() && @annotation(logger)")
    public void advice(KthLog logger) {
        System.out.println("--- Kth日志的内容为[" + logger.value() + "] ---");
    }

如果用@Before注解,则进入实际方法前,执行adivice方法

@Around注解:

@Around的作用

既可以在目标方法之前织入增强动作,也可以在执行目标方法之后织入增强动作;
可以决定目标方法在什么时候执行,如何执行,甚至可以完全阻止目标目标方法的执行;
可以改变执行目标方法的参数值,也可以改变执行目标方法之后的返回值; 当需要改变目标方法的返回值时,只能使用Around方法;
虽然Around功能强大,但通常需要在线程安全的环境下使用。因此,如果使用普通的Before、AfterReturing增强方法就可以解决的事情,就没有必要使用Around增强处理了。
————————————————
版权声明:本文为CSDN博主「咚咚大帝」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_41981107/article/details/85260765

joinPoint.getArgs()用来获取加注解的方法的入参,获得入参之后,进行处理

result = joinPoint.proceed(args);传入修改后的args, 通过调用proceed()方法,执行了实际的操作,并获取到了返回值

再对返回的result进行处理,


测试: http://localhost:8080/user/6

打印台为: 可以看到 id -1

[UserController][findUser]-日志内容-[日志测试]
查询id为[5]的用户
返回的用户为[User{id=5, name='user-5'}]

返回给前台的页面为: 可以看到id不变, user - 1

{"id":6,"name":"user-5"}

这样就做出了对业务逻辑的增强


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 mym_74@163.com