使用Spring AOP自定义注解方式实现用户操作日志记录

版权声明:本文由施勇原创,转载请注明作者和出处! https://blog.csdn.net/shiyong1949/article/details/82936377

1,开发环境
操作系统:Windows 7
JDK:1.8.0_161
Eclipse:Mars.2 Release (4.5.2)

2,自定义注解类UserLog

@Target({ElementType.PARAMETER, ElementType.METHOD})  
@Retention(RetentionPolicy.RUNTIME)  
@Documented
public @interface UserLog {
	
	/** 要执行的操作内容比如:用户:XXX登录成功 **/
	public String operationContent() default "";
}

3,日志处理切面UserLogAspect
这里使用的是后通知,当业务代码执行完成后,再执行日志保存。

@Aspect
@Component
public class UserLogAspect {

	@Autowired
	private ILogSysUserService logSysUserService;
	
	//Controller层切点  
	@Pointcut("@annotation(com.riskraider.common.annotation.UserLog)")
	public void controllerAspect() {
		
	}
	
	/** 
	 * 前置通知 用于拦截Controller层记录用户的操作 
	 * 
	 * @param joinPoint 切点 
	 */ 
	@SuppressWarnings("rawtypes")
	@After("controllerAspect()")
	public void doAfter(JoinPoint joinPoint) {
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
		
		HttpSession session = request.getSession();
		
		//读取session中的用户
		SysAccount account = (SysAccount) session.getAttribute("account");
		
		if(null != account){
			//获取请求ip
			String ip = request.getRemoteAddr();
			
			try{
				String targetName = joinPoint.getTarget().getClass().getName();
				String methodName = joinPoint.getSignature().getName();
				Object[] arguments = joinPoint.getArgs();
				Class targetClass = Class.forName(targetName);
				Method[] methods = targetClass.getMethods();
				String operationUrl = request.getServletPath();
				String operationContent = "";
				
				for (Method method : methods) {
					if (method.getName().equals(methodName)) {
						Class[] clazzs = method.getParameterTypes();
						
						if (clazzs.length == arguments.length) {
							//凡是加了UserLog注解的方法都记录日志
							if(null != method.getAnnotation(UserLog.class)){
								operationContent = method.getAnnotation(UserLog.class).operationContent();
								
								//获取用户请求方法的参数并序列化为JSON格式字符串    
								Map<String,Object> nameAndArgs = null;
						        
						        if(null != joinPoint.getArgs() && joinPoint.getArgs().length > 0) {
						        	//获取参数名称和值  
							        nameAndArgs = getParameMap(joinPoint);
						        }
								
						        SysUserLogDTO log = new SysUserLogDTO();
								log.setUserId(account.getAccountId());
								log.setUserName(account.getName());
								log.setUserIp(ip);
								log.setOperationUrl(operationUrl);
								log.setOperationContent(operationContent);
								log.setParameMap(nameAndArgs);
								
								logSysUserService.saveSysUserLog(log);
								
								break;
							}
						}
					}
				}
			}catch(Exception e) {
				LoggerUtils.error("记录用户操作日志失败!", e);
			}
		}
	}
	
	/**
	 * @Title: getParameMap
	 * @Description: 获取参数的名称和值
	 * @author: 施勇
	 * @date: 2018年10月3日 下午3:12:26
	 * @param: @param joinPoint
	 * @param: @return
	 * @return: Map<String,Object>
	 * @throws
	 */
	public Map<String,Object> getParameMap(JoinPoint joinPoint){
		Map<String, Object> map = new HashMap<String, Object>();
		
		Object[] args = joinPoint.getArgs(); // 参数值
        String[] argNames = ((MethodSignature)joinPoint.getSignature()).getParameterNames(); // 参数名
		
        for(int i=0;i<argNames.length;i++){
        	if("response".equals(argNames[i]) || "request".equals(argNames[i]) || "pwd".equals(argNames[i])){
        		continue;
        	}else{
        		map.put(argNames[i], args[i]);
        	}
        }
        
		return map;
	}
	
}

getParameMap()这个方法是用于获取用户请求中的参数,只需要保存业务相关的参数就可以了,所以将request和response过滤掉了,同时也不保存用户登录时的密码。对这个参数Map在保存到数据库中的时候可以转换成JSONString,这样方便查看。

4,使用注解
在需要记录日志的地方加上注解

	@RequestMapping("/doLogin")
	@ResponseBody
	@UserLog(operationContent="登录系统")
	public ResultBean doLogin(String loginName, String pwd, HttpServletRequest request,HttpServletResponse response){
	
}

这里重点是AOP切面保存用户操作日志,其他AOP相关配置就不重复说了。

猜你喜欢

转载自blog.csdn.net/shiyong1949/article/details/82936377