Spring Boot入门(6)-使用AOP统一处理Web请求日志
2018-03-02 23:10
1276 查看
本文介绍 SpringBoot 使用 AOP 统一处理 Web 请求日志。
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
import com.liuyanzhao.blog.domain.User;
import com.liuyanzhao.blog.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @Author 言曌
* @DATE 2017/10/29 上午10:33
* @URL http://liuyanzhao.com
*/
@RestController
public class UserController {
@Autowired
private UserRepository userRepository;
/**
* 查询所有用户列表
* @return
*/
@GetMapping(value = "/users")
public List<User> listUser() {
System.out.println("List all user!");
return userRepository.findAll();
}
/**
* 删除一个用户
* @param id
*/
@DeleteMapping(value = "/users/{id}")
public void deleteUser(@PathVariable("id") Integer id) {
System.out.println("Delete a user!");
userRepository.delete(id);
}
}
2、UserRepository.javapackage com.liuyanzhao.blog.repository;
import com.liuyanzhao.blog.domain.User;
import org.springframework.data.jpa.repository.JpaRepository;
/**
* @Author 言曌
* @DATE 2017/10/29 上午10:35
* @URL http://liuyanzhao.com
*/
public interface UserRepository extends JpaRepository<User,Integer>{//表名和Id类型
}
3、User.javapackage com.liuyanzhao.blog.domain;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.validation.constraints.Min;
@Entity
public class User {
@Id
@GeneratedValue
private Integer id;
private String name;
private String gender;
private Integer age;
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;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
4、HttpAspect.java 拦截器① 写法一、package com.liuyanzhao.blog.aspect;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
/**
* @Author 言曌
* @DATE 2017/10/30 下午7:03
* @URL http://liuyanzhao.com
*/
@Aspect
@Component
public class HttpAspect {
//在UserController所有方法调用之前执行一次
@Before("execution(public * com.liuyanzhao.blog.controller.UserController.*(..))")
public void doBefore() {
System.out.println("11111111");
}
//在UserController所有方法调用之后执行一次
@After("execution(public * com.liuyanzhao.blog.controller.UserController.*(..))")
public void doAfter() {
System.out.println("222222222");
}
}
注意:@Aspect 表示该类是一个面向切面编程的类@Component 表示将该类加入 Spring 容器@Before("execution(public * com.liuyanzhao.blog.controller.UserController.*(..))") 表示在 UserController 类下的所有方法执行前执行。@After与@Before相反 然后我们可以发起一个查询所有用户的请求和删除一个用户的请求,观察控制台
可以证明拦截器是有效的 ② 写法二、我们发现上面的 @Before 和 @After 后面的代码是一样的,重复了,本着不写重复代码的原则,我们要把它整理一下,所以 HttpAspect.java 可以改成这样package com.liuyanzhao.blog.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;
/**
* @Author 言曌
* @DATE 2017/10/30 下午7:03
* @URL http://liuyanzhao.com
*/
@Aspect
@Component
public class HttpAspect {
@Pointcut("execution(public * com.liuyanzhao.blog.controller.UserController.*(..))")
public void log() { }
//在UserController所有方法调用之前执行一次
@Before("log()")
public void doBefore() {
System.out.println("11111111");
}
//在UserController所有方法调用之后执行一次
@After("log()")
public void doAfter() {
System.out.println("222222222");
}
}
③ 写法三 (推荐)package com.liuyanzhao.blog.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.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
/**
* @Author 言曌
* @DATE 2017/10/30 下午7:03
* @URL http://liuyanzhao.com
*/
@Aspect
@Component
public class HttpAspect {
private final static Logger logger = LoggerFactory.getLogger(HttpAspect.class);
@Pointcut("execution(public * com.liuyanzhao.blog.controller.UserController.*(..))")
public void log() { }
//在UserController所有方法调用之前执行一次
@Before("log()")
public void doBefore() {
logger.info("11111111111");
}
//在UserController所有方法调用之后执行一次
@After("log()")
public void doAfter() {
logger.info("22222222222");
}
}
注意 Logger 的包不要导错了,要导 org.slf4j.Logger; 下的和方法一执行同样的操作,控制台效果图如下
我们发现这次的日志里会有时间,进程号,端口号,哪个类输出的日志等信息,更加强大,所以更为推荐使用。
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
/**
* @Author 言曌
* @DATE 2017/10/30 下午7:03
* @URL http://liuyanzhao.com
*/
@Aspect
@Component
public class HttpAspect {
private final static Logger logger = LoggerFactory.getLogger(HttpAspect.class);
@Pointcut("execution(public * com.liuyanzhao.blog.controller.UserController.*(..))")
public void log() { }
//在UserController所有方法调用之前执行一次
@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_method={}",joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
//参数
logger.info("args={}",joinPoint.getArgs());
}
//在UserController所有方法调用之后执行一次
@After("log()")
public void doAfter() {
logger.info("22222222222");
}
//返回结果
@AfterReturning(returning = "object",pointcut = "log()")
public void doAfterReturning(Object object) {
logger.info("response={}",object);
}
}
发起一个请求,控制台效果图
一、导入依赖
<dependency><groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
二、代码示例
这里通过一个拦截器的示例介绍。主要看 HttpAspect.java 的代码1、UserController.javapackage com.liuyanzhao.blog.controller;import com.liuyanzhao.blog.domain.User;
import com.liuyanzhao.blog.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @Author 言曌
* @DATE 2017/10/29 上午10:33
* @URL http://liuyanzhao.com
*/
@RestController
public class UserController {
@Autowired
private UserRepository userRepository;
/**
* 查询所有用户列表
* @return
*/
@GetMapping(value = "/users")
public List<User> listUser() {
System.out.println("List all user!");
return userRepository.findAll();
}
/**
* 删除一个用户
* @param id
*/
@DeleteMapping(value = "/users/{id}")
public void deleteUser(@PathVariable("id") Integer id) {
System.out.println("Delete a user!");
userRepository.delete(id);
}
}
2、UserRepository.javapackage com.liuyanzhao.blog.repository;
import com.liuyanzhao.blog.domain.User;
import org.springframework.data.jpa.repository.JpaRepository;
/**
* @Author 言曌
* @DATE 2017/10/29 上午10:35
* @URL http://liuyanzhao.com
*/
public interface UserRepository extends JpaRepository<User,Integer>{//表名和Id类型
}
3、User.javapackage com.liuyanzhao.blog.domain;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.validation.constraints.Min;
@Entity
public class User {
@Id
@GeneratedValue
private Integer id;
private String name;
private String gender;
private Integer age;
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;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
4、HttpAspect.java 拦截器① 写法一、package com.liuyanzhao.blog.aspect;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
/**
* @Author 言曌
* @DATE 2017/10/30 下午7:03
* @URL http://liuyanzhao.com
*/
@Aspect
@Component
public class HttpAspect {
//在UserController所有方法调用之前执行一次
@Before("execution(public * com.liuyanzhao.blog.controller.UserController.*(..))")
public void doBefore() {
System.out.println("11111111");
}
//在UserController所有方法调用之后执行一次
@After("execution(public * com.liuyanzhao.blog.controller.UserController.*(..))")
public void doAfter() {
System.out.println("222222222");
}
}
注意:@Aspect 表示该类是一个面向切面编程的类@Component 表示将该类加入 Spring 容器@Before("execution(public * com.liuyanzhao.blog.controller.UserController.*(..))") 表示在 UserController 类下的所有方法执行前执行。@After与@Before相反 然后我们可以发起一个查询所有用户的请求和删除一个用户的请求,观察控制台
可以证明拦截器是有效的 ② 写法二、我们发现上面的 @Before 和 @After 后面的代码是一样的,重复了,本着不写重复代码的原则,我们要把它整理一下,所以 HttpAspect.java 可以改成这样package com.liuyanzhao.blog.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;
/**
* @Author 言曌
* @DATE 2017/10/30 下午7:03
* @URL http://liuyanzhao.com
*/
@Aspect
@Component
public class HttpAspect {
@Pointcut("execution(public * com.liuyanzhao.blog.controller.UserController.*(..))")
public void log() { }
//在UserController所有方法调用之前执行一次
@Before("log()")
public void doBefore() {
System.out.println("11111111");
}
//在UserController所有方法调用之后执行一次
@After("log()")
public void doAfter() {
System.out.println("222222222");
}
}
③ 写法三 (推荐)package com.liuyanzhao.blog.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.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
/**
* @Author 言曌
* @DATE 2017/10/30 下午7:03
* @URL http://liuyanzhao.com
*/
@Aspect
@Component
public class HttpAspect {
private final static Logger logger = LoggerFactory.getLogger(HttpAspect.class);
@Pointcut("execution(public * com.liuyanzhao.blog.controller.UserController.*(..))")
public void log() { }
//在UserController所有方法调用之前执行一次
@Before("log()")
public void doBefore() {
logger.info("11111111111");
}
//在UserController所有方法调用之后执行一次
@After("log()")
public void doAfter() {
logger.info("22222222222");
}
}
注意 Logger 的包不要导错了,要导 org.slf4j.Logger; 下的和方法一执行同样的操作,控制台效果图如下
我们发现这次的日志里会有时间,进程号,端口号,哪个类输出的日志等信息,更加强大,所以更为推荐使用。
三、将 http 请求写入日志
将上面的 HttpAspect.java 修改一下,用于获取 Http 请求,并写入日志package com.liuyanzhao.blog.aspect;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
/**
* @Author 言曌
* @DATE 2017/10/30 下午7:03
* @URL http://liuyanzhao.com
*/
@Aspect
@Component
public class HttpAspect {
private final static Logger logger = LoggerFactory.getLogger(HttpAspect.class);
@Pointcut("execution(public * com.liuyanzhao.blog.controller.UserController.*(..))")
public void log() { }
//在UserController所有方法调用之前执行一次
@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_method={}",joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
//参数
logger.info("args={}",joinPoint.getArgs());
}
//在UserController所有方法调用之后执行一次
@After("log()")
public void doAfter() {
logger.info("22222222222");
}
//返回结果
@AfterReturning(returning = "object",pointcut = "log()")
public void doAfterReturning(Object object) {
logger.info("response={}",object);
}
}
发起一个请求,控制台效果图
相关文章推荐
- Spring Boot中使用AOP统一处理Web请求日志
- Spring Boot中使用AOP统一处理Web请求日志
- 46. Spring Boot中使用AOP统一处理Web请求日志【从零开始学Spring Boot】
- Spring Boot中使用AOP统一处理Web请求日志
- springboot【19】日志管理之使用AOP统一处理Web请求日志
- 详解Spring Boot中使用AOP统一处理Web请求日志
- Spring Boot教程(六)使用AOP统一处理Web请求日志
- Spring Boot中使用AOP统一处理Web请求日志
- Spring Boot中使用AOP统一处理Web请求日志
- (十四)SpringBoot使用AOP统一处理Web请求日志添加MDC
- Spring Boot中使用AOP统一处理Web请求日志
- Spring Boot中使用AOP统一处理Web请求日志
- Spring Boot中使用AOP统一处理Web请求日志
- Spring Boot中使用AOP统一处理Web请求日志
- Spring Cloud Spring Boot mybatis分布式微服务云架构(四十)使用AOP统一处理Web请求日志(1)
- Spring Boot(十一)使用AOP,@Aspect统一处理Web请求日志
- (转)Spring Boot中使用AOP统一处理Web请求日志
- 46. Spring Boot中使用AOP统一处理Web请求日志【从零开始学Spring Boot】
- 46. Spring Boot中使用AOP统一处理Web请求日志
- 46. Spring Boot中使用AOP统一处理Web请求日志