使用Spring AOP 来记录用户操作日志并存储到数据库中

之前要做一个记录用户操作的日志记录,找了很多方法,最后选择使用spring AOP来实现。由于是要记录用户操作的日志,所以我使用的是返回通知(@AfterReturning),只有在前端调用了我后端的接口并成功返回,才调用我的切面方法记录用户的操作存储到数据库中。

LogAnnotation.java

import java.lang.annotation.ElementType;  
import java.lang.annotation.Retention;  
import java.lang.annotation.RetentionPolicy;  
import java.lang.annotation.Target;

import org.springframework.data.mongodb.core.mapping.Document; 

/**
 * 日志
 * @author **
 *
 */
@Target({ElementType.PARAMETER,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Document
public @interface LogAnnotation {
	
    /** 日志描述 */
    String description() default "";
 
    /** 业务类型 */
    int bizID();
} 

切面类

LogAspect.java

@Aspect
@Component
@SuppressWarnings({ "unchecked", "unused", "rawtypes" })
public class LogAspect {
	// 注入service,用来将日志信息保存在数据库 这是我的service,你只需要注入你自己的service就行
	@Resource
	private OprLogDaoService oprLogDaoService;

    //在**处填入你的LogAnnotation所在的包
    //此代码是拦截所有使用了LogAnnotation注解的接口
	@Pointcut("@annotation(**.LogAnnotation)")
	// 定义一个切点
	private void accAspect() {
	}

    //返回通知
    @AfterReturning(pointcut= "accAspect()",returning="result")
	public void around(JoinPoint joinPoint, Object result) throws Throwable {

		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
				.getRequest();
		String classType = joinPoint.getTarget().getClass().getName();
		Class<?> clazz = Class.forName(classType);
		String clazzName = clazz.getName();
		// 拦截的方法名称。当前正在执行的方法
		String methodName = joinPoint.getSignature().getName();
		// 获取方法的参数
		Object[] args = joinPoint.getArgs();
		

		// 获取传入参数的键值对
		Map<String, Object> map = (Map<String, Object>)         
        LogUtil.getFieldsName(this.getClass(), clazzName, methodName,
				args);
		// 将request中的参数转化为键值对,方便取出
		Map<String, Object> map2 = (Map<String, Object>) map.get("request");
		String resultArgs = result.toString();
		// 获取返回方法的参数
		JSONObject jasonObject = JSONObject.fromObject(resultArgs);
		Map mapResult = (Map) jasonObject;
		//将返回的result参数取出
		Map<String, Object> res = (Map<String, Object>) mapResult.get("result");
        //这样传入的参数和返回的参数都已变成Map对象
        //通过直接 .get("字段名")的方式将对应的字段值取出
        //比如取出用户的用户名ID
        Integer userID = (Integer) mapResult.get("userID");
		
			// 常见日志实体对象
			OprLog oprLog = new OprLog();
            
            //根据自己定义的实体类的属性将数据填入
            OprLog.setUserID(userID);
            OprLog.set...();        
			// 保存进数据库
            //开头定义的service,这边使用你自己的service就行了
			oprLogDaoService.addLog(oprLog);
		
	}

接下来就是在controller上添加注解了

只需要在接口上添加注解@LogAnnotation(description = "日志记录", bizID = 1)  bizID是我自己定义的你也可以定义成String类型,写上方法名。

@LogAnnotation(description = "日志记录", bizID = 1)
@RequestMapping(value = "/Test", method = RequestMethod.POST)

获取自定义注解内容的方法

可以直接在注解上写用户的操作内容(修改、添加之类的)

/**
	 * 获取注解内容
	 * @param joinPoint
	 * @return
	 * @throws Exception
	 */
	public static Integer getMthodRemark(JoinPoint joinPoint)  
            throws Exception {  
        String targetName = joinPoint.getTarget().getClass().getName();  
        String methodName = joinPoint.getSignature().getName();  
        Object[] arguments = joinPoint.getArgs();  
  
		Class targetClass = Class.forName(targetName);
		Method[] method = targetClass.getMethods();
		Integer bizId = null;//此处可以根据你想要的类型来修改
		for (Method m : method) {  
            if (m.getName().equals(methodName)) {  
                Class[] tmpCs = m.getParameterTypes();  
                if (tmpCs.length == arguments.length) {  
                    ControllerLogAnnotation cla = m.getAnnotation(ControllerLogAnnotation.class);  
                    if (cla != null) {  
                        bizId = cla.bizID();  
                    }  
                    break;  
                }  
            }  
        }  
        return bizId;  
    }  
}

另外还有一些工具类的方法

这个是转换成map对象的方法

	public static Map<String, Object> getFieldsName(Class cls, String clazzName, String methodName, Object[] args)throws Exception {
		Map<String, Object> map = new HashMap<String, Object>();

		ClassPool pool = ClassPool.getDefault();
		ClassClassPath classPath = new ClassClassPath(cls);
		pool.insertClassPath(classPath);

		CtClass cc = pool.get(clazzName);
		CtMethod cm = cc.getDeclaredMethod(methodName);
		MethodInfo methodInfo = cm.getMethodInfo();
		CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
		LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
		if (attr == null) {
			// exception
		}
		int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;
		for (int i = 0; i < cm.getParameterTypes().length; i++) {
			map.put(attr.variableName(i + pos), args[i]);// paramNames即参数名
		}
		return map;
	}

最后在springMVCxml中加入

<context:component-scan
        //LogAspect 在aop中
		base-package="切面所在的包例如(a.b.aop)"></context:component-scan>

	<aop:aspectj-autoproxy expose-proxy="true"></aop:aspectj-autoproxy>

另外还有一些依赖的jar包,需要的jar包都可以在百度中搜索到,用的时候没有可以在百度查询jar包依赖,放在maven项目中的pom.xml文件中。

猜你喜欢

转载自blog.csdn.net/qq_33322856/article/details/82217837