SpringBoot-AOP
使用AOP統(tǒng)一處理請求日志
1.AOP的概念
AOP:AOP是一種編程范式撼港,與語言無關(guān),是一種程序設(shè)計思想
面向切面(AOP) Aspect Oriented Programming
面向?qū)ο?OOP) Object Oriented Programming
面向過程(POP) Procedure Oriented Programming
面向過程到面向?qū)ο螅?/p>
功能:下雨了芦圾,我打開了雨傘
面向過程:假如下雨了蛾派,我打開了雨傘
面向?qū)ο螅禾鞖?->下雨;我-->打傘
即:換個角度看世界个少,換個姿勢處理問題
面向?qū)ο螅宏P(guān)注的是將需求功能垂直劃分為不同的并且相對獨立的洪乍,會封裝成良好的類并且讓他們有屬于自己的行為。
面向切面:利用橫切的技術(shù)夜焦,將面向?qū)ο髽?gòu)建的龐大的類的體系進行水平的切割壳澳,并且將其中會影響到多個類的公共行為封裝成一個可重用的模塊,該模塊就成為切面
AOP的思想:將通用的邏輯從業(yè)務(wù)邏輯中分離出來
2.實現(xiàn)AOP
網(wǎng)絡(luò)請求和數(shù)據(jù)庫操作請求:
1.jpg
使用AOP思想:
2.jpg
3.實現(xiàn)使用AOP記錄每一個http請求
需求:授權(quán)訪問(必須先登錄才能訪問)
第一步:添加依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--項目的基本描述-->
<groupId>com.hcx</groupId>
<artifactId>girl</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>girl</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--web項目必須引入的依賴-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--單元測試時需要用到的-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
第二步:編寫切面類:
@Aspect
@Component
public class HttpAspect {
//在http請求到方法之前記錄
/**
* @Before注解:在方法執(zhí)行之前執(zhí)行
* com.hcx包下的girlcontroller里面的girlList方法茫经,不管是什么參數(shù)都會被攔截
* 所有方法都攔截: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("我是方法執(zhí)行之后被攔截");
}
}
第三步:攔截controller中的方法:
@RestController
public class GirlController {
@Autowired
private GirlRepository girlRepository;
@Autowired
private GirlService girlService;
/**
* 查詢所有女生
* @return
*/
@GetMapping(value = "/girls")
public List<Girl> girlList(){
System.out.println("我是girlList方法");
return girlRepository.findAll();
}
}
運行結(jié)果:
3.jpg
4.jpg
注意:以上代碼可以看出有重復(fù)巷波,在切面類中優(yōu)化:
HttpAspect:
@Aspect
@Component
public class HttpAspect {
private final static Logger logger = LoggerFactory.getLogger(HttpAspect.class); //該類是org.slf4j的
//在http請求到方法之前記錄
/**
* @Before注解:在方法執(zhí)行之前執(zhí)行
* com.hcx包下的girlcontroller里面的girlList方法萎津,不管是什么參數(shù)都會被攔截
* 所有方法都攔截: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("我是方法執(zhí)行之前被攔截");
logger.info("前日志信息"); //打印info抹镊、error等日志
}
@After("log()")
public void doAfter(){
// System.out.println("我是方法執(zhí)行之后被攔截");
logger.info("后日志信息");
}
}
GirlController:
@RestController
public class GirlController {
/**
* getLogger方法中的參數(shù)與類名對應(yīng)
*/
private final static Logger logger = LoggerFactory.getLogger(GirlController.class);
@Autowired
private GirlRepository girlRepository;
@Autowired
private GirlService girlService;
/**
* 查詢所有女生
* @return
*/
@GetMapping(value = "/girls")
public List<Girl> girlList(){
// System.out.println("我是girlList方法");
logger.info("我是girlList方法");
return girlRepository.findAll();
}
}
5.jpg
6.jpg
記錄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
* 請求的是哪個類方法:類方法
* 方法的參數(shù)
*/
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());
//方法的參數(shù)
logger.info("args={}",joinPoint.getArgs());
}
@After("log()")
public void doAfter(){
// System.out.println("我是方法執(zhí)行之后被攔截");
logger.info("后日志信息");
}
/**獲取返回的內(nèi)容:
* {
"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方法中的參數(shù)與類名對應(yīng)
*/
private final static Logger logger = LoggerFactory.getLogger(GirlController.class);
@Autowired
private GirlRepository girlRepository;
@Autowired
private GirlService girlService;
/**
* 查詢所有女生
* @return
*/
@GetMapping(value = "/girls")
public List<Girl> girlList(){
// System.out.println("我是girlList方法");
logger.info("我是girlList方法");
return girlRepository.findAll();
}
}
Girl:
@Entity //該注解表示該類在數(shù)據(jù)庫中有對應(yīng)的表 不用創(chuàng)建該表
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;
}
}
7.jpg