栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

使用Springboot的AOP日志拦截获取前端网站的操作记录

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

使用Springboot的AOP日志拦截获取前端网站的操作记录

使用Springboot的AOP日志拦截获取前端网站的操作记录
  • 前言
  • 一、创建一个Springboot Web项目
  • 二、运行项目
  • 三、代码解析
  • 总结


前言

随着我们的不断学习,我们的技术不断沉淀,做出来的项目也不断成熟

所以,我们的网站怎么能没有日志记录呢


一、创建一个Springboot Web项目

选择左边那个 Spring Initializr 来创建

这一步是选择项目要用到的依赖,勾选以后就不用配置 Maven 的 pom 了,当然这里面都是些常用依赖,里面没有的还是要手动添加 pom,Springboot 的Web项目选择Spring Web就行了,根据需要选择

完成后我们向 pom.xml 中添加一条依赖,用于日志的拦截和输出

	
    
        org.springframework.boot
        spring-boot-starter-aop
    

先建立项目结构, annotation 和 aop 是用于日志拦截的文件,拦截的位置是进入 controller 层之前就开始拦截。

annotation 下面的 Log

package com.xuyijie.aoplogintercept.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
    String value() default "";
}

aop 下面的 LogAspect 和 WebLogAspect , @Pointcut 里面的包名修改成你们自己的

package com.xuyijie.aoplogintercept.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LogAspect {
    private static final Logger logger = LoggerFactory.getLogger(LogAspect.class);

    
    @Pointcut("@annotation(com.xuyijie.aoplogintercept.annotation.Log)")
    public void logPointCut(){

    }

    public Object around(ProceedingJoinPoint point) throws Throwable{
        long beginTime = System.currentTimeMillis();
        // 执行方法
        Object result = point.proceed();
        // 执行时长(毫秒)
        long time = System.currentTimeMillis() - beginTime;
        //异步保存日志 这里是文本日志
        return result;
    }

    void saveLog(ProceedingJoinPoint joinPoint,long time) throws InterruptedException{

    }
}
package com.xuyijie.aoplogintercept.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
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;
import java.util.Arrays;

@Aspect
@Component
public class WebLogAspect {
    private static final Logger logger = LoggerFactory.getLogger(WebLogAspect.class);

    
    //两个..代表所有子目录,最后括号里的两个..代表所有参数
    @Pointcut("execution(* com.xuyijie.aoplogintercept.controller.*.*(..))")
    public void logPointCut(){

    }

    
    @Before("logPointCut()")
    public void doBefore(JoinPoint joinPoint){
        // 接收到请求,记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 记录下请求内容
        logger.info("请求地址:" + request.getRequestURI().toString());
        logger.info("请求方法:" + request.getMethod());
        logger.info("后台接口:" + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        logger.info("参数:" + Arrays.toString(joinPoint.getArgs()));

    }

    
    // returning的值和doAfterReturning的参数名一致
    @AfterReturning(returning = "ret",pointcut = "logPointCut()")
    public void doAfterReturning(Object ret){
        // 处理完请求,返回内容(返回值太复杂时,打印的是物理存储空间的地址)
        logger.info("返回值:" + ret);
    }

    @Around("logPointCut()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        long startTime = System.currentTimeMillis();
        // ob 为方法的返回值
        Object ob = pjp.proceed();
        logger.info("耗时:" + (System.currentTimeMillis() - startTime) + "ms");
        return ob;
    }
}

controller 里面很简单,就是在网页打印一句话

package com.xuyijie.aoplogintercept.controller;

import com.xuyijie.aoplogintercept.annotation.Log;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class IndexController {
    @Log("日志注解,配合WebAspect记录请求前、请求后、请求过程")
    @RequestMapping("/log")
    @ResponseBody
    public String log(String name){
        return "这是自定义的返回结果";
    }
}

二、运行项目

启动项目

然后在浏览器的地址栏里输入 localhost:8080/log/?name=啦啦啦 ,回车访问

我没有配置 application.properties 文件,所以端口默认8080,/log是controller里面方法上面配置的请求路径,?name=啦啦啦 ,name 是 controller 里面方法的传参。

网页打印出结果,回到代码的控制台,发现下面打印出了 请求地址、请求方法、传参 等等


三、代码解析

首先是各注解的意思

@Aspect 面向切面编程注解,通常应用在类上
@Pointcut Pointcut是植入Advice的触发条件。每个Pointcut的定义包括2部分,一是表达式,二是方法签名。方法签名必须是 public及void型。可以将Pointcut中的方法看作是一个被Advice引用的助记符,因为表达式不直观,因此我们可以通过方法签名的方式为 此表达式命名。因此Pointcut中的方法只需要方法签名,而不需要在方法体内编写实际代码
@Around:环绕增强,相当于MethodInterceptor
@AfterReturning:后置增强,相当于AfterReturningAdvice,方法正常退出时执行
@Before:标识一个前置增强方法,相当于BeforeAdvice的功能,相似功能的还有
@AfterThrowing:异常抛出增强,相当于ThrowsAdvice
@After: final增强,不管是抛出异常或者正常退出都会执行

然后是,annotation 和 aop 是用于日志拦截的文件,写好后,想要拦截哪个方法的日志,就在哪个方法上面加注解 @Log("")


总结

这个方法拦截到的数据如果太复杂,会显示内存地址而不是我们能看懂的文字,比如前端的传参是 json 的话,就要额外处理了。

这篇是最基础的写法,结构越简单越好理解,以后会写一个完整的日志方法,包括存储、过滤、格式化和错误日志的处理,到时候再来放传送门。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/643780.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号