SpringBoot-AOP
使用AOP统一处理请求日志
1.AOP的概念
AOP:AOP是一种编程范式,与语言无关,是一种程序设计思想
面向切面(AOP) Aspect Oriented Programming
面向对象(OOP) Object Oriented Programming
面向过程(POP) Procedure Oriented Programming
面向过程到面向对象:
功能:下雨了,我打开了雨伞
面向过程:假如下雨了,我打开了雨伞
面向对象:天气-->下雨;我-->打伞
即:换个角度看世界,换个姿势处理问题
面向对象:关注的是将需求功能垂直划分为不同的并且相对独立的,会封装成良好的类并且让他们有属于自己的行为。
面向切面:利用横切的技术,将面向对象构建的庞大的类的体系进行水平的切割,并且将其中会影响到多个类的公共行为封装成一个可重用的模块,该模块就成为切面
AOP的思想:将通用的逻辑从业务逻辑中分离出来
2.实现AOP
网络请求和数据库操作请求:
使用AOP思想:
3.实现使用AOP记录每一个http请求
需求:授权访问(必须先登录才能访问)
第一步:添加依赖:
org.springframework.boot
spring-boot-starter-aop
pom.xml:
4.0.0
com.hcx
girl
0.0.1-SNAPSHOT
jar
girl
Demo project for Spring Boot
org.springframework.boot
spring-boot-starter-parent
1.5.6.RELEASE
UTF-8
UTF-8
1.8
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-starter-thymeleaf
org.springframework.boot
spring-boot-starter-data-jpa
mysql
mysql-connector-java
org.springframework.boot
spring-boot-starter-aop
org.springframework.boot
spring-boot-maven-plugin
第二步:编写切面类:
@Aspect
@Component
public class HttpAspect {
//在http请求到方法之前记录
/**
* @Before注解:在方法执行之前执行
* com.hcx包下的girlcontroller里面的girlList方法,不管是什么参数都会被拦截
* 所有方法都拦截:execution(public * com.hcx.controller.GirlController.*(..))
*/
@Before("execution(public * com.hcx.controller.GirlController.girlList(..))")
public void log(){
System.out.println("被拦截了");
}
@After("execution(public * com.hcx.controller.GirlController.girlList(..))")
public void doAfter(){
System.out.println("我是方法执行之后被拦截");
}
}
第三步:拦截controller中的方法:
@RestController
public class GirlController {
@Autowired
private GirlRepository girlRepository;
@Autowired
private GirlService girlService;
/**
* 查询所有女生
* @return
*/
@GetMapping(value = "/girls")
public List girlList(){
System.out.println("我是girlList方法");
return girlRepository.findAll();
}
}
运行结果:
注意:以上代码可以看出有重复,在切面类中优化:
HttpAspect:
@Aspect
@Component
public class HttpAspect {
private final static Logger logger = LoggerFactory.getLogger(HttpAspect.class); //该类是org.slf4j的
//在http请求到方法之前记录
/**
* @Before注解:在方法执行之前执行
* com.hcx包下的girlcontroller里面的girlList方法,不管是什么参数都会被拦截
* 所有方法都拦截:execution(public * com.hcx.controller.GirlController.*(..))
*/
/*@Before("execution(public * com.hcx.controller.GirlController.girlList(..))")
public void log(){
System.out.println("被拦截了");
}*/
/**
* 公用的方法,使用@Pointcut注解
*/
@Pointcut("execution(public * com.hcx.controller.GirlController.girlList(..))")
public void log(){
}
@Before("log()")
public void doBefore(){
// System.out.println("我是方法执行之前被拦截");
logger.info("前日志信息"); //打印info、error等日志
}
@After("log()")
public void doAfter(){
// System.out.println("我是方法执行之后被拦截");
logger.info("后日志信息");
}
}
GirlController:
@RestController
public class GirlController {
/**
* getLogger方法中的参数与类名对应
*/
private final static Logger logger = LoggerFactory.getLogger(GirlController.class);
@Autowired
private GirlRepository girlRepository;
@Autowired
private GirlService girlService;
/**
* 查询所有女生
* @return
*/
@GetMapping(value = "/girls")
public List girlList(){
// System.out.println("我是girlList方法");
logger.info("我是girlList方法");
return girlRepository.findAll();
}
}
记录http请求:
HttpAspect:
@Aspect
@Component
public class HttpAspect {
private final static Logger logger = LoggerFactory.getLogger(HttpAspect.class); //该类是org.slf4j的
/**
* 公用的方法,使用@Pointcut注解
*/
@Pointcut("execution(public * com.hcx.controller.GirlController.girlList(..))")
public void log(){
}
@Before("log()")
public void doBefore(JoinPoint joinPoint){
/**
* 请求路径:url
* 请求方式:method
* 客户端ip:ip
* 请求的是哪个类方法:类方法
* 方法的参数
*/
ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();//注意:选择的HttpServletRequest选的是javax.servlet.http的
//url
logger.info("url={}",request.getRequestURL());
//method
logger.info("method={}",request.getMethod());
//ip
logger.info("ip={}",request.getRemoteAddr());
//getDeclaringTypeName():获取类名,getName:获取类方法
logger.info("class_method={}",joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
//方法的参数
logger.info("args={}",joinPoint.getArgs());
}
@After("log()")
public void doAfter(){
// System.out.println("我是方法执行之后被拦截");
logger.info("后日志信息");
}
/**获取返回的内容:
* {
"id": 2,
"cupSize": "B",
"age": 19
}
*/
@AfterReturning(returning = "object",pointcut = "log()")
public void doAfterReturning(Object object){
logger.info("response={}",object.toString());
}
}
GirlController:
@RestController
public class GirlController {
/**
* getLogger方法中的参数与类名对应
*/
private final static Logger logger = LoggerFactory.getLogger(GirlController.class);
@Autowired
private GirlRepository girlRepository;
@Autowired
private GirlService girlService;
/**
* 查询所有女生
* @return
*/
@GetMapping(value = "/girls")
public List girlList(){
// System.out.println("我是girlList方法");
logger.info("我是girlList方法");
return girlRepository.findAll();
}
}
Girl:
@Entity //该注解表示该类在数据库中有对应的表 不用创建该表
public class Girl {
@Id
@GeneratedValue
private Integer id;
private String cupSize;
/**
* 给年龄加上限制:年龄必须大于18岁
* value:值
* message:提示信息
*/
@Min(value =18,message = "年龄必须大于18岁")
private Integer age;
public Girl() {
}
@Override
public String toString() {
return "Girl{" +
"id=" + id +
", cupSize='" + cupSize + '\'' +
", age=" + age +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getCupSize() {
return cupSize;
}
public void setCupSize(String cupSize) {
this.cupSize = cupSize;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}