在外界访问资源的时候,需要作日志记录
但不可能在每个controller上面都写一遍日志记录的函数
因此需要使用AOP对controller进行一个日志方法的增强

首先做好springboot的yml配置

logging:
  level:
    root: info
    com.wzyblog: debug
  file:
    name: log/blog-dev.log

步骤:
1、编写日志方法类
2、编写好切面,设置好切点表达式和注解
3、设定需要记录的日志内容
记录{ url;访问源ip;调用方法;传入参数;返回的页面名 }
开整


目录结构如下

java利用切面编程实现日志管理 springboot 切面日志_java


我们需要覆盖所有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) +
                    '}';
        }
    }
}

最后的测试略