需求
- 对系统请求的敏感数据做记录
- 记录操作类型 如"更新","修改"
- 记录关键值
- 记录操作人
思路
基于AOP对controller方法进行操作,判断该controller方法是不是需要记录的操作类型;然后对方法参数进行筛选,记录参数中符合要求的关键值
实现
基于Spring boot aop做了实现
通过注解标注方法,参数,属性
自定义注解
import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * 用来判断该方法是否进行日志记录 * Created by xuchonggao on 2017/2/21. */@Target({ElementType.METHOD, ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER})@Retention(RetentionPolicy.RUNTIME)public @interface LogAble { String value(); //操作对象名称,操作类型 或者字段对应的名称}
定义AOP类,进行操作
import com.jockiller.logable.annotion.LogAble;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.Signature;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.reflect.MethodSignature;import org.springframework.stereotype.Component;import org.springframework.util.StringUtils;import javax.servlet.http.HttpServletRequest;import java.lang.annotation.Annotation;import java.lang.reflect.Field;import java.lang.reflect.Method;/** * Created by jockiller on 2017/2/25. */@Aspect@Componentpublic abstract class LogInterceptor { @Around("@annotation(logAble)") Object saveLog(ProceedingJoinPoint point, LogAble logAble) throws Throwable { StringBuffer accessContent = new StringBuffer(); long userId = 0; HttpServletRequest request = null; Signature signature = point.getSignature(); try { MethodSignature methodSignature = (MethodSignature) signature; Method targetMethod = methodSignature.getMethod(); Annotation[][] paramAnnotions = targetMethod.getParameterAnnotations(); String paramAnno = null; Class clazz; Object requestArg; LogAble classLog; for (int i = 0; i < point.getArgs().length; i++) { requestArg = point.getArgs()[i]; paramAnno = isLogAbleParam(paramAnnotions, i); if (requestArg == null && paramAnno == null) { continue; } else if (requestArg != null) { clazz = requestArg.getClass(); if (requestArg instanceof HttpServletRequest) { request = (HttpServletRequest) requestArg; userId = getUserId(request); } else if (clazz.isAnnotationPresent(LogAble.class)) { classLog = (LogAble) clazz.getAnnotation(LogAble.class); accessContent.append("--").append(classLog.value()).append("["); for (Field field : clazz.getDeclaredFields()) { if (field.isAnnotationPresent(LogAble.class)) { LogAble fieldLog = (LogAble) field.getAnnotation(LogAble.class); if (fieldLog != null) { field.setAccessible(true); Object val = field.get(requestArg); accessContent.append("--").append(fieldLog.value()).append(":").append(val == null ? null : val.toString()); } } } accessContent.append("]"); } else if (!StringUtils.isEmpty(paramAnno)) { accessContent.append("--").append(paramAnno).append('[').append(requestArg.toString()).append(']'); } } else { accessContent.append("--").append(paramAnno).append('[').append(']'); } } if (userId <= 0) { throw new RuntimeException("没有获取到用户信息,请确保controller方法有HttpServletRequest参数,并且用户已经登录"); } } catch (Exception e) { //保证日志处理不影响正常业务 //TODO 需要自己对异常进行处理 if (e instanceof RuntimeException) { throw e; } else { System.out.println("处理操作日志出错"); } } Object proceed = point.proceed(); if (doSave(proceed)) { saveLog(accessContent, userId, getRequestIp(request)); } return proceed; } /** * 判断参数是否被@LogAble修饰 * * @param annotations * @param paramIndex * @return 返回LogAble的value */ String isLogAbleParam(Annotation[][] annotations, int paramIndex) { assert annotations.length > paramIndex; String res = null; for (Annotation anno : annotations[paramIndex]) { if (anno instanceof LogAble) { res = ((LogAble) anno).value(); break; } } return res; } /** * 获取操作人Id的方法 * * @param request * @return */ public abstract long getUserId(HttpServletRequest request); /** * 获取真实访问IP的方法 * * @param request * @return */ public abstract String getRequestIp(HttpServletRequest request); /** * 进行保存日志的方法 * * @param saveparam */ public abstract void saveLog(Object... saveparam); /** * 根据执行结果或者参数准备情况判断是否保存日志 * * @param logObj * @return */ public abstract boolean doSave(Object logObj);}
demo
@RequestMapping("/save") @LogAble("保存") public String saveTT(TestLog log, String abc, HttpServletRequest request,@LogAble("小白") String name) { return "aaa"; }
package com.test.domain;import com.jockiller.logable.annotion.LogAble;/** * 用来测试的类 * Created by jockiller on 2017/2/25. */@LogAble("雷锋兔")public class TestLog { @LogAble("名字") private String name; private String desc; public TestLog() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; }}
总结
代码略显简陋,仅提供了基本实现