AOP概述
如图中显示,当我们请求的操作继续往下走的时候都是相类似的, 那这个时候我们就可以把具体的业务操作代码提取出来作为公共的操作,这样就有了面向切面编程AOP
下面来举例子说明 如何AOP统一处理请求日志
pom.xml 文件中引入AOP依赖
<!-- 引入AOP依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
创建一个AOP统一拦截处理类
HttpAspect 类
package com.zhang.aspect;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
/**
* AOP统一拦截处理类
* @author Administrator
*
*/
@Aspect
@Component
public class HttpAspect {
/**
* 这个注解表示在请求GirlController类中的girlLsit()方法前拦截
* 方法中的的(..)表示传任何的参数都可以不限制,都会拦截。不会因为你传参的问题而不拦截
*
* 如果我们想每个方法都要拦截的话把方法改变成 * (星号),这样springBoot就会帮你把全部的方法都配置要拦截处理
*/
@Before("execution(public * com.zhang.contorller.GirlController.girlLsit(..))")
public void log(){
System.out.println("111111111111111111");
}
}
Postman 测试一下调用girlList()方法会不会被拦截,结果拦截成功
如果我们想每个方法都要拦截的话把方法改变成 * (星号),这样springBoot就会帮你把全部的方法都配置要拦截处理,修改好之后重新启动项目在测试一下是否拦截成功
Postman 测试一下调用查询一个女生方法,测试拦截成功
为了在确认是否是在请求之前拦截的,在girlLsit()这方法中也打印一下。我们可以通过打印的前面再次确认拦截是在请求前还是在请求后实现
测试看到打印的结果,确实是在请求前拦截的
有拦截前就有拦截后,在HttpAspect类中加入拦截后的方法
/**
* 这个注解表示在请求GirlController类中的girlLsit()方法后拦截
*/
@After("execution(public * com.zhang.contorller.GirlController.*(..))")
public void doAfter(){
System.out.println("22222222222222");
}
Postman 测试一下调用查询一个女生集合方法,测试拦截成功
高类聚低耦合,避免老是写重复的代码,我们又把抽离出一个公共的拦截方法,测试效果和之前一样就说明抽离成功
HttpAspect 类
package com.zhang.aspect;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
/**
* AOP统一拦截处理类
* @author Administrator
*
*/
@Aspect
@Component
public class HttpAspect {
/**
* 定义一个公共的拦截方法 让别的方法调用,高类聚低耦合
*/
@Pointcut("execution(public * com.zhang.contorller.GirlController.*(..))")
public void log(){
}
/**
* 这个注解表示在请求GirlController类中的girlLsit()方法前拦截
* 方法中的的(..)表示传任何的参数都可以不限制,都会拦截。不会因为你传参的问题而不拦截
*
* 如果我们想每个方法都要拦截的话把方法改变成 * (星号),这样springBoot就会帮你把全部的方法都配置要拦截处理
*/
@Before("log()")
public void doBefore(){
System.out.println("111111111111111111");
}
/**
* 这个注解表示在请求GirlController类中的girlLsit()方法后拦截
*/
@After("log()")
public void doAfter(){
System.out.println("22222222222222");
}
}
测试结果,抽离成功
下面在转换成用日志的形式打印出来,
HttpAspect 类 logger一定是选择spring自带的 import org.slf4j.Logger;
package com.zhang.aspect;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.springframework.stereotype.Component;
/**
* AOP统一拦截处理类
* @author Administrator
*
*/
@Aspect
@Component
public class HttpAspect {
private final static Logger logger= org.slf4j.LoggerFactory.getLogger(HttpAspect.class);
/**
* 定义一个公共的拦截方法 让别的方法调用,高类聚低耦合
*/
@Pointcut("execution(public * com.zhang.contorller.GirlController.*(..))")
public void log(){
}
/**
* 这个注解表示在请求GirlController类中的girlLsit()方法前拦截
* 方法中的的(..)表示传任何的参数都可以不限制,都会拦截。不会因为你传参的问题而不拦截
*
* 如果我们想每个方法都要拦截的话把方法改变成 * (星号),这样springBoot就会帮你把全部的方法都配置要拦截处理
*/
@Before("log()")
public void doBefore(){
logger.info("1111111111111111");
}
/**
* 这个注解表示在请求GirlController类中的girlLsit()方法后拦截
*/
@After("log()")
public void doAfter(){
logger.info("22222222222222");
}
}
重新启动项目测试一下, 我们要输出的内容全部都以日志的形式打印出来,同时建议所以的拦截都是以日志的形式输出为更佳的方案
GirlController 类也添加上日志对象
package com.zhang.contorller;
import java.util.List;
import javax.validation.Valid;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.zhang.aspect.HttpAspect;
import com.zhang.domain.Girl;
import com.zhang.repository.GirlRepository;
import com.zhang.service.GirlService;
@RestController
public class GirlController {
@Autowired
private GirlRepository girlRepository;
@Autowired
private GirlService girlService;
private final static Logger logger= org.slf4j.LoggerFactory.getLogger(HttpAspect.class);
/**
* 查询girl对象集合
* @return
*/
@GetMapping(value="/girls")
public List<Girl> girlLsit(){
logger.info("girlLsit");
return girlRepository.findAll();
}
/**
* 新增一个女孩
*/
@PostMapping(value="/girlsAdd")
public Girl girlAdd(@Valid Girl girl , BindingResult bindingResult){
if(bindingResult.hasErrors()){
System.out.println(bindingResult.getFieldError().getDefaultMessage());
return null;
}
girl.setCupSize(girl.getCupSize());
girl.setAge(girl.getAge());
return girlRepository.save(girl);
}
/**
* 查询一个女生
*/
@GetMapping(value = "/girls/{id}")
public Girl girlFindOne(@PathVariable("id") Integer id){
return girlRepository.findOne(id);
}
/**
* 更新女生数据
*/
@PutMapping(value="/girls/{id}")
public Girl girlUpdate(@PathVariable("id") Integer id ,
@RequestParam("cupSize") String cupSize,
@RequestParam("age") Integer age){
Girl girl = new Girl();
girl.setEid(id);
girl.setCupSize(cupSize);
girl.setAge(age);
return girlRepository.save(girl);
}
/**
* 删除女生数据
*/
@DeleteMapping(value="/girls/{id}")
public void girlDelete(@PathVariable("id") Integer id){
girlRepository.delete(id);
}
/**
* 通过年龄查询女生列表
*/
@GetMapping(value="/girls/age/{age}")
public List<Girl> girlListByAge(@PathVariable("age") Integer age ){
return girlRepository.findByAge(age);
}
/**
* 事务管理统一成功或者失败回滚
*/
@PostMapping(value="/girls/two")
public void girlTwo(){
girlService.insertTwo();
}
}
重新启动项目测试一下, 我们要输出的内容全部都以日志的形式打印出来
接下来开始举例记录HTTP请求
HttpAspect 类
package com.zhang.aspect;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
/**
* AOP统一拦截处理类
* @author Administrator
*
*/
@Aspect
@Component
public class HttpAspect {
private final static Logger logger= org.slf4j.LoggerFactory.getLogger(HttpAspect.class);
/**
* 定义一个公共的拦截方法 让别的方法调用,高类聚低耦合
*/
@Pointcut("execution(public * com.zhang.contorller.GirlController.*(..))")
public void log(){
}
/**
* 这个注解表示在请求GirlController类中的girlLsit()方法前拦截
* 方法中的的(..)表示传任何的参数都可以不限制,都会拦截。不会因为你传参的问题而不拦截
*
* 如果我们想每个方法都要拦截的话把方法改变成 * (星号),这样springBoot就会帮你把全部的方法都配置要拦截处理
*/
@Before("log()")
public void doBefore(JoinPoint joinpoint){
ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
//url
logger.info("url={}",request.getRequestURL());
//method
logger.info("method={}",request.getMethod());
//ip
logger.info("ip={}",request.getRemoteAddr());
//类方法
logger.info("class_mothod={}",joinpoint.getSignature().getDeclaringTypeName()+"."+joinpoint.getSignature().getName());
//参数
logger.info("args={}",joinpoint.getArgs());
}
/**
* 这个注解表示在请求GirlController类中的girlLsit()方法后拦截
*/
@After("log()")
public void doAfter(){
logger.info("22222222222222");
}
}
获取到HTTP请求中属性以及属性对应的值
获取到HTTP请求返回的内容
HttpAspect 类 新增方法
/**
* 获取到HTTP请求返回的内容
*/
@AfterReturning(returning="object",pointcut="log()")
public void doAfterReturning( Object object){
logger.info("response={}",object.toString());
}
girl 类中重写tostring 方法
@Override
public String toString() {
return "Girl [eid=" + eid + ", cupSize=" + cupSize + ", age=" + age + "]";
}
测试结果,获取到HTTP请求中属性以及属性对应的值 与 获取到HTTP请求返回的内容