自定义注解 + AOP 记录用户的使用日志
使用背景
(1)在学校项目中,安防平台实际的使用人员大多都是外聘人员,用户的一些关键操作最好记录清楚,像是青岛工程职业学院网络及监控系统项目中,有个功能是对全校学生权限的一键冻结和解冻。
(2)对接非常强势的第三方数据时,例如腾讯的腾讯微卡产品,虽然是他们将数据接入到海康平台,但仍然不接受定制,我们必须按照腾讯的接口协议,提供给他们接口。注意:此时没有办法走OpenApi,而请假数据是每天有推送的,为了一旦出现问题可回溯,需要记录完整的数据日志。
落地实践
一:自定义注解
配置自定义注解"LogPoint",之后会用在关键的接口上,作为切入点来记录该接口的访问信息。
java
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface LogPoint {
/***
* @Description 日志描述
* @return java.lang.String
*/
String description() default "";
}
二:切面配置
1.在切面里,我们可以配置请求参数的详细信息逐条打印,和响应结果与它的耗时记录,这些打印信息足以应对现场的大多数问题。
2.不用担心info日志打印过多的问题,只需要把注解标注在关键的接口,与多占的那些硬盘空间相比,这些信息能帮助技术和研发节省更多的时间,更具性价比。
java
/**
* @ClassName AspectLogConfig
* @Description 出入参日志配置类
* @Version 1.0
**/
@Aspect
@Component
@Slf4j
public class LogConfig {
private final static Logger logger = LoggerFactory.getLogger(LogConfig.class);
@Pointcut("@annotation(com.hikvision.pea.common.annotation.LogPoint)")
public void logPoint() {
}
/***
* @Description 切入点之前织入
* @Param []
* @return void
*/
@Before("logPoint()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
//开始打印请求日志
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
//打印请求相关参数
logger.info("================== start ==================");
//打印请求 url
logger.info("URL : {}", request.getRequestURL().toString());
//打印描述信息
//打印HTTP method
logger.info("HTTP Method : {}", request.getMethod());
//打印调用 controller 的全路径以及执行方法
logger.info("Class Method : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
//打印请求的ip
logger.info("IP : {}", request.getRemoteAddr());
//打印请求入参
logger.info("Request Args : {}", joinPoint.getArgs());
}
@After("logPoint()")
public void doAfter() throws Throwable {
}
/***
* @Description 环绕
* @Date 14:35 2022/6/23
* @Param [proceedingJoinPoint]
* @return java.lang.Object
*/
@Around("logPoint()")
public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
//执行切点
Object result = proceedingJoinPoint.proceed();
logger.info("打印出参 : {}", result);
logger.info("执行耗时 : {} ms", System.currentTimeMillis() - startTime);
logger.info("================== end ===================" + System.lineSeparator());
return result;
}
}
三:Api层使用
只需要将注解加在对应的接口上,无需其它编码。
java
/**
* @ClassName ResourceController
* @Description 门禁点控制器
* @Version 1.0
**/
@Api(tags = "门禁点控制器")
@RestController
@RequestMapping("/resource")
@Slf4j
public class ResourceController {
@Autowired
IResourceService iResourceService;
@ApiOperation("获取门禁点资源")
@PostMapping("/doorSources")
@LogPoint(description = "获取门禁点资源")
public ResponseData getDoorSources(@ApiParam("入参") @RequestBody ResourceReqVo resourceReqVo) {
Page<Resource> resources = iResourceService.getResources(resourceReqVo);
return ResponseData.success(resources);
}
}
使用效果
将调用方的请求参数、IP、响应结果、耗时,都完整的打印出来,一旦出现外聘人员误操作或者三方数据不匹配,通过这些信息,定位起问题来都非常方便。