欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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就可以了