前言 随着我们的不断学习,我们的技术不断沉淀,做出来的项目也不断成熟
所以,我们的网站怎么能没有日志记录呢
1、创建Springboot Web项目并添加依赖 选择左边那个 Spring Initializr 来创建
这一步是选择项目要用到的依赖,勾选以后就不用配置 Maven 的 pom 了,当然这里面都是些常用依赖,里面没有的还是要手动添加 pom,Springboot 的Web项目选择Spring Web就行了,根据需要选择
完成后我们向pom.xml
中添加一条依赖,用于日志的拦截和输出
1 2 3 4 5 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-aop</artifactId > </dependency >
先建立项目结构, annotation 和 aop 就是用于日志拦截的文件
2、新建保存日志实体类(非必须) 我们先新建一个实体类来存储我们拦截到的日志,如果不想存储就不用新建这个了,直接把日志打印到控制台就行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 import lombok.Data;import java.util.Date;@Data public class LogSave { private String operationModule; private String operationType; private String operationDescription; private String requestUrl; private String requestMethod; private String requestInterface; private String requestParam; private String responseResult; private long operationPeriod; private Date operationTime; }
3、简简单单写个Controller controller
里面很简单,就是在网页打印一句话,然后加上我们自定义的 @Log
注解,@Log代码在下面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import com.xuyijie.aoplogintercept.annotation.Log;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestController public class TestController { @Log(operationModule = "主题", operationType = "操作类型:查询/删除", operationDescription = "具体操作:删除了文件") @RequestMapping("/log") public String log () { return "这是自定义的返回结果" ; } }
4、自定义注解 annotation包
下面的 Log
,是自定义注解,字段的解释下面的注释中很清晰哦
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 import java.lang.annotation.*;@Documented @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Log { String operationModule () default "" ; String operationType () default "" ; String operationDescription () default "" ; }
5、开始拦截 aop包
下面的LogAspect
, @Pointcut
里面的包名修改成你们自己的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 import com.xuyijie.aoplogintercept.annotation.Log;import entity.LogSave;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.*;import org.aspectj.lang.reflect.MethodSignature;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.lang.reflect.Method;import java.util.Arrays;@Aspect @Component public class LogAspect { private LogSave logSave = new LogSave (); @Pointcut("@annotation(com.xuyijie.aoplogintercept.annotation.Log)") public void logPointCut () { } @Before("logPointCut()") public void doBefore (JoinPoint joinPoint) { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); assert attributes != null ; HttpServletRequest request = attributes.getRequest(); logSave = new LogSave (); logSave.setRequestUrl(request.getRequestURI()); logSave.setRequestMethod(request.getMethod()); logSave.setRequestInterface(joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName()); logSave.setRequestParam(Arrays.toString(joinPoint.getArgs())); MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); Log logAnnotation = method.getAnnotation(Log.class); logSave.setOperationModule(logAnnotation.operationModule()); logSave.setOperationType(logAnnotation.operationType()); logSave.setOperationDescription(logAnnotation.operationDescription()); } @AfterReturning(returning = "ret", pointcut = "logPointCut()") public void doAfterReturning (Object ret) { logSave.setResponseResult(ret.toString()); } @Around("logPointCut()") public Object doAround (ProceedingJoinPoint pjp) throws Throwable { long startTime = System.currentTimeMillis(); Object ob = pjp.proceed(); logSave.setOperationPeriod(System.currentTimeMillis() - startTime); return ob; } }
6、运行项目 启动项目
然后在浏览器的地址栏里输入 localhost:8080/log/?name=啦啦啦 ,回车访问
我没有配置 application.properties 文件,所以端口默认8080,/log是controller里面方法上面配置的请求路径,?name=啦啦啦 ,name 是 controller 里面方法的传参。
你们自己在在 LogAspect
里面添加一点打印语句,控制台打印出拦截结果,请求地址、请求方法、传参 等等
7、代码解析 首先是各注解的意思
1 2 3 4 5 6 7 8 9 10 11 12 @Aspect 面向切面编程注解,通常应用在类上@Pointcut Pointcut是植入Advice的触发条件。每个Pointcut的定义包括2 部分,一是表达式,二是方法签名。方法签名必须是 public 及void 型。可以将Pointcut中的方法看作是一个被Advice引用的助记符,因为表达式不直观,因此我们可以通过方法签名的方式为 此表达式命名。因此Pointcut中的方法只需要方法签名,而不需要在方法体内编写实际代码@Around :环绕增强,相当于MethodInterceptor@AfterReturning :后置增强,相当于AfterReturningAdvice,方法正常退出时执行@Before :标识一个前置增强方法,相当于BeforeAdvice的功能,相似功能的还有@AfterThrowing :异常抛出增强,相当于ThrowsAdvice@After : final 增强,不管是抛出异常或者正常退出都会执行然后是,LogAspect 里面的包路径配置, @annotation : 指定 @Log 注解位置,这里 @annotation 里的配置代表只拦截增加了自定义注解 @Log 的方法,想要拦截哪个方法的日志,就在哪个方法上面加注解 `@Log() `execution:指定 controller 包下的注解,.*代表controller包下所有文件,*(..)代表所有方法 这里execution是拦截全部controller接口的意思,如果只想拦截增加了自定义注解的方法,使用@annotation
总结 @Arround 是个万能注解,可以代替 @Before 和 @After,所以我在保存数据库的那个文件里只是用了 @Arround,保存到数据库的字段可以自己定制,下面是我另一个项目的日志,给你们参考一下。