使用AOP 记录操作日志
- 最近在做后台管理系统,需要记录下操作日志到数据库
- 采用AOP 的方式来实现
- springboot + aop + mybatis
表设计与实体类
CREATE TABLE `sys_log` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '日志ID',
`username` varchar(50) DEFAULT NULL COMMENT '操作用户',
`operation` text COMMENT '操作内容',
`time` decimal(11,0) DEFAULT NULL COMMENT '耗时',
`method` text COMMENT '操作方法',
`params` text COMMENT '方法参数',
`ip` varchar(64) DEFAULT NULL COMMENT '操作者IP',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`location` varchar(50) DEFAULT NULL COMMENT '操作地点',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1842 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
@Data
@Table(name = "sys_log")
public class SysLog implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String username;
private String operation;
private Long time;
private String method;
private String params;
private String ip;
private Date createTime;
private String location;
}
AOP 实现
package com.xtardex.admin.cofig.data.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
String value() default "";
}
package com.xtardex.admin.cofig.data.aspectj;
import com.xtardex.admin.entity.SysLog;
import com.xtardex.admin.service.ISysLogService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Slf4j
@Aspect
@Component
public class LogAspect {
@Autowired
private ISysLogService logService;
@Pointcut("@annotation(com.xtardex.admin.cofig.data.annotation.Log)")
public void pointcut() {
}
@Around("pointcut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
Object result = null;
long beginTime = System.currentTimeMillis();
result = point.proceed();
HttpServletRequest request = HttpContextUtil.getHttpServletRequest();
String ip = IPUtil.getIpAddr(request);
long time = System.currentTimeMillis() - beginTime;
String username = "";
SysLog log = new SysLog();
log.setUsername(username);
log.setIp(ip);
log.setTime(time);
logService.saveLog(point, log);
return result;
}
}
@Service
public class SysLogServiceImpl implements ISysLogService {
@Autowired
private SysLogMapper logMapper;
@Autowired
ObjectMapper objectMapper;
@Override
public void saveLog(ProceedingJoinPoint joinPoint, SysLog log) throws JsonProcessingException {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
Log logAnnotation = method.getAnnotation(Log.class);
if (logAnnotation != null) {
log.setOperation(logAnnotation.value());
}
String className = joinPoint.getTarget().getClass().getName();
String methodName = signature.getName();
log.setMethod(className + "." + methodName + "()");
Object[] args = joinPoint.getArgs();
LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
String[] paramNames = u.getParameterNames(method);
if (args != null && paramNames != null) {
StringBuilder params = new StringBuilder();
params = handleParams(params, args, Arrays.asList(paramNames));
log.setParams(params.toString());
}
log.setCreateTime(new Date());
log.setLocation("");
logMapper.saveIgnoreNull(log);
}
private StringBuilder handleParams(StringBuilder params, Object[] args, List paramNames) throws JsonProcessingException {
for (int i = 0; i < args.length; i++) {
if (args[i] instanceof Map) {
Set set = ((Map) args[i]).keySet();
List<Object> list = new ArrayList<>();
List<Object> paramList = new ArrayList<>();
for (Object key : set) {
list.add(((Map) args[i]).get(key));
paramList.add(key);
}
return handleParams(params, list.toArray(), paramList);
} else {
if (args[i] instanceof Serializable) {
Class<?> aClass = args[i].getClass();
try {
aClass.getDeclaredMethod("toString", new Class[]{null});
params.append(" ").append(paramNames.get(i)).append(": ").append(objectMapper.writeValueAsString(args[i]));
} catch (NoSuchMethodException e) {
params.append(" ").append(paramNames.get(i)).append(": ").append(objectMapper.writeValueAsString(args[i].toString()));
}
} else if (args[i] instanceof MultipartFile) {
MultipartFile file = (MultipartFile) args[i];
params.append(" ").append(paramNames.get(i)).append(": ").append(file.getName());
} else {
params.append(" ").append(paramNames.get(i)).append(": ").append(args[i]);
}
}
}
return params;
}
}
使用到的工具类
package com.xtardex.admin.common.utils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Objects;
public class HttpContextUtil {
private HttpContextUtil(){
}
public static HttpServletRequest getHttpServletRequest() {
return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
}
}
package com.xtardex.admin.common.utils;
import javax.servlet.http.HttpServletRequest;
public class IPUtil {
private static final String UNKNOWN = "unknown";
protected IPUtil(){
}
public static String getIpAddr(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
}
}
注意
- 我采用的是fastmybatis, 所以mapper 实现与 mybatis 有点不同,入库操作不一样