# 操作日志记录功能设计文档 **日期**: 2026-04-03 **作者**: 张翔 **版本**: 1.0 ## 1. 概述 ### 1.1 背景 当前系统的Dashboard操作日志一直显示0,原因是缺少操作日志记录功能。虽然数据库表、服务层和API都已就绪,但没有自动记录用户操作的机制。 ### 1.2 目标 实现一个基于注解的操作日志记录功能,自动记录关键业务操作,为系统审计和问题追踪提供数据支持。 ### 1.3 范围 只记录关键业务操作,包括: - 用户管理:创建、更新、删除用户、修改密码、分配角色 - 角色管理:创建、更新、删除角色、分配权限 - 菜单管理:创建、更新、删除菜单 - 系统配置:创建、更新、删除配置 - 数据字典:创建、更新、删除字典 - 公告管理:创建、更新、删除公告 ## 2. 架构设计 ### 2.1 整体架构 采用**AOP切面 + 注解驱动**的架构: ``` 用户请求 → Handler方法(带@OperationLog注解) ↓ OperationLogAspect拦截 ↓ 记录开始时间、获取请求参数 ↓ 执行业务方法 ↓ 记录结束时间、获取返回结果 ↓ 异步保存操作日志到数据库 ↓ 返回结果给用户 ``` ### 2.2 核心组件 1. **`@OperationLog`注解**:标记需要记录日志的方法 2. **`OperationLogAspect`切面**:拦截注解方法,自动记录操作日志 3. **`OperationLogService`服务**:已有的服务层,负责保存日志到数据库 4. **异步处理**:使用Reactor的异步机制,不阻塞主业务流程 ### 2.3 关键设计点 - **响应式编程**:使用Reactor的Mono/Flux,与现有WebFlux架构保持一致 - **异步记录**:日志记录不影响主业务流程性能 - **错误容错**:日志记录失败不影响业务方法执行 - **自动获取上下文**:从SecurityContext获取当前用户,从ServerWebExchange获取IP地址 ## 3. 详细设计 ### 3.1 注解定义 ```java package cn.novalon.manage.sys.audit; import java.lang.annotation.*; /** * 操作日志注解 * 标记需要记录操作日志的方法 * * @author 张翔 * @date 2026-04-03 */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface OperationLog { /** * 操作名称 * 例如:"创建用户"、"删除角色" */ String operation(); /** * 模块名称 * 例如:"用户管理"、"角色管理" */ String module(); } ``` ### 3.2 切面实现 ```java @Aspect @Component public class OperationLogAspect { private final IOperationLogService logService; private final ObjectMapper objectMapper; @Around("@annotation(operationLog)") public Object around(ProceedingJoinPoint point, OperationLog operationLog) throws Throwable { long startTime = System.currentTimeMillis(); // 1. 获取请求信息 String username = getCurrentUsername(); String ip = getCurrentIp(); String method = point.getSignature().toShortString(); String params = serializeParams(point.getArgs()); // 2. 执行业务方法 Object result = null; String status = "0"; // 0-成功, 1-失败 String errorMsg = null; try { result = point.proceed(); // 3. 处理响应式结果 if (result instanceof Mono) { return ((Mono) result) .doOnSuccess(res -> { long duration = System.currentTimeMillis() - startTime; saveLogAsync(operationLog, username, ip, method, params, res, duration, "0", null); }) .doOnError(error -> { long duration = System.currentTimeMillis() - startTime; saveLogAsync(operationLog, username, ip, method, params, null, duration, "1", error.getMessage()); }); } return result; } catch (Throwable error) { status = "1"; errorMsg = error.getMessage(); throw error; } finally { if (!(result instanceof Mono)) { long duration = System.currentTimeMillis() - startTime; saveLogAsync(operationLog, username, ip, method, params, result, duration, status, errorMsg); } } } private void saveLogAsync(OperationLog operationLog, String username, String ip, String method, String params, Object result, long duration, String status, String errorMsg) { // 异步保存日志,不阻塞主流程 Mono.fromRunnable(() -> { cn.novalon.manage.sys.core.domain.OperationLog log = new cn.novalon.manage.sys.core.domain.OperationLog(); log.setUsername(username); log.setOperation(operationLog.module() + " - " + operationLog.operation()); log.setMethod(method); log.setParams(params); log.setResult(serializeResult(result)); log.setIp(ip); log.setDuration(duration); log.setStatus(status); log.setErrorMsg(errorMsg); logService.save(log).subscribe(); }).subscribeOn(Schedulers.boundedElastic()).subscribe(); } } ``` ### 3.3 需要记录的操作 #### 用户管理模块 - `createUser()` - 创建用户 - `updateUser()` - 更新用户 - `deleteUser()` - 删除用户 - `changePassword()` - 修改密码 - `assignRoles()` - 分配角色 #### 角色管理模块 - `createRole()` - 创建角色 - `updateRole()` - 更新角色 - `deleteRole()` - 删除角色 - `assignPermissionsToRole()` - 分配权限 #### 菜单管理模块 - `createMenu()` - 创建菜单 - `updateMenu()` - 更新菜单 - `deleteMenu()` - 删除菜单 #### 其他模块 - 系统配置:创建、更新、删除配置 - 数据字典:创建、更新、删除字典 - 公告管理:创建、更新、删除公告 ## 4. 测试策略 ### 4.1 单元测试 **`OperationLogAspectTest`**:测试切面的核心逻辑 - 测试成功场景:方法执行成功,日志正确记录 - 测试失败场景:方法抛出异常,日志记录错误信息 - 测试响应式场景:Mono返回值的处理 - 测试上下文获取:用户、IP等信息的正确获取 ### 4.2 集成测试 **`OperationLogIntegrationTest`**:测试完整的日志记录流程 - 调用带注解的API接口 - 验证日志是否正确保存到数据库 - 验证日志内容的完整性 ### 4.3 E2E测试 在现有E2E测试中验证: - 执行用户管理操作后,检查Dashboard操作日志数量是否增加 - 验证操作日志显示是否正确 ## 5. 部署计划 ### 5.1 阶段1:开发与测试(当前) 1. 创建`@OperationLog`注解 2. 实现`OperationLogAspect`切面 3. 编写单元测试和集成测试 4. 在关键Handler方法上添加注解 ### 5.2 阶段2:验证 1. 运行所有测试,确保功能正常 2. 手动测试Dashboard操作日志显示 3. 验证日志记录不影响系统性能 ### 5.3 阶段3:上线 1. 提交代码到Git 2. 更新文档 3. 部署到开发环境验证 ## 6. 性能考虑 - **异步保存**:日志保存使用异步方式,不阻塞主业务流程 - **索引优化**:数据库表已有索引(created_at, username) - **日志清理**:建议后续添加定时任务清理历史日志(保留最近3个月) ## 7. 风险与缓解 | 风险 | 影响 | 缓解措施 | |------|------|----------| | 日志记录失败影响业务 | 高 | 使用异步保存,失败时只记录错误日志,不影响业务流程 | | 日志量过大影响性能 | 中 | 只记录关键操作,使用异步保存,定期清理历史日志 | | 敏感信息泄露 | 高 | 参数序列化时排除敏感字段(如password) | ## 8. 后续优化 1. **日志查询优化**:添加更多查询条件(时间范围、操作类型等) 2. **日志导出功能**:支持导出操作日志为Excel 3. **日志统计分析**:统计用户操作频率、操作类型分布等 4. **日志清理任务**:定时清理历史日志,保留最近3个月数据