找回密码
 立即注册
首页 业界区 安全 记录用户业务请求日志

记录用户业务请求日志

敛饺乖 2025-9-24 11:03:49
在用户的一般使用的时候,对于很多操作类型的接口,为了后面便于追查问题,需要记录用户的请求日志。
用户的请求日志目前主流的存储方式有:

  • 日志文件
  • 数据库
  • MongoDB
  • ElasticSearch
在商城的项目中暂时存放在MySQL中了。
增加注解

增加专门的注解标识哪些是需要记录用户日志的。
注解就叫BizLog注解:
  1. @Target(ElementType.METHOD)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. public @interface BizLog {
  4.     String value() default "";
  5. }
复制代码
其中的value参数,用来接收用户自定义的日志描述。
后面只要有接口打上了这个注解,就会自动将用户的业务请求日志记录到数据库中。
增加业务日志表

为了方便后续追溯用户的请求行为,将用户的业务请求日志记录到数据库的某一张表中。
这样以后就可以通过这张表查询数据了。
  1. CREATE TABLE `biz_log` (
  2.   `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ID',
  3.   `method_name` varchar(30) NOT NULL COMMENT '方法名称',
  4.   `description` varchar(30) NOT NULL COMMENT '描述',
  5.   `request_ip` varchar(15) NOT NULL COMMENT '请求ip',
  6.   `browser` varchar(200)  NULL COMMENT '浏览器',
  7.   `url` varchar(100) NOT NULL COMMENT '请求地址',
  8.   `param` varchar(300)  NULL COMMENT '请求参数',
  9.   `time` int NOT NULL COMMENT '耗时,毫秒级',
  10.   `exception` varchar(300)  NULL COMMENT '异常',
  11.   `status` tinyint(1) NOT NULL DEFAULT 1 COMMENT '状态 1:成功 0:失败',
  12.   `create_user_id` bigint NOT NULL COMMENT '创建人ID',
  13.   `create_user_name` varchar(30) NOT NULL COMMENT '创建人名称',
  14.   `create_time` datetime(3) DEFAULT NULL COMMENT '创建日期',
  15.   `update_user_id` bigint DEFAULT NULL COMMENT '修改人ID',
  16.   `update_user_name` varchar(30)  DEFAULT NULL COMMENT '修改人名称',
  17.   `update_time` datetime(3) DEFAULT NULL COMMENT '修改时间',
  18.   `is_del` tinyint(1) DEFAULT '0' COMMENT '是否删除 1:已删除 0:未删除',
  19.   PRIMARY KEY (`id`) USING BTREE
  20. ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='业务日志表';
复制代码
增加业务日志拦截器
  1. package com.kailong.interceptor;
  2. import cn.hutool.http.useragent.UserAgent;
  3. import cn.hutool.http.useragent.UserAgentUtil;
  4. import com.kailong.annotation.BizLog;
  5. import com.kailong.entity.log.BizLogEntity;
  6. import com.kailong.service.log.BizLogService;
  7. import com.kailong.util.IpUtil;
  8. import org.aspectj.lang.JoinPoint;
  9. import org.aspectj.lang.ProceedingJoinPoint;
  10. import org.aspectj.lang.annotation.AfterThrowing;
  11. import org.aspectj.lang.annotation.Around;
  12. import org.aspectj.lang.annotation.Aspect;
  13. import org.aspectj.lang.annotation.Pointcut;
  14. import org.aspectj.lang.reflect.MethodSignature;
  15. import org.springframework.beans.factory.annotation.Autowired;
  16. import org.springframework.stereotype.Component;
  17. import org.springframework.web.context.request.RequestContextHolder;
  18. import org.springframework.web.context.request.ServletRequestAttributes;
  19. import javax.servlet.http.HttpServletRequest;
  20. import java.lang.reflect.Method;
  21. @Aspect
  22. @Component
  23. public class BizLogAspect {
  24.     @Autowired
  25.     private BizLogService bizLogService;
  26.     @Pointcut("@annotation(com.kailong.annotation.BizLog)")
  27.     public void pointcut() {
  28.     }
  29.     @Around("pointcut()")
  30.     public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
  31.         long startTime = System.currentTimeMillis();
  32.         HttpServletRequest httpServletRequest = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
  33.                 .getRequest();
  34.         Object result = joinPoint.proceed();
  35.         long time = System.currentTimeMillis() - startTime;
  36.         BizLogEntity bizLogEntity = createBizLogEntity(joinPoint, httpServletRequest);
  37.         bizLogEntity.setTime((int) time);
  38.         bizLogEntity.setStatus(1);
  39.         bizLogService.save(bizLogEntity);
  40.         return result;
  41.     }
  42.     private String getParam(JoinPoint joinPoint) {
  43.         StringBuilder params = new StringBuilder("{");
  44.         Object[] argValues = joinPoint.getArgs();
  45.         String[] argNames = ((MethodSignature) joinPoint.getSignature()).getParameterNames();
  46.         if (argValues != null) {
  47.             for (int i = 0; i < argValues.length; i++) {
  48.                 params.append(" ").append(argNames[i]).append(": ").append(argValues[i]);
  49.             }
  50.         }
  51.         return params.append("}").toString();
  52.     }
  53.     private BizLogEntity createBizLogEntity(JoinPoint joinPoint, HttpServletRequest httpServletRequest) {
  54.         MethodSignature signature = (MethodSignature) joinPoint.getSignature();
  55.         Method method = signature.getMethod();
  56.         BizLog bizLog = method.getAnnotation(BizLog.class);
  57.         String methodName = joinPoint.getTarget().getClass().getName() + "." + signature.getName();
  58.         BizLogEntity bizLogEntity = new BizLogEntity();
  59.         bizLogEntity.setDescription(bizLog.value());
  60.         bizLogEntity.setMethodName(methodName);
  61.         bizLogEntity.setStatus(1);
  62.         bizLogEntity.setRequestIp(IpUtil.getIpAddr(httpServletRequest));
  63.         bizLogEntity.setUrl(httpServletRequest.getRequestURI());
  64.         bizLogEntity.setBrowser(getBrowserName(httpServletRequest));
  65.         bizLogEntity.setParam(getParam(joinPoint));
  66.         return bizLogEntity;
  67.     }
  68.     @AfterThrowing(pointcut = "pointcut()", throwing = "e")
  69.     public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
  70.         HttpServletRequest httpServletRequest = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
  71.                 .getRequest();
  72.         BizLogEntity bizLogEntity = createBizLogEntity(joinPoint, httpServletRequest);
  73.         bizLogEntity.setStatus(0);
  74.         bizLogEntity.setException(e.getMessage());
  75.         bizLogService.save(bizLogEntity);
  76.     }
  77.     private String getBrowserName(HttpServletRequest httpServletRequest) {
  78.         String userAgentString = httpServletRequest.getHeader("User-Agent");
  79.         UserAgent ua = UserAgentUtil.parse(userAgentString);
  80.         return ua.getBrowser().toString();
  81.     }
  82. }
复制代码
这个拦截器会记录用户业务请求的ip、地址、参数、浏览器和接口耗时都数据。
如果用户业务请求失败了,也会记录一条失败的数据。
BizLog相关类

(基础设置,实际项目需修改)
BizLogEntity
  1. package com.kailong.entity.log;
  2. /**
  3. * created by kailong on 2025/9/23
  4. */
  5. import com.baomidou.mybatisplus.annotation.IdType;
  6. import com.baomidou.mybatisplus.annotation.TableId;
  7. import com.baomidou.mybatisplus.annotation.TableName;
  8. import com.kailong.entity.BaseEntity;
  9. import io.swagger.v3.oas.annotations.media.Schema;
  10. import lombok.AllArgsConstructor;
  11. import lombok.Data;
  12. import lombok.NoArgsConstructor;
  13. import java.io.Serializable;
  14. import java.util.Date;
  15. /**
  16. * 业务日志实体类
  17. * 对应表:biz_log
  18. */
  19. @Data
  20. @NoArgsConstructor
  21. @AllArgsConstructor
  22. @TableName("biz_log") // 指定MyBatis-Plus对应的表名
  23. @Schema(description = "业务日志实体类,用于记录系统业务操作日志") // Swagger3类级别描述
  24. public class BizLogEntity extends BaseEntity implements Serializable {//可以不继承BaseEntity
  25.     private static final long serialVersionUID = 1L;
  26.     /**
  27.      * 日志ID(主键,自增)
  28.      */
  29.     @TableId(value = "id", type = IdType.AUTO) // MyBatis-Plus主键注解,指定自增策略
  30.     @Schema(description = "日志ID", example = "1") // Swagger3字段描述+示例值
  31.     private Long id;
  32.     /**
  33.      * 方法名称(记录调用的业务方法名)
  34.      */
  35.     @Schema(description = "方法名称", example = "getUserInfo")
  36.     private String methodName;
  37.     /**
  38.      * 操作描述(记录业务操作的简要说明)
  39.      */
  40.     @Schema(description = "操作描述", example = "查询用户信息")
  41.     private String description;
  42.     /**
  43.      * 请求IP(记录发起请求的客户端IP地址)
  44.      */
  45.     @Schema(description = "请求IP", example = "192.168.1.100")
  46.     private String requestIp;
  47.     /**
  48.      * 浏览器类型(记录发起请求的浏览器信息,如Chrome、Firefox)
  49.      */
  50.     @Schema(description = "浏览器类型", example = "Chrome 120.0.0.0")
  51.     private String browser;
  52.     /**
  53.      * 请求地址(记录请求的URL路径,如/api/user/info)
  54.      */
  55.     @Schema(description = "请求地址", example = "/api/user/info")
  56.     private String url;
  57.     /**
  58.      * 请求参数(记录请求的参数信息,如{"userId":1})
  59.      */
  60.     @Schema(description = "请求参数", example = "{"userId":1}")
  61.     private String param;
  62.     /**
  63.      * 耗时(记录业务方法执行的耗时,单位:毫秒)
  64.      */
  65.     @Schema(description = "耗时(毫秒)", example = "50")
  66.     private Integer time;
  67.     /**
  68.      * 异常信息(记录业务方法执行过程中抛出的异常信息,无异常则为空)
  69.      */
  70.     @Schema(description = "异常信息", example = "java.lang.NullPointerException: 用户不存在")
  71.     private String exception;
  72.     /**
  73.      * 状态(1:成功 0:失败,记录业务操作的执行结果)
  74.      */
  75.     @Schema(description = "状态(1:成功 0:失败)", example = "1")
  76.     private int status;
  77.     /**
  78.      * 创建人ID(记录创建该日志的用户ID)
  79.      */
  80.     @Schema(description = "创建人ID", example = "1001")
  81.     private Long createUserId;
  82.     /**
  83.      * 创建人名称(记录创建该日志的用户名)
  84.      */
  85.     @Schema(description = "创建人名称", example = "admin")
  86.     private String createUserName;
  87.     /**
  88.      * 创建时间(记录日志的创建时间,默认为当前时间)
  89.      */
  90.     @Schema(description = "创建时间", example = "2025-09-23 17:13:18")
  91.     private Date createTime;
  92.     /**
  93.      * 修改人ID(记录最后修改该日志的用户ID,无修改则为空)
  94.      */
  95.     @Schema(description = "修改人ID", example = "1002")
  96.     private Long updateUserId;
  97.     /**
  98.      * 修改人名称(记录最后修改该日志的用户名,无修改则为空)
  99.      */
  100.     @Schema(description = "修改人名称", example = "operator")
  101.     private String updateUserName;
  102.     /**
  103.      * 修改时间(记录最后修改该日志的时间,无修改则为空)
  104.      */
  105.     @Schema(description = "修改时间", example = "2025-09-23 17:15:30")
  106.     private Date updateTime;
  107.     /**
  108.      * 是否删除(1:已删除 0:未删除,逻辑删除标记)
  109.      */
  110.     @Schema(description = "是否删除(1:已删除 0:未删除)", example = "0")
  111.     private Integer isDel;
  112. }
复制代码
BizLogMapper(用的MyBatisplus)
  1. @Mapper
  2. public interface BizLogMapper extends BaseMapper<BizLogEntity> {
  3. }
复制代码
BizLogService
  1. public interface BizLogService {
  2.     public void save(BizLogEntity bizLogEntity);
  3. }
复制代码
BizLogServiceImpl
  1. @Service
  2. public class BizLogServiceImpl implements BizLogService {
  3.     @Autowired
  4.     private BizLogMapper bizLogMapper;
  5.     @Override
  6.     public void save(BizLogEntity bizLogEntity) {
  7.         FillUserUtil.fillCreateUserInfo(bizLogEntity);
  8.         bizLogMapper.insert(bizLogEntity);
  9.     }
  10. }
复制代码
测试效果
1.png


来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册