在外界访问资源的时候,需要作日志记录
但不可能在每个controller上面都写一遍日志记录的函数
因此需要使用AOP对controller进行一个日志方法的增强
首先做好springboot的yml配置
logging:
level:
root: info
com.wzyblog: debug
file:
name: log/blog-dev.log
步骤:
1、编写日志方法类
2、编写好切面,设置好切点表达式和注解
3、设定需要记录的日志内容
记录{ url;访问源ip;调用方法;传入参数;返回的页面名 }
开整
目录结构如下
我们需要覆盖所有controller
【我这里的所有controller会放到web包下】
代码如下
@Aspect
@Component
public class LogAspect {
private Logger logger= LoggerFactory.getLogger(this.getClass());
@Pointcut("execution(* com.wzyblog.web.*.*(..))")
public void log(){}
@Before("log()")
public void doBefore(){
}
@AfterReturning(returning = "result", pointcut = "log()")
public void logAfterReturning(Object result){
}
日志嘛,肯定需要写日志的一个对象
private Logger logger= LoggerFactory.getLogger(this.getClass());
编写一个内部类,包含{ url;访问源ip;调用方法;传入参数;返回的页面名 }
编写其全参构造函数以及tostring方法【用lombok也可】
/**
*我们想让日志记录 :
* url请求
* 访问对象的IP地址
* 调用了什么方法
* 传入了什么参数
* */
private class content{
private String url;
private String ip;
private String method;
private Object[] args;
public content(String url, String ip, String method, Object[] args) {
this.url = url;
this.ip = ip;
this.method = method;
this.args = args;
}
@Override
public String toString() {
return "{" +
"url='" + url + '\'' +
", ip='" + ip + '\'' +
", method='" + method + '\'' +
", args=" + Arrays.toString(args) +
'}';
}
}
Question
url和访问源ip如何获得呢?
我们可以在请求域中获取
先得到一个servletrequestattributes对象
再从中取出所需要的httpservletrequest对象
调用其中的两个方法即可获取url与ip
【其中getrequestURL方法返回的类型是stringbuffer】
ServletRequestAttributes attributes= (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
String url=request.getRequestURL().toString();
String ip=request.getRemoteAddr();
调用方法和传入参数又如何获取呢?
此时则需要使用一个aop特有的对象【joinpoint】
dobefore函数传入一个joinpoint对象
调用此对象的两个函数即可获取所要数据
String method=
joinPoint.getSignature().getDeclaringTypeName()
+"."+
joinPoint.getSignature().getClass();
Object[] args=joinPoint.getArgs();
再将这四个参数利用内部类的有参构造创建content对象
最后写入日志
content content = new content(url,ip,method,args);
logger.info("Request:{}",content);
最后返回的页面名称如何获取?
使用afterreturning注解
这个注解可以获取切面方法的返回值
controller的返回值恰好是html文件名【无改动前后缀的情况下】
@AfterReturning(returning = "result", pointcut = "log()")
public void logAfterReturning(Object result){
logger.info("Result:{}",result);
// 记录最后返回的是哪个页面
}
编写完之后的代码如下
@Aspect
@Component
public class LogAspect {
private Logger logger= LoggerFactory.getLogger(this.getClass());
@Pointcut("execution(* com.wzyblog.web.*.*(..))")
public void log(){}
@Before("log()")
public void doBefore(JoinPoint joinPoint){
// 传入的是切面对象,即出发这个AOP时被调用的那个方法,以获取所需要的"调用方法"以及"传入参数"
ServletRequestAttributes attributes= (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
String url=request.getRequestURL().toString();
String ip=request.getRemoteAddr();
String method=
joinPoint.getSignature().getDeclaringTypeName()
+"."+
joinPoint.getSignature().getClass();
Object[] args=joinPoint.getArgs();
content content = new content(url,ip,method,args);
logger.info("Request:{}",content);
}
@AfterReturning(returning = "result", pointcut = "log()")
public void logAfterReturning(Object result){
logger.info("Result:{}",result);
// 记录最后返回的是哪个页面
}
/**
*我们想让日志记录 :
* url请求
* 访问对象的IP地址
* 调用了什么方法
* 传入了什么参数
* */
private class content{
private String url;
private String ip;
private String method;
private Object[] args;
public content(String url, String ip, String method, Object[] args) {
this.url = url;
this.ip = ip;
this.method = method;
this.args = args;
}
@Override
public String toString() {
return "{" +
"url='" + url + '\'' +
", ip='" + ip + '\'' +
", method='" + method + '\'' +
", args=" + Arrays.toString(args) +
'}';
}
}
}
最后的测试略