场景:当service的方法执行抛出异常时,事务会发生回滚,导致无法记录错误日志
解决:切面
其他:1.日志需要记录日志标题,保存入参
2.失败时会抛出异常;日志需要判断执行是否成功,记录状态
3.只是模拟操作,实际情况需要将日志保存到数据库
引入依赖:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>
代码:
1. 日志记录时需要加标题,每个方法的日志标题不一样,解决办法是切面+自定义注解
package com.test.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 LogAnnotation {String logTitle() default "";//日志标题
}
controller的方法上加注解:
@LogAnnotation(logTitle = "post测试")@PostMapping("/login")public String login(@RequestBody Department department) throws Exception{return "hello World";}
2. 配置切面
package com.test.aspect;import com.test.Annotation.LogAnnotation;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;@Aspect
@Component
public class LogAspect {@Autowiredprivate HttpServletRequest request;// @Pointcut("@annotation(com.test.aspect.LogAnnotation)") //单独设置@Pointcut("execution(* com.test.controller.*.*(..)) && @annotation(com.test.Annotation.LogAnnotation)") //同时设置public void pt() {}@Around("pt()")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {Object result = null;try{MethodSignature signature = (MethodSignature)joinPoint.getSignature();Method method = signature.getMethod();LogAnnotation logAnnotation =method.getAnnotation(LogAnnotation.class);System.out.println("@anno logtitle = " + logAnnotation.logTitle());//自定义注解-日志名称System.out.println("method = " + method.getName());//方法名System.out.println("params = " + Arrays.toString(joinPoint.getArgs()));//参数,post和get都可以获取;也可以转为JSON格式result = joinPoint.proceed();//执行结果,即response返回的数据System.out.println("response = " + result);//todo:记录状态为true的日志,dao操作省略return result;}catch (Exception e) {//如果controller的方法执行时发生异常,会被捕获异常,可以在这里记录错误日志System.out.println("method has exception, e = " + e);//todo:记录状态为false的日志,dao操作省略}return result;}
}
3.测试
3.1 get测试: 发送请求:http://localhost:8081/hello?userId=abc
a. get测试-正常请求时
@LogAnnotation(logTitle = "get测试")@GetMapping("/hello")public String hello(@RequestParam(value="userId", required = false) String userId) throws Exception{return "hello World";}
打印:
@anno logtitle = get测试
method = hello
params = [abc]
response = hello World
b. get测试-抛出异常时
@LogAnnotation(logTitle = "get测试")@GetMapping("/hello")public String hello(@RequestParam(value="userId", required = false) String userId) throws Exception{try {int i = 1/0;}catch (Exception e) {throw new Exception("eeeeeee");}return "hello World";}
打印:
@anno logtitle = get测试
method = hello
params = [abc]
method has exception, e = java.lang.Exception: eeeeeee
3.2 post请求
@LogAnnotation(logTitle = "post测试")@PostMapping("/login")public String login(@RequestBody Department department) throws Exception{return "登录成功";}
post请求,路径:localhost:8081/login
body:
{"id":1,"departName":"部门名称"
}
打印
@anno logtitle = post测试
method = login
params = [Department(id=1, departName=部门名称)]
response = 登录成功