目录
1、引入依赖
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<scope>test</scope>
</dependency>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
2、切面方法
切面方法说明如下:
@Aspect | 作用是把当前类标识为一个切面供容器读取 |
@Pointcut | (切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式 |
@Before | 标识一个前置增强方法,相当于BeforeAdvice的功能 |
@AfterReturning | 后置增强,相当于AfterReturningAdvice,方法退出时执行 |
@AfterThrowing | 异常抛出增强,相当于ThrowsAdvice |
@After | final增强,不管是抛出异常或者正常退出都会执行 |
@Around | 环绕增强,相当于MethodInterceptor |
3、Log类
package com.shucha.deveiface.biz.aspect;
import java.lang.annotation.*;
/**
* @author tqf
* @Description 自定义拦截日志
* @Version 1.0
* @since 2022-08-08 15:28
*/
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
/**
* 操作描述 查询、新增、修改、删除等
* @return
*/
String menu() default "";
/**
* 接口名称 不需要填写 可以通过request.getRequestURL().toString(); 获取
* @return
*/
String operation() default "";
/**
* 是否记录请求参数数据, 默认true: 记录; false:不记录
*
* @return
*/
boolean isData() default true;
}
4、LogAspect类
package com.shucha.deveiface.biz.aspect;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.sdy.common.model.Response;
import com.sdy.mvc.controller.BaseController;
import com.sdy.mvc.utils.HttpUtil;
import com.shucha.deveiface.biz.model.SysLog;
import com.shucha.deveiface.biz.service.SysLogService;
import feign.Request;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
/**
* @author tqf
* @Description 日志切面类
* @Version 1.0
* @since 2022-08-08 15:28
*/
@Aspect
@Component
@Slf4j
@Order(1)
public class LogAspect {
@Autowired
private SysLogService sysLogService;
private final ThreadLocal<Long> startTime = new ThreadLocal<>();
// 配置织入点
@Pointcut("@annotation(Log)")
public void logPointCut() {
}
@Before("logPointCut()")
private void before() {
startTime.set( System.currentTimeMillis());
}
/**
* 处理完请求后执行
* @param joinPoint
* @param res
* @throws Exception
*/
@AfterReturning(returning = "res", pointcut = "logPointCut()")
public void afterReturning(JoinPoint joinPoint, Response res) throws Exception {
long nowTime = System.currentTimeMillis();
HttpServletRequest request = getRequest();
handleLog(joinPoint, null, res, nowTime, request);
}
/**
* 拦截异常操作
* @param joinPoint 切点
* @param e 异常
*/
@AfterThrowing(value = "logPointCut()", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, Exception e) throws Exception {
// 从上下文中获取reqeust
ServletRequestAttributes servletRequestAttributes =
(ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
// HttpServletRequest request = getRequest();
HttpServletRequest request = servletRequestAttributes.getRequest();
handleLog(joinPoint, e, null, System.currentTimeMillis(), request);
}
protected void handleLog(final JoinPoint joinPoint, final Exception e, Response jsonResult, Long nowTime, HttpServletRequest request) throws Exception {
Log controllerLog = getAnnotationLog(joinPoint);
ProceedingJoinPoint point = (ProceedingJoinPoint)joinPoint;
if (controllerLog == null) {
return;
}
// 数据库日志
SysLog sysLog = new SysLog();
// 接口地址
String requestUrl = request.getRequestURL().toString();
// 请求的IP地址
String ip = HttpUtil.getIpAddr(request);
sysLog.setIp(ip);
// 获取操作内容
String content = controllerLog.menu();
// 获取请求参数
String requestData = "";
if(controllerLog.isData()){
requestData = getRequestParams(point,request);
}
if (jsonResult == null) {
content = content + "--出现服务异常!";
}
if (jsonResult != null && !jsonResult.getSuccess()) {
content = content + "--执行失败!";
}
sysLog.setContent(content)
.setType(content)
.setCreateTime(new Date())
.setRequestUrl(requestUrl)
.setRequestData(requestData);
// 保存数据库
sysLogService.save(sysLog);
}
/**
* 是否存在注解,如果存在就获取
*/
private Log getAnnotationLog(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if (method != null) {
return method.getAnnotation(Log.class);
}
return null;
}
private HttpServletRequest getRequest() {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
return attributes.getRequest();
}
/**
* 获取请求参数 json格式返回
* @param request
* @return
*/
private String getParameterName(HttpServletRequest request){
// 增加查询日志 获取所有查询的参数名称和值 json格式存储
Map map = new HashMap();
Enumeration paramNames = request.getParameterNames();
while (paramNames.hasMoreElements()) {
String paramName = (String) paramNames.nextElement();
String[] paramValues = request.getParameterValues(paramName);
if (paramValues.length == 1) {
String paramValue = paramValues[0];
if (paramValue.length() != 0) {
map.put(paramName, paramValue);
}
}
}
return JSON.toJSONString(map);
}
/**
* 获取请求参数
* @param request
* @return
*/
public String getRequestParams(ProceedingJoinPoint point, HttpServletRequest request) {
MethodSignature methodSignature = (MethodSignature)point.getSignature();
Method method = methodSignature.getMethod();
String queryString = null;
String requestMethod = request.getMethod();
if (requestMethod.equals(Request.HttpMethod.POST.name())) {
//参数值
Object[] args = ArrayUtils.toArray(point.getArgs());
queryString = JSON.toJSONString(args[0], SerializerFeature.WriteMapNullValue);
}
else {
// 增加查询日志 获取所有查询的参数名称和值 json格式存储
Map map = new HashMap();
Enumeration paramNames = request.getParameterNames();
while (paramNames.hasMoreElements()) {
String paramName = (String) paramNames.nextElement();
String[] paramValues = request.getParameterValues(paramName);
if (paramValues.length == 1) {
String paramValue = paramValues[0];
if (paramValue.length() != 0) {
map.put(paramName, paramValue);
}
}
}
queryString = JSON.toJSONString(map);
}
return queryString;
}
}
5、SysLog实体类
package com.shucha.deveiface.biz.model;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.sdy.common.model.BaseModel;
import com.sdy.common.utils.DateUtil;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.util.Date;
/**
* <p>
* 用户操作日志
* </p>
*
* @author tqf
* @since 2022-08-08 15:25
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
public class SysLog extends BaseModel {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@ApiModelProperty(value = "主键")
@TableId
private Long id;
/**
* 操作用户id
*/
@ApiModelProperty(value = "操作用户id")
private Long userId;
@ApiModelProperty(value = "请求参数")
private String requestData;
@ApiModelProperty(value = "请求接口地址")
private String requestUrl;
/**
* IP地址
*/
@ApiModelProperty(value = "IP地址")
private String ip;
/**
* 操作内容
*/
@ApiModelProperty(value = "操作内容")
private String content;
/**
* 操作类型
*/
@ApiModelProperty(value = "操作类型")
private String type;
/**
* 创建时间
*/
@ApiModelProperty(value = "创建时间")
@JsonFormat(pattern = DateUtil.DATETIME_FORMAT)
private Date createTime;
}
创建表和插入数据
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for sys_log
-- ----------------------------
DROP TABLE IF EXISTS `sys_log`;
CREATE TABLE `sys_log` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`user_id` int(11) NULL DEFAULT NULL COMMENT '操作用户id',
`ip` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT 'IP地址',
`content` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '操作内容',
`request_url` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '请求接口地址',
`request_data` longtext CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL COMMENT '请求参数',
`type` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '操作类型\r\n0:登陆\r\n1:新增用户\r\n2:开户\r\n3:用户基本信息编辑\r\n4:用户资源编辑\r\n5:新增角色\r\n6编辑角色\r\n7:角色权限编辑\r\n8:角色关联用户编辑\r\n9:新增菜单\r\n10:菜单编辑\r\n11:日志查询',
`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_user_id`(`user_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_unicode_ci COMMENT = '操作日志信息' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of sys_log
-- ----------------------------
INSERT INTO `sys_log` VALUES (1, NULL, '192.168.0.111', '查询数据', 'http://192.168.0.111:50041/test/getData', '{}', '查询数据', '2022-08-08 17:21:51');
INSERT INTO `sys_log` VALUES (2, NULL, '192.168.0.111', '新增数据发发发', NULL, NULL, NULL, NULL);
INSERT INTO `sys_log` VALUES (3, NULL, '192.168.0.111', '新增数据', 'http://192.168.0.111:50041/test/saveData', '{\"content\":\"新增数据发发发\",\"createTime\":null,\"id\":2,\"ip\":\"192.168.0.111\",\"requestData\":null,\"requestUrl\":null,\"type\":null,\"userId\":null}', '新增数据', '2022-08-08 17:22:12');
SET FOREIGN_KEY_CHECKS = 1;
6、服务类和服务实现类
package com.shucha.deveiface.biz.service;
import com.sdy.mvc.service.BaseService;
import com.shucha.deveiface.biz.model.SysLog;
/**
* <p>
* 用户操作日志 服务类
* </p>
*
* @author cgj
* @since 2021-07-13
*/
public interface SysLogService extends BaseService<SysLog> {
}
package com.shucha.deveiface.biz.service.impl;
import com.sdy.mvc.service.impl.BaseServiceImpl;
import com.shucha.deveiface.biz.mapper.SysLogMapper;
import com.shucha.deveiface.biz.model.SysLog;
import com.shucha.deveiface.biz.service.SysLogService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* <p>
* 用户操作日志 服务实现类
* </p>
*
* @author cgj
* @since 2021-07-13
*/
@Slf4j
@Service
public class SysLogServiceImpl extends BaseServiceImpl<SysLog> implements SysLogService {
@Autowired
private SysLogMapper sysLogMapper;
}
7、实际调用
package com.shucha.deveiface.web.controller;
import com.sdy.common.model.Response;
import com.shucha.deveiface.biz.aspect.Log;
import com.shucha.deveiface.biz.model.SysLog;
import com.shucha.deveiface.biz.service.SysLogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* @author tqf
* @Description
* @Version 1.0
* @since 2022-08-08 15:23
*/
@RestController
@RequestMapping("/test")
public class TestController {
@Autowired
private SysLogService logService;
@Log(menu = "查询数据")
@GetMapping("/getData")
public Response test(){
return Response.success("请求成功");
}
@Log(menu = "新增数据")
@PostMapping("/saveData")
public Response saveData(@RequestBody SysLog sysLog){
logService.save(sysLog);
return Response.success();
}
}