IT频道
快驴生鲜系统:用户操作日志设计、实现与优化全方案
来源:     阅读:18
网站管理员
发布于 2025-10-30 10:40
查看主页
  
   一、需求分析
  
  1. 日志记录范围:
   - 用户登录/登出操作
   - 关键业务操作(下单、修改订单、取消订单等)
   - 敏感数据访问(查看价格、库存等)
   - 系统配置变更
   - 异常操作尝试
  
  2. 日志内容要求:
   - 操作时间
   - 操作用户ID及角色
   - 操作类型
   - 操作对象(如订单ID、商品ID等)
   - 操作结果(成功/失败)
   - 操作前后的数据变化(可选)
   - 客户端IP地址
  
   二、系统设计
  
   1. 数据库设计
  
  ```sql
  CREATE TABLE user_operation_log (
   id BIGINT PRIMARY KEY AUTO_INCREMENT,
   user_id BIGINT NOT NULL COMMENT 用户ID,
   username VARCHAR(50) NOT NULL COMMENT 用户名,
   operation_type VARCHAR(50) NOT NULL COMMENT 操作类型,
   operation_target VARCHAR(100) COMMENT 操作对象ID,
   operation_content TEXT COMMENT 操作详情,
   operation_result VARCHAR(20) NOT NULL COMMENT 操作结果(SUCCESS/FAILED),
   client_ip VARCHAR(50) COMMENT 客户端IP,
   user_agent VARCHAR(255) COMMENT 用户代理,
   create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 操作时间,
   module_name VARCHAR(50) COMMENT 所属模块
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT=用户操作日志表;
  ```
  
   2. 日志级别设计
  
  - INFO:常规操作记录
  - WARN:可疑操作或边界情况
  - ERROR:操作失败记录
  
   3. 架构设计
  
  ```
  用户操作
   ↓
  AOP切面拦截
   ↓
  日志服务层
   ↓
  异步写入数据库/消息队列
   ↓
  日志分析系统(可选)
  ```
  
   三、技术实现
  
   1. Spring AOP实现日志拦截
  
  ```java
  @Aspect
  @Component
  public class OperationLogAspect {
  
   @Autowired
   private OperationLogService logService;
  
   @Autowired
   private HttpServletRequest request;
  
   // 定义切点:拦截所有Controller层方法
   @Pointcut("execution(* com.kuailefresh.controller.*.*(..))")
   public void controllerPointcut() {}
  
   @Around("controllerPointcut()")
   public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
   // 获取方法签名
   MethodSignature signature = (MethodSignature) joinPoint.getSignature();
   Method method = signature.getMethod();
  
   // 获取操作类型注解
   OperationLog operationLog = method.getAnnotation(OperationLog.class);
   if (operationLog == null) {
   return joinPoint.proceed();
   }
  
   // 获取用户信息
   Long userId = UserContext.getCurrentUserId();
   String username = UserContext.getCurrentUsername();
  
   // 记录开始时间
   long startTime = System.currentTimeMillis();
  
   try {
   // 执行方法
   Object result = joinPoint.proceed();
  
   // 计算耗时
   long costTime = System.currentTimeMillis() - startTime;
  
   // 构建日志内容
   String operationType = operationLog.value();
   String moduleName = operationLog.module();
  
   // 获取方法参数
   Object[] args = joinPoint.getArgs();
   StringBuilder params = new StringBuilder();
   for (Object arg : args) {
   if (arg != null) {
   params.append(arg.toString()).append(";");
   }
   }
  
   // 保存日志
   OperationLogDTO logDTO = new OperationLogDTO();
   logDTO.setUserId(userId);
   logDTO.setUsername(username);
   logDTO.setOperationType(operationType);
   logDTO.setModuleName(moduleName);
   logDTO.setOperationResult("SUCCESS");
   logDTO.setClientIp(getClientIp());
   logDTO.setParams(params.toString());
   logDTO.setCostTime((int) costTime);
  
   // 异步保存日志
   asyncLogService.saveLog(logDTO);
  
   return result;
   } catch (Exception e) {
   // 异常处理
   long costTime = System.currentTimeMillis() - startTime;
  
   OperationLogDTO logDTO = new OperationLogDTO();
   logDTO.setUserId(userId);
   logDTO.setUsername(username);
   logDTO.setOperationType(operationLog.value());
   logDTO.setModuleName(operationLog.module());
   logDTO.setOperationResult("FAILED");
   logDTO.setClientIp(getClientIp());
   logDTO.setExceptionMsg(e.getMessage());
   logDTO.setCostTime((int) costTime);
  
   asyncLogService.saveLog(logDTO);
  
   throw e;
   }
   }
  
   private String getClientIp() {
   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 ip;
   }
  }
  ```
  
   2. 自定义注解
  
  ```java
  @Target(ElementType.METHOD)
  @Retention(RetentionPolicy.RUNTIME)
  public @interface OperationLog {
   String value() default ""; // 操作类型
   String module() default ""; // 所属模块
  }
  ```
  
   3. 异步日志服务
  
  ```java
  @Service
  public class AsyncLogServiceImpl implements AsyncLogService {
  
   @Autowired
   private OperationLogMapper logMapper;
  
   @Async
   @Override
   public void saveLog(OperationLogDTO logDTO) {
   try {
   // 转换为实体
   OperationLogEntity logEntity = new OperationLogEntity();
   BeanUtils.copyProperties(logDTO, logEntity);
  
   // 保存到数据库
   logMapper.insert(logEntity);
   } catch (Exception e) {
   // 可以添加重试机制或写入失败日志
   log.error("保存操作日志失败", e);
   }
   }
  }
  ```
  
   4. 控制器示例
  
  ```java
  @RestController
  @RequestMapping("/orders")
  public class OrderController {
  
   @OperationLog(value = "创建订单", module = "订单管理")
   @PostMapping
   public Result createOrder(@RequestBody OrderCreateDTO dto) {
   // 业务逻辑
   return Result.success();
   }
  
   @OperationLog(value = "取消订单", module = "订单管理")
   @PutMapping("/{orderId}/cancel")
   public Result cancelOrder(@PathVariable Long orderId) {
   // 业务逻辑
   return Result.success();
   }
  }
  ```
  
   四、高级功能实现
  
   1. 日志查询接口
  
  ```java
  @RestController
  @RequestMapping("/admin/logs")
  public class LogController {
  
   @Autowired
   private OperationLogService logService;
  
   @GetMapping
   public Result queryLogs(
   @RequestParam(required = false) Long userId,
   @RequestParam(required = false) String operationType,
   @RequestParam(required = false) String module,
   @RequestParam(required = false) Date startTime,
   @RequestParam(required = false) Date endTime,
   @RequestParam(defaultValue = "1") Integer pageNum,
   @RequestParam(defaultValue = "10") Integer pageSize) {
  
   PageInfo pageInfo = logService.queryLogs(
   userId, operationType, module, startTime, endTime, pageNum, pageSize);
  
   return Result.success(pageInfo);
   }
  }
  ```
  
   2. 日志分析(示例:统计各模块操作次数)
  
  ```java
  @Service
  public class LogAnalysisServiceImpl implements LogAnalysisService {
  
   @Autowired
   private OperationLogMapper logMapper;
  
   @Override
   public Map countOperationsByModule(Date date) {
   List> result = logMapper.countOperationsByModule(date);
  
   Map moduleStats = new HashMap<>();
   for (Map row : result) {
   String module = (String) row.get("module_name");
   Integer count = ((Number) row.get("operation_count")).intValue();
   moduleStats.put(module, count);
   }
  
   return moduleStats;
   }
  }
  ```
  
   五、部署与优化
  
  1. 日志存储优化:
   - 按日期分表存储
   - 定期归档冷数据到低成本存储
   - 实现日志压缩
  
  2. 性能优化:
   - 使用消息队列缓冲日志写入
   - 批量插入数据库
   - 对高频操作采用本地缓存+定时刷盘
  
  3. 安全考虑:
   - 对敏感操作日志进行脱敏处理
   - 实现日志访问权限控制
   - 记录日志查看操作
  
  4. 监控告警:
   - 监控日志写入延迟
   - 对异常操作频率设置告警
   - 监控日志存储空间使用情况
  
   六、测试用例
  
  1. 正常操作测试:
   - 验证下单操作日志是否正确记录
   - 验证修改订单操作日志是否完整
  
  2. 异常操作测试:
   - 模拟权限不足操作,验证失败日志记录
   - 模拟系统异常,验证异常日志记录
  
  3. 性能测试:
   - 高并发场景下日志写入性能
   - 日志查询响应时间
  
  4. 边界测试:
   - 超长参数值截断处理
   - 特殊字符转义处理
  
   七、维护与扩展
  
  1. 日志字段扩展:
   - 预留扩展字段以便未来添加新信息
   - 使用JSON格式存储复杂操作详情
  
  2. 多环境支持:
   - 不同环境日志隔离存储
   - 环境标识字段
  
  3. 国际化支持:
   - 操作类型描述多语言支持
   - 日志查询界面国际化
  
  4. 合规性要求:
   - GDPR等数据保护法规合规
   - 日志保留策略配置化
  
  通过以上设计实现,快驴生鲜系统能够完整记录用户操作轨迹,为系统运维、安全审计和业务分析提供有力支持。
免责声明:本文为用户发表,不代表网站立场,仅供参考,不构成引导等用途。 IT频道
购买生鲜系统联系18310199838
广告
相关推荐
蔬东坡生鲜系统:数字化赋能,降本增效控损耗
万象订货系统:破传统痛点,助商家降本增效、灵活安全转型
万象生鲜配送系统:精准预测、智能管理,提升库存周转率
水果批发业客户管理痛点及万象源码部署方案与预期效果
生鲜小程序:打破限制、升级品质,引领便捷健康新生活