SpringMVC项目中使用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类型,写上方法名。

  1. @LogAnnotation(description = "日志记录", bizID = 1)

  2. @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>
 

猜你喜欢

转载自blog.csdn.net/quliuwuyiz/article/details/86719649