spring+aop+自定义注解实现操作日志记录
程序员文章站
2022-07-10 12:18:04
...
1,spring配置文件
<bean class="com.able.aop.LogAspect" id="logAspect"/> <aop:config> <aop:aspect id="serviceMonitor" ref="logAspect"> <aop:pointcut expression="execution(* com.able.controller.*.*(..))" id="servicePointcut" /> <aop:around method="doAroundMethodLog" pointcut-ref="servicePointcut"/> </aop:aspect> </aop:config>
2,日志拦截类
public class LogAspect { private static final Logger logger = LoggerFactory.getLogger(LogAspect.class); @Autowired private HttpServletRequest request; @Autowired private UserOperatLogService userOperatLogService; @Autowired private TokenService tokenService; /** * 标注该方法体为环绕通知,当目标方法执行时执行该方法体 */ public Object doAroundMethodLog(ProceedingJoinPoint jp) throws Throwable{ StopWatch stopWatch = new StopWatch(); //记录方法执行耗时 stopWatch.start(); Object retVal = null; try{ retVal = jp.proceed(); }catch (Throwable e){ e.printStackTrace(); logger.error(e.getMessage()); retVal = new ResponseEntity(new RestResult(e.getMessage(),false), HttpStatus.OK); }finally { stopWatch.stop(); insertOpertLog(jp, stopWatch); } return retVal; } private void insertOpertLog(ProceedingJoinPoint jp, StopWatch stopWatch) { Class<? extends Object> classD=jp.getTarget().getClass(); String className = classD.getName(); MethodSignature joinPointObject = (MethodSignature) jp.getSignature(); Method method = joinPointObject.getMethod(); String methodName = method.getName(); if(!jp.getTarget().getClass().isAnnotationPresent(NoLog.class)&&!method.isAnnotationPresent(NoLog.class)){ String params = parseParames(jp.getArgs()); //解析目标方法体的参数 UserOperatLog userOperatLog=new UserOperatLog(); userOperatLog.setIpAddr(request.getRemoteAddr()); userOperatLog.setActionUrl(request.getRequestURI()); userOperatLog.setTimeLong(stopWatch.getTotalTimeMillis()+""); ShiroUser shiroUser = (ShiroUser) SecurityUtils.getSubject().getPrincipal(); if(shiroUser!=null){ userOperatLog.setUserId(shiroUser.getZhsId()); userOperatLog.setUserName(shiroUser.getRealName()); }else{ String tokenCode=request.getParameter("tokenCode")==null?"":request.getParameter("tokenCode"); if(tokenCode!=null && !"".equals(tokenCode)){ Token token = new Token(); token.setTokenCode(tokenCode); List<Token> list =tokenService.selectBySelective(token); if(list != null && list.size() > 0){ token=list.get(0); userOperatLog.setUserId(token.getUserId()); userOperatLog.setUserName(token.getRealName()); } } } Function fd = null; Operate md = null; if(classD.isAnnotationPresent(Function.class)){ fd = classD.getAnnotation(Function.class); } if(method.isAnnotationPresent(Operate.class)){ md =method.getAnnotation(Operate.class); } if(fd!=null){ userOperatLog.setMean(fd.value()); userOperatLog.setModule(fd.moduleName()); userOperatLog.setSubModule(fd.subModuleName()); } if(md!=null){ userOperatLog.setFunction(md.value()); } userOperatLog.setParamData(params); userOperatLog.setCreateTime(DateUtil.getTimeStamp()); logger.info("业务处理"+",模块:["+(fd!=null?fd.moduleName():"")+"],操作:["+(md!=null?md.value():"")+"],调用类名称:["+className+"],调用方法名称:["+methodName+"],参数为:" + params + ";耗时" + stopWatch.getTotalTimeMillis() + "毫秒"); userOperatLogService.insertBySelective(userOperatLog); //userOperatLogService.testasy(); logger.info("执行完毕======="); } }
3,自定义注解三个
功能模块注解
/** * 每个类的功能描述 * @author zhangqh * @date 2016-8-2 下午01:03:59 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented public @interface Function { String value() default ""; String moduleName() default ""; String subModuleName() default ""; }
操作方法注解
/** * 方法描述 * @author zhangqh * @date 2016-8-2 下午12:55:25 */ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Operate { String value() default ""; }
不需要记录日志的注解
/** * 免记录日志注解标识 * @author wjhu * @date 2016-8-2 下午01:03:59 */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) @Documented public @interface NoLog { }
4,controller中记录操作日志的使用
/** * @Function注解为对应的操作日志模块 * @author zhangqh * */ @Controller @RequestMapping("/test") @Function(value ="测试模块",moduleName = "测试模块",subModuleName = "") public class test { /** * 会记录对应的操作说明 */ @Operate(value="操作") public void aa(){ } /** * 使用@NoLog注解就不是记录该方法的操作日志了 */ @NoLog public void bb(){ } }
提示:如果记录日志要持久化到数据库的话,建议入库操作加上异步操作这样对性能会提升不少
spring对异步调用方法支持也比较好 配置也比较简单,只需要要在配置文件中加入
<!-- 支持异步加载 --> <task:annotation-driven/>
就可以了,然后使用的方法上加上@Async就可以了