目录
  • 一、首先自定义注解类SysLogAnnotation
  • 二、添加切面类SysLogAspect,实现同一的日志添加
    • 1、使用@Aspect注解定义切面类
    • 2、通过继承ApplicationEvent
    • 3、通过实现ApplicationContextAware接口
  • 三、编写类监听事件
    • 四、在controller中的方法上
      • 总结

        一、首先自定义注解类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";
            }
        

        总结

        以上为个人经验,希望能给大家一个参考,也希望大家多多支持。

        声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。