一、首先自定义注解类SysLogAnnotation
/** * @date 2019/2/1 操作日志注解 */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface SysLogAnnotation { /** * 描述 * @return {String} */ String value(); }
二、添加切面类SysLogAspect,实现同一的日志添加
1、使用@Aspect注解定义切面类
@Component注册bean
@Around(“@annotation(sysLogAnnotation)”)
实现切面环绕监听添加了@sysLogAnnotation注解的方法,
通过sysLogAnnotation.value()获取注解中的value值
@Aspect @Slf4j @Component public class SysLogAspect { @Around("@annotation(sysLogAnnotation)") @SneakyThrows public Object around(ProceedingJoinPoint point, com.example.swaggerdemo.annotation.SysLogAnnotation sysLogAnnotation) { String strClassName = point.getTarget().getClass().getName(); String strMethodName = point.getSignature().getName(); log.debug("[类名]:{},[方法]:{}", strClassName, strMethodName); SysLog logVo = SysLogUtils.getSysLog(); logVo.setTitle(sysLogAnnotation.value()); // 发送异步日志事件 Long startTime = System.currentTimeMillis(); Object obj; try { obj = point.proceed(); } catch (Exception e) { logVo.setType(LogTypeEnum.ERROR.getType()); logVo.setException(e.getMessage()); throw e; } finally { Long endTime = System.currentTimeMillis(); logVo.setTime(String.valueOf(endTime - startTime)); SpringContextHolder.publishEvent(new SysLogEvent(logVo)); } return obj; } } @Slf4j @UtilityClass public class SysLogUtils { public SysLog getSysLog() { //获取请求url,ip,httpMethod HttpServletRequest request = ((ServletRequestAttributes) Objects .requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest(); SysLog sysLog = new SysLog(); //sysLog.setCreateBy(Objects.requireNonNull(getUsername())); //sysLog.setUpdateBy(Objects.requireNonNull(getUsername())); sysLog.setType(LogTypeEnum.NORMAL.getType()); sysLog.setRemoteAddr(ServletUtil.getClientIP(request)); sysLog.setRequestUri(URLUtil.getPath(request.getRequestURI())); sysLog.setMethod(request.getMethod()); sysLog.setUserAgent(request.getHeader(HttpHeaders.USER_AGENT)); sysLog.setParams(HttpUtil.toParams(request.getParameterMap())); //sysLog.setServiceId(getClientId(request)); return sysLog; } }
2、通过继承ApplicationEvent
自定义事件SysLogEvent
public class SysLogEvent extends ApplicationEvent { public SysLogEvent(SysLog source) { super(source); } }
3、通过实现ApplicationContextAware接口
获得自定义上下文管理器
调用applicationContext.publishEvent(event)方法发布事件
在切面监听方法时,调用事件发布方法发布事件
@Slf4j @Service @Lazy(false) public class SpringContextHolder implements ApplicationContextAware, DisposableBean { private static ApplicationContext applicationContext = null; /** * 取得存储在静态变量中的ApplicationContext. */ public static ApplicationContext getApplicationContext() { return applicationContext; } /** * 实现ApplicationContextAware接口, 注入Context到静态变量中. */ @Override public void setApplicationContext(ApplicationContext applicationContext) { SpringContextHolder.applicationContext = applicationContext; } /** * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型. */ @SuppressWarnings("unchecked") public static <T> T getBean(String name) { return (T) applicationContext.getBean(name); } /** * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型. */ public static <T> T getBean(Class<T> requiredType) { return applicationContext.getBean(requiredType); } /** * 清除SpringContextHolder中的ApplicationContext为Null. */ public static void clearHolder() { if (log.isDebugEnabled()) { log.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext); } applicationContext = null; } /** * 发布事件 * @param event */ public static void publishEvent(ApplicationEvent event) { if (applicationContext == null) { return; } applicationContext.publishEvent(event); } /** * 实现DisposableBean接口, 在Context关闭时清理静态变量. */ @Override @SneakyThrows public void destroy() { SpringContextHolder.clearHolder(); } }
三、编写类监听事件
通过@EventListener(SysLogEvent.class)注解指定监听的时间
@Async注解异步执行事件
@RequiredArgsConstructor注解写在类上可以代替@AutoWired注解
需要注意的是在注入时需要用final定义,或者使用@notnull注解
@Slf4j @RequiredArgsConstructor @Component public class SysLogListener { private final SysLogMapper sysLogMapper; @Async @Order @EventListener(SysLogEvent.class) public void saveSysLog(SysLogEvent event) { SysLog sysLog = (SysLog) event.getSource(); sysLogMapper.insert(sysLog); } }
四、在controller中的方法上
加上@SysLogAnnotation注解就可以实现通过aop切面的方式来添加日志
@SysLogAnnotation("导出日志") @ApiOperation(value = "导出测试",notes = "导出测试") @GetMapping("export") public Object exportTest() { exportService.testExport(); return "success"; }
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。