一、首先系统引用以下依赖
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>net.minidev</groupId>
<artifactId>json-smart</artifactId>
<version>2.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
二、准备好表
CREATE TABLE `request_log` (
`id` int(9) NOT NULL AUTO_INCREMENT,
`status` varchar(2) DEFAULT NULL COMMENT '请求状态{0失败;1成功}',
`request` text CHARACTER SET utf8 COLLATE utf8_bin COMMENT '请求参数',
`response` text CHARACTER SET utf8 COLLATE utf8_bin COMMENT '返回参数',
`error` text CHARACTER SET utf8 COLLATE utf8_bin COMMENT '错误信息',
`type` varchar(20) DEFAULT NULL COMMENT '操作说明{30001增加;30002删除;30003修改}',
`method` varchar(20) DEFAULT NULL COMMENT '请求方式',
`created_by` varchar(32) DEFAULT NULL COMMENT '创建者',
`created_at` bigint(20) DEFAULT NULL COMMENT '创建时间',
`updated_by` varchar(32) DEFAULT NULL COMMENT '修改人',
`updated_at` bigint(20) DEFAULT NULL COMMENT '修改时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1 COMMENT='请求日志表';
三、开始正文
生成好实体类
/**
* <p>
* 请求日志表
* </p>
*
* @author LAZ
* @since 2019-10-09
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("request_log")
public class RequestLog implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
/**
* 请求结果标识
*/
private String status;
/**
* 请求参数
*/
private String request;
/**
* 返回参数
*/
private String response;
/**
* 错误信息
*/
private String error;
/**
* 操作说明{30001增加;30002删除;30003修改}
*/
private Integer type;
/**
* 请求方式
*/
private String method;
/**
* 创建人
*/
private String createdBy;
/**
* 创建时间
*/
private Long createdAt;
/**
* 更新人
*/
private String updatedBy;
/**
* 更新时间
*/
private Long updatedAt;
}
定义好一个枚举
/**
* @author laz
* @version 1.0
* @date 2019/10/9 10:31
*/
public enum LogType {
/**
* 应用-增加
*/
APP_ADD(30001),
/**
* 应用-删除
*/
APP_DELETE(30002),
/**
* 应用-修改
*/
APP_UPDATE(30003),
/**
* 部署-部署应用
*/
DEP_ADD(40001),
/**
* 部署-回滚应用
*/
DEP_ROLLBACK(40002);
private int value;
LogType(int value) {
this.value = value;
}
LogType(String value) {
for (LogType item : values()) {
if (item.name().equals(value)) {
this.value = item.value;
}
}
throw new IllegalArgumentException("Invalid type value");
}
public int value() {
return value;
}
public static LogType valueOf(int value) {
for (LogType item : values()) {
if (item.value() == value) {
return item;
}
}
throw new IllegalArgumentException("Invalid type value");
}
}
自定义一个注解
import java.lang.annotation.*;
/**
* 使用方式 @LogInfo(logType = LogType.APP_ADD)
* @author laz
* @version 1.0
* @date 2019/10/9 10:31
*/
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogInfo {
/**
* 描述
* @return
*/
public String description() default "";
/**
* 日志类型
* @return
*/
public LogType logType();
}
编写切面代码
package com.hnmqet.transdata.config;
import cn.hutool.core.util.ReflectUtil;
import com.hnmqet.framework.model.BasePageResult;
import com.hnmqet.transdata.common.Constant;
import com.hnmqet.transdata.entity.RequestLog;
import com.hnmqet.transdata.service.RequestLogService;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
/**
* @author laz
* @version 1.0
* @date 2019/10/9 10:31
*/
@Aspect
@Component
@Slf4j
@Order(1)
public class LogAop {
@Autowired
private RequestLogService requestLogService;
private ThreadLocal<RequestLog> threadLocal = new ThreadLocal<>();
//这个地方就是切点
//这个路径是你的自定义注解路径
@Pointcut("@annotation(com.hnmqet.transdata.config.LogInfo)")
public void controllerMethodPointcut() {
}
/**
* 前置advice
* @param point
*/
@Before("controllerMethodPointcut()")
public void before(JoinPoint point) {
RequestLog logEntity = new RequestLog();
//将当前实体保存到threadLocal
threadLocal.set(logEntity);
//获取连接点的方法签名对象,在该对象中可以获取到目标方法名,所属类的Class等信息
MethodSignature signature = (MethodSignature) point.getSignature();
//获取到该方法@LogInfo注解中的日志类型:枚举类LogType的值,保存到log实体中
logEntity.setType(signature.getMethod().getAnnotation(LogInfo.class).logType().value());
//RequestContextHolder:持有上下文的Request容器,获取到当前请求的request
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
HttpServletRequest httpServletRequest = sra.getRequest();
logEntity.setMethod(httpServletRequest.getMethod());
JSONObject jsonObject = new JSONObject();
//存储uri到json中
jsonObject.accumulate("uri", httpServletRequest.getRequestURI().toString());
//这一步获取到的方法有可能是代理方法也有可能是真实方法
Method m = ((MethodSignature) point.getSignature()).getMethod();
//判断代理对象本身是否是连接点所在的目标对象,不是的话就要通过反射重新获取真实方法
if (point.getThis().getClass() != point.getTarget().getClass()) {
m = ReflectUtil.getMethod(point.getTarget().getClass(), m.getName(), m.getParameterTypes());
}
//通过真实方法获取该方法的参数名称
LocalVariableTableParameterNameDiscoverer paramNames = new LocalVariableTableParameterNameDiscoverer();
String[] parameterNames = paramNames.getParameterNames(m);
//获取连接点方法运行时的入参列表
Object[] args = point.getArgs();
//将参数名称与入参值一一对应起来
Map<String, Object> params = new HashMap<>();
for (int i = 0; i < parameterNames.length; i++) {
params.put(parameterNames[i], args[i]);
}
jsonObject.accumulate("params", params);
//为log实体类的request字段赋值
logEntity.setRequest(jsonObject.toString());
System.out.println("============================ 》Before : " + logEntity.toString());
}
/**
* 方法成功return之后的advice
* @param point
* @param rtv
*/
@AfterReturning(value = "controllerMethodPointcut()", returning = "rtv")
public void after(JoinPoint point, Object rtv) {
//得到当前线程的log对象
RequestLog log = threadLocal.get();
//rtv为controller方法返回数据
JSONObject jsonObject = JSONObject.fromObject(rtv);
//为log实体的response字段赋值
log.setResponse(jsonObject.toString());
log.setStatus(Constant.REQUEST_SUCCESS);
//插入一条log信息
requestLogService.save(threadLocal.get());
//移除当前log实体
threadLocal.remove();
System.out.println("============================ 》AfterReturning : " + log.toString());
}
/**
* 报错之后的advice
* @param throwing
*/
@AfterThrowing(value = "controllerMethodPointcut()", throwing = "throwing")
public void error(Throwable throwing) {
RequestLog log = threadLocal.get();
log.setStatus(Constant.REQUEST_ERRORS);
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
//将报错信息写入error字段
throwing.printStackTrace(new PrintStream(byteArrayOutputStream));
log.setError(byteArrayOutputStream.toString());
} catch (IOException e) {
e.printStackTrace();
}
requestLogService.save(threadLocal.get());
threadLocal.remove();
System.out.println("============================ 》AfterThrowing : " + log.toString());
}
}
应用
在你需要记录日志的方法上添加这个注解就好了
成果
好了另外还需要添加什么字段都可以到上面进行添加