前言:AOP:将通用逻辑从业务逻辑中分离出来
一、在pom.xml中添加AOP依赖
<!--添加aop依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
二、往常的做法是在启动类上添加注解,但是aop不需要
三、建立我们的处理文件,首先建一个aspect包,再在包下面建议我们的类,
然后在类上面我们添加@Aspect注解和@Component注解如下:
/**
* 系统日志,处理切面类
*/
@Aspect
@Component
public class HttpAspect {
}
四、我们现在要做的是在做一些增删改查前要验证是否登录了,下面我们就在HttpAspect下面进行验证和拦截。
@Aspect
@Component
public class HttpAspect {
@Before("execution(public * com.imooc.controller.GirlController.girlList(..))")
public void log(){
System.out.println(11111);
}
}
这里我们先验证一下girlList方法,格式就如上面的代码一样,下面我们运行程序进行测试!
这里我们还是用postman进行接口测试,看一下控制台:
打印出来了我们之前在HttpAspect中打印的数字!
若想把GirlController中的所有方法都添加此拦截,只需按照如下操作即可:
@Before("execution(public * com.imooc.controller.GirlController.*(..))")
其中*号代表扫描所有的方法。
下面我们再测试一下@After方法
@Aspect
@Component
public class HttpAspect {
@Before("execution(public * com.imooc.controller.GirlController.*(..))")
public void log(){
System.out.println(11111);
}
@After("execution(public * com.imooc.controller.GirlController.*(..))")
public void doAfter(){
System.out.println(2222);
}
然后运行一下,看一下控制台的代码,先是执行了@Before方法,然后执行了GirlController方法,最后执行了@After方法。
现在我们发现我们在@Before和@After的注解中写了许多重复的代码,这样是非常不好的,所以下面我们用另外一种方法书写:
@Pointcut("execution(public * com.imooc.controller.GirlController.*(..))")
public void log(){
}
@Before("log()")
public void doBefore(){
System.out.println(1111);
}
@After("log()")
public void doAfter(){
System.out.println(2222);
}
这里我们使用了@Pointcut,定义了一个公用的方法,然后在下面的注解中调用这个方法。运行代码验证也是成功的。
现在我们不再使用system进行打印,改用log进行打印,下面看一下操作流程:
private final static Logger logger= LoggerFactory.getLogger(HttpAspect.class);
这里我们导入的是slf4j的日志,然后在下面我们直接调用即可,例如:
@Before("log()") public void doBefore(){ logger.info("111111111111"); } @After("log()") public void doAfter(){ logger.info("22222222222"); }
经过测试成功,这里不再赘述测试过程!
测试成功,那我们就要正式使用它了!
首先编写以下代码:
@Before("log()")
public void doBefore(JoinPoint joinPoint){
ServletRequestAttributes attributes= (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request= attributes.getRequest();
//请求url
logger.info("url={}",request.getRequestURL());
//请求方式:GET POST...
logger.info("method={}",request.getMethod());
//客户端ip
logger.info("ip={}",request.getRemoteAddr());
//请求的那个类的方法
String className=joinPoint.getTarget().getClass().getName();
String methodName=joinPoint.getSignature().getName();
logger.info("class-method={}",className+"."+methodName+"()");
//请求参数
logger.info("args={}",joinPoint.getArgs());
}
即我们在程序启动前获取请求的url、请求的方式、请求的方法名等,并且将他们打印出来,下面运行一下测试结果:
这里还是使用postman测试,然后查看控制台的结果图如下:
我们已经打印出来了我们上面所需要的信息。参数没有的原因是因为我们在这个get方法中没有传参!下面我们换个带参数的测试以下:
这里我们带着参数id=7进行查询,查看控制台结果:
我们可以看到参数也被打印出来了!
那么我们现在思考一个功能,如何把查询出来的结果返回呢?下面我们进行编码:
@AfterReturning(returning ="object",pointcut = "log()")
public void doAfterReturning(Object object){
logger.info("response={}",object);
}
下面我们再运行程序进行测试:
查看控制台结果如下:
返回的结果已经被打印出来了,如果我们想打印具体的内容可以这样操作:
在Girl实体类中添加toString方法如下:
@Override
public String toString() {
return "Girl{" +
"id=" + id +
", cupSize='" + cupSize + '\'' +
", age=" + age +
'}';
}
然后在HttpAspect类中编码如下:
@AfterReturning(returning ="object",pointcut = "log()")
public void doAfterReturning(Object object){
logger.info("response={}",object.toString());
}
这样就可以打印出来具体内容如下:
response=Girl{id=7, cupSize='A', age=18}
关于AOP 的内容的学习就先到这里!!