十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

SpringBoot开发企业后台-操作日志记录的最佳实践

SpringBoot开发企业后台-操作日志记录的最佳实践 SpringBoot开发企业后台-操作日志记录的最佳实践AOP 很适合记录“谁在什么时候调用了什么接口”却无法天然知道一次修改改变了哪些业务字段、为什么改变以及是否与事务一起成功。接口日志与业务审计并不是同一份数据。关键风险只依赖通用切面审计记录会停留在请求 JSON把所有审计手写进 Service又会散落和遗漏。企业系统需要把通用调用事实与业务变更事实分层采集。MetaLite 使用切面统一记录入口事实同时允许业务层补充修改前后值和业务语义。本文先划清操作日志与审计日志再用 BaseAspectLogger 和字段变更链说明两类信息怎样汇合。一、操作日志和业务审计不是同一件事后台各业务 Service 在创建、更新、删除和状态变化成功后调用recordOperate(operateType,remark,recordId,changeData);例如外部调用方更新完成后记录sysUserOperateLogService.recordOperate(OperateTypeEnum.UPDATE,外部调用方管理-更新外部调用方: appId,appId,FastJson.obj2Json(update.getSetMap()));业务代码明确知道资源类型、业务主键和变化字段因此比通用切面猜测参数含义更准确。二、一条操作日志保存哪些字段SysUserOperateLogEntity包含字段含义userId/userName操作者operateType新增、修改、删除、登录等动作recordId被操作业务记录changeData变更内容operateIp请求来源 IPremark面向人的操作描述operateTime实际操作时间查询接口可以按用户、用户名、操作类型、记录 ID 和时间区间筛选并按操作时间倒序分页。这已经形成了基础的后台审计查询闭环。三、操作者如何从请求上下文补齐普通操作日志从ThreadContext获取登录用户 IDStringloginUserIdThreadContext.getLoginUserId();随后从 Redis 登录缓存读取用户名再通过IpUtil.getRemoteIp()获取来源 IP。这种方式让业务调用只提供“动作与对象”不必每次重复传操作者信息。但它也有明确边界如果线程上下文没有登录用户 IDrecordOperate会直接返回不写日志。因此该入口只适用于同步接口请求链路。定时任务、消息消费、异步线程和系统自动操作需要专门的操作者模型例如operatorTypeSYSTEM operatorIdjob:xxx不能默默跳过。四、登录与登出为什么使用专用方法登录成功之前ThreadContext 中通常还没有登录用户 ID登出也涉及缓存清理顺序。因此 MetaLite 提供recordOperateLogin(userId,userName)recordOperateLogout(userId,userName)调用方显式传入身份日志类型固定为登录或登出。这说明通用上下文并不能覆盖所有审计场景。认证边界上的身份来源应由认证流程本身提供。五、changeData 应记录结果还是原始参数记录整个请求参数最省事但它可能包含没有实际变化的字段前端附带但服务端忽略的字段密码、密钥和 Token大段无关数据。更好的来源是实际写入集合。例如差异比较得到{status:0,remark:已审核}它比原始请求更接近数据库事实。如果同时保留before和after还可以表达{status:{before:1,after:0}}当前不同 Service 的changeData口径并不完全一致有的记录新实体有的记录更新 Map有的删除时记录旧实体。查询端需要知道操作类型才能解释内容。后续可以统一成带版本的变更协议。六、敏感字段是当前最重要的边界显式记录并不会自动安全。当前创建或删除外部调用方时可能序列化整个实体修改密码与重置密码也会把Update序列化为changeData其中包含加密后的密码值。密文依然是敏感数据。它可能被离线破解、重放或在密钥泄漏后恢复明文。审计写入前应建立字段策略密码、私钥、Secret、Token → 完全不记录值 手机号、证件号、邮箱 → 脱敏 普通配置 → 记录前后值 大文本 → 摘要或截断不能依赖序列化框架猜测哪些字段敏感。七、业务成功与日志成功如何保持一致当前调用通常是先写业务表 再插入操作日志表需要明确两个问题日志插入失败业务是否应该回滚业务回滚时日志是否也会回滚如果二者在同一数据库和同一本地事务中可以获得强一致如果没有事务包裹可能出现业务成功但日志缺失或日志存在但业务最终失败。对高强度审计场景可以采用同库同事务写入Outbox 与异步投递独立审计存储并记录投递状态失败告警与补偿任务。MetaLite 的日志 Service 本身没有声明一套独立事务语义最终一致性取决于外层业务事务如何组织。八、只记录成功操作够不够业务 Service 通常在数据库变更成功后记录日志因此当前日志主要表达成功操作。安全审计还经常需要失败事件登录失败无权限访问密码重置被拒绝敏感配置修改校验失败批量操作部分失败。失败日志不能简单沿用成功变更结构应额外记录resultFAIL errorCode failureReason脱敏 target requestId / TraceId同时要限制重复失败日志造成的写入放大和恶意刷盘。九、为什么还需要 TraceId 和客户端信息当前实体保存操作者、IP 和时间但没有单独保存 TraceId、AppId、User-Agent 或服务实例。当一次操作跨越网关、Admin 服务和多个内部服务时TraceId 能把业务审计与技术日志串起来AppId 能说明操作来自 Web 管理端还是其他受信应用。建议将以下字段作为审计上下文traceId appId operatorType resourceType recordId result operateIp这比把所有信息揉进remark更容易查询和统计。十、AOP 适合做什么业务代码适合做什么两种方式并不冲突。AOP 适合统一TraceId、耗时和异常请求入口与响应结果审计注解元数据通用上下文补齐。业务代码适合提供资源类型与业务记录 ID操作类型实际字段差异面向业务的描述敏感字段策略。可以让业务方法返回或发布一个AuditEvent再由统一组件持久化但不应让切面通过反射猜测每个参数的业务含义。企业操作日志的价值不是“每个方法都留下一行”而是任何关键数据变化都能回答谁、何时、从哪里、对什么、改了什么以及最终是否成功。十一、一次用户状态修改应留下怎样的审计证据以“管理员停用用户”为例审计记录至少要回答谁在什么时间操作了哪个用户、修改前后状态是什么、请求来自哪个 IP、是否成功以及对应 TraceId。只记录recordIduserId和“修改用户”四个字不足以支持事后调查。建议把可审计字段分为三层固定元数据由框架补齐业务对象变化由 Service 显式提供密码、Token、密钥等敏感字段在进入changeData前直接排除。失败操作也应留下独立事件但不能与业务事务绑定到一起后因为回滚而消失。这说明 AOP 适合统一操作者、IP、时间和 TraceId业务 Service 仍必须告诉日志组件“改了什么”。框架简介MetaLite 是面向企业生产环境的新一代 Java 微服务技术底座。系列文章重点分享代码背后的设计思路、技术取舍与工程实践。源码基线JDK 21、Spring Boot 3.2.9、Spring Cloud 2023.0.1、Spring Cloud Alibaba 2023.0.1.3具体组件版本以项目backend-bom为准。作者简介15 年 Spring 体系企业级开发经验专注于 Java 微服务架构、工程治理与生产实践。持续更新MetaLite 系列内容将持续更新围绕核心设计、源码链路、技术取舍与生产实践展开。欢迎关注作者及时获取后续内容。在线演示演示地址: https://admin.metalite.top/演示账号: guess演示密码: admin2026
返回列表