说在前面
前两天项目经理给了一个需求,就是把所有的rest请求的日志记录下来并存到数据库中,要包含:
- 请求的信息:参数、方法、rest地址
- 响应的信息:状态、描述、数据
- 操作的记录:操作的业务模块、业务名称、操作的类型(SELECT|INSERT|DELETE|UPDATE)
- 请求人信息:userid、username(业务用户,登录后token里带着id)
我本来想的是用正常的增删改查业务去写这个功能,但是写到一半我就放弃了,传参、dto转entity真的会累死人啊,就想着用注解去完成这个业务,虽然中间的业务差不多,但个人感觉业务层面的耦合少了很多。
注解+AOP实现自定义业务存库功能
定义自定义注解
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyLog{
//操作的服务模块
String operationModule() default "";
//操作的类型
String operationType() default "";
}
控制层调用
触发注解的地方就在控制层
@RestController
@RequestMapping("/demo/api")
@Api(value = "示例接口")
public class DemoController {
@Autowired
private IDemoServie demoServie;
@ApiOperation(value = "获取示例数据", httpMethod = "GET", notes = "记录存储数据")
@RequestMapping(value = "/getAll", method = {RequestMethod.GET})
@XkSfLog(operationType = "SELECT", operationModule = "测试模块")
public APIResponse<DemoDto> page(PageQueryDto<DemoDto> pageDto) {
List<DemoDto> dList=demoServie.getAll();
return new APIResponse<DemoDto>(dList);
}
}
定义切面
切面需要用到:
- @Aspect:将一个类定义为切面类
@Pointcut:定义一个切点 ```java @Aspect @Component public class XkSfLogAspect { ThreadLocal
startTime = new ThreadLocal(); @Autowired private XkSfLogService xkSfLogService;
public XkSfLogAspect() { }
@Pointcut(“@annotation(com.xk.sifang.api.utils.log.XkSfLog)”) public void sfLogPointCut() { }
@Before(“sfLogPointCut()”) public void doBefore(JoinPoint joinPoint) {
this.startTime.set(System.currentTimeMillis());
}
@AfterReturning(
value = "sfLogPointCut()",
returning = "response"
) /**
正常请求日志存库 */ public void saveOperLog(JoinPoint joinPoint, Object response) { RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); HttpServletRequest request = (HttpServletRequest)requestAttributes.resolveReference(“request”); XkSfLogDto xkSfLogDto = new XkSfLogDto();
try {
XkSfLog annotationXkSfLog = (XkSfLog)method.getAnnotation(XkSfLog.class);
ApiOperation annotationApi = (ApiOperation) method.getAnnotation(ApiOperation.class);
//获取从注解传来的参数
if (annotationXkSfLog != null) {}
//从api注解中获取请求方法、业务详情、业务名称
if(annotationApi != null){}
//记录请求信息
if (null != response) {
//记录响应数据
}
//调用业务层存入成功请求的日志
xkSfLogService.saveXkSfLog(xkSfLogDto);
} catch (Exception e) {
e.printStackTrace();
} }
@AfterThrowing(
pointcut = "sfLogPointCut()",
throwing = "e"
) /**
异常业务日志存库 */ public void saveExceptionLog(JoinPoint joinPoint, Throwable e) { RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); HttpServletRequest request = (HttpServletRequest)requestAttributes.resolveReference(“request”); XkSfLogDto excepLog = new XkSfLogDto();
try {
XkSfLog annotationXkSfLog = (XkSfLog)method.getAnnotation(XkSfLog.class);
ApiOperation annotationApi = (ApiOperation)method.getAnnotation(ApiOperation.class);
//获取从注解传来的参数
if(annotationXkSfLog != null){}
if (annotationApi != null) {}
//记录请求信息
//记录响应失败的信息
excepLog.setResStatus("ERROR");
excepLog.setResDescription(e.getMessage());
//异常业务存库
xkSfLogService.saveXkSfLog(excepLog);
} catch (Exception var12) {
var12.printStackTrace();
} }
/**
工具方法 */ public Map
converMap(Map paramMap) { Map rtnMap = new HashMap(); Iterator var3 = paramMap.keySet().iterator(); while(var3.hasNext()) {
String key = (String)var3.next();
rtnMap.put(key, ((String[])paramMap.get(key))[0]);
}
return rtnMap; }
}