010-53388338

快驴生鲜系统用户操作日志方案:从设计到实现及优化维护全解析

分类:IT频道 时间:2026-02-26 05:35 浏览:16
概述
    一、需求分析    1.1目标  -记录用户在系统中的关键操作行为  -提供操作追溯和审计功能  -支持问题排查和系统优化  -满足合规性要求    1.2需记录的操作类型  -用户登录/登出  -商品管理操作(增删改查)  -订单处理操作(创建、修改、取消、发货等)  -库存管理操作  -
内容
  
   一、需求分析
  
   1.1 目标
  - 记录用户在系统中的关键操作行为
  - 提供操作追溯和审计功能
  - 支持问题排查和系统优化
  - 满足合规性要求
  
   1.2 需记录的操作类型
  - 用户登录/登出
  - 商品管理操作(增删改查)
  - 订单处理操作(创建、修改、取消、发货等)
  - 库存管理操作
  - 权限变更操作
  - 系统配置修改
  - 数据导出操作
  
   二、系统设计
  
   2.1 日志表结构设计
  ```sql
  CREATE TABLE `user_operation_logs` (
   `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 主键ID,
   `user_id` bigint(20) NOT NULL COMMENT 用户ID,
   `username` varchar(50) NOT NULL COMMENT 用户名,
   `operation_type` varchar(50) NOT NULL COMMENT 操作类型,
   `operation_module` varchar(50) NOT NULL COMMENT 操作模块,
   `operation_content` text COMMENT 操作内容(JSON格式),
   `request_params` text COMMENT 请求参数(JSON格式),
   `response_result` text COMMENT 响应结果(JSON格式),
   `ip_address` varchar(50) COMMENT IP地址,
   `user_agent` varchar(500) COMMENT 用户代理,
   `operation_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 操作时间,
   `execution_time` int(11) COMMENT 执行耗时(毫秒),
   `status` tinyint(1) DEFAULT 1 COMMENT 状态(1-成功,0-失败),
   PRIMARY KEY (`id`),
   KEY `idx_user_id` (`user_id`),
   KEY `idx_operation_time` (`operation_time`),
   KEY `idx_operation_type` (`operation_type`)
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT=用户操作日志表;
  ```
  
   2.2 技术选型
  - 日志记录方式:AOP切面编程 + 注解方式
  - 日志存储:MySQL数据库 + 异步写入(提高性能)
  - 日志查询:提供管理后台查询界面
  - 日志清理:定期归档或删除旧日志
  
   三、开发实现
  
   3.1 自定义日志注解
  ```java
  @Target(ElementType.METHOD)
  @Retention(RetentionPolicy.RUNTIME)
  public @interface OperationLog {
   String operationType() default ""; // 操作类型
   String operationModule() default ""; // 操作模块
   boolean saveParams() default true; // 是否保存请求参数
   boolean saveResult() default false; // 是否保存响应结果
   String desc() default ""; // 操作描述
  }
  ```
  
   3.2 AOP切面实现
  ```java
  @Aspect
  @Component
  public class OperationLogAspect {
  
   @Autowired
   private UserOperationLogService logService;
  
   @Autowired
   private HttpServletRequest request;
  
   @Pointcut("@annotation(com.kuailu.annotation.OperationLog)")
   public void logPointCut() {}
  
   @Around("logPointCut()")
   public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
   long beginTime = System.currentTimeMillis();
  
   // 获取方法签名
   MethodSignature signature = (MethodSignature) joinPoint.getSignature();
   Method method = signature.getMethod();
  
   // 获取注解信息
   OperationLog operationLog = method.getAnnotation(OperationLog.class);
  
   // 执行方法
   Object result = joinPoint.proceed();
  
   // 执行耗时
   long time = System.currentTimeMillis() - beginTime;
  
   // 保存日志
   try {
   saveLog(joinPoint, operationLog, time, result);
   } catch (Exception e) {
   // 记录日志保存失败,不影响主流程
   log.error("保存操作日志失败", e);
   }
  
   return result;
   }
  
   private void saveLog(ProceedingJoinPoint joinPoint, OperationLog operationLog,
   long time, Object result) {
   // 获取请求参数
   Object[] args = joinPoint.getArgs();
   String params = operationLog.saveParams() ? JsonUtils.toJson(args) : null;
  
   // 获取响应结果
   String resultStr = operationLog.saveResult() ? JsonUtils.toJson(result) : null;
  
   // 获取用户信息
   UserDTO user = UserContext.getCurrentUser();
  
   // 构建日志对象
   UserOperationLog log = new UserOperationLog();
   log.setUserId(user != null ? user.getId() : 0);
   log.setUsername(user != null ? user.getUsername() : "system");
   log.setOperationType(operationLog.operationType());
   log.setOperationModule(operationLog.operationModule());
   log.setOperationContent(operationLog.desc());
   log.setRequestParams(params);
   log.setResponseResult(resultStr);
   log.setIpAddress(getIpAddress());
   log.setUserAgent(request.getHeader("User-Agent"));
   log.setOperationTime(new Date());
   log.setExecutionTime((int)time);
   log.setStatus(time > 5000 ? 0 : 1); // 超过5秒视为失败
  
   // 异步保存日志
   logService.asyncSaveLog(log);
   }
  
   private String getIpAddress() {
   // 获取IP地址逻辑
   // ...
   }
  }
  ```
  
   3.3 异步日志服务
  ```java
  @Service
  public class UserOperationLogServiceImpl implements UserOperationLogService {
  
   @Autowired
   private UserOperationLogMapper logMapper;
  
   @Async("logTaskExecutor") // 使用异步线程池
   @Override
   public void asyncSaveLog(UserOperationLog log) {
   logMapper.insert(log);
   }
  
   // 日志查询方法...
  }
  ```
  
   3.4 线程池配置
  ```java
  @Configuration
  public class AsyncTaskConfig {
  
   @Bean("logTaskExecutor")
   public Executor logTaskExecutor() {
   ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
   executor.setCorePoolSize(5);
   executor.setMaxPoolSize(10);
   executor.setQueueCapacity(100);
   executor.setThreadNamePrefix("log-task-");
   executor.initialize();
   return executor;
   }
  }
  ```
  
   四、管理后台实现
  
   4.1 日志查询界面
  - 支持按时间范围查询
  - 支持按用户、操作类型、模块筛选
  - 支持查看操作详情(参数、结果等)
  - 支持导出Excel
  
   4.2 关键代码示例
  ```java
  @RestController
  @RequestMapping("/api/operation-logs")
  public class OperationLogController {
  
   @Autowired
   private UserOperationLogService logService;
  
   @GetMapping("/page")
   public Result> queryPage(
   @RequestParam(required = false) Long userId,
   @RequestParam(required = false) String operationType,
   @RequestParam(required = false) String operationModule,
   @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date startTime,
   @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date endTime,
   @RequestParam(defaultValue = "1") Integer pageNum,
   @RequestParam(defaultValue = "10") Integer pageSize) {
  
   PageHelper.startPage(pageNum, pageSize);
   List logs = logService.queryLogs(
   userId, operationType, operationModule, startTime, endTime);
  
   return Result.success(new PageInfo<>(logs));
   }
  
   @GetMapping("/export")
   public void exportLogs(HttpServletResponse response,
   @RequestParam(required = false) Long userId,
   @RequestParam(required = false) String operationType,
   @RequestParam(required = false) String operationModule,
   @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date startTime,
   @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date endTime) throws IOException {
  
   List logs = logService.queryLogs(
   userId, operationType, operationModule, startTime, endTime);
  
   // 导出Excel逻辑
   // ...
   }
  }
  ```
  
   五、性能优化与注意事项
  
  1. 异步写入:采用异步方式写入日志,避免影响主业务流程
  2. 批量插入:对于高并发场景,可考虑批量插入日志
  3. 日志分级:根据操作重要性设置不同日志级别
  4. 敏感信息处理:对日志中的敏感信息进行脱敏处理
  5. 日志清理:设置日志保留策略,定期清理或归档旧日志
  6. 错误处理:确保日志记录失败不影响主业务流程
  7. 监控告警:对异常操作或高频失败操作设置监控告警
  
   六、测试验证
  
  1. 单元测试:验证AOP切面和日志服务
  2. 集成测试:验证完整操作流程中的日志记录
  3. 性能测试:验证高并发下的日志记录性能
  4. 异常测试:验证日志记录失败时的系统行为
  
   七、部署与维护
  
  1. 部署:将日志服务与主应用一起部署
  2. 监控:监控日志写入性能和失败情况
  3. 维护:定期检查日志表大小,执行维护操作
  
  通过以上设计和实现,快驴生鲜系统可以完整记录用户操作日志,为系统运维、审计和问题排查提供有力支持。
评论
  • 下一篇

  • Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 8192 bytes) in /www/wwwroot/www.sjwxsc.com/config/function.php on line 274