需求
- 对系统请求的敏感数据做记录
- 记录操作类型 如"更新","修改"
- 记录关键值
- 记录操作人
思路
基于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
@Component
public 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;
}
}
总结
代码略显简陋,仅提供了基本实现