9.3 KiB
@Log 注解使用指南
一、概述
@Log 注解是 skills 项目中用于记录操作日志的核心功能。它基于 AOP(面向切面编程) 和 拦截器 机制实现,能够自动捕获 Controller 层方法的请求和响应信息,并异步保存到数据库的 sys_log 表中。
二、核心特性
✅ 无侵入性: 只需添加 @Log 注解,无需修改业务代码
✅ 自动化: 请求/响应信息自动捕获,无需手动记录
✅ 高性能: 异步保存,不影响接口响应速度
✅ 智能化: 自动识别浏览器、操作系统、IP等信息
✅ 可扩展: 支持类级别和方法级别的注解配置
三、快速开始
3.1 数据库初始化
执行 SQL 脚本创建或更新日志表:
# 在项目根目录执行
mysql -u root -p skills < backend/db/alter_sys_log_table.sql
3.2 在控制器上添加注解
方式一:类级别注解(推荐)
在 Controller 类上添加 @Log 注解,该类下所有方法都会记录日志:
@Log(module = "用户管理")
@RestController
@RequestMapping("/api/user")
public class UserController {
@PostMapping("/add")
public CommonResult addUser(@RequestBody UserReq req) {
// 自动记录日志
}
}
方式二:方法级别注解
在特定方法上添加 @Log 注解,只记录该方法的日志:
@RestController
@RequestMapping("/api/order")
public class OrderController {
@Log(module = "订单管理", description = "创建订单")
@PostMapping("/create")
public CommonResult createOrder(@RequestBody OrderReq req) {
// 自动记录日志
}
}
方式三:忽略特定接口
对于高频调用的接口,可以设置 ignore = true 不记录日志:
@Log(module = "认证")
@RestController
@RequestMapping("/api/auth")
public class AuthController {
@PostMapping("/login")
public CommonResult login(@RequestBody LoginReq req) {
// 会记录日志
}
@Log(ignore = true)
@GetMapping("/check/token")
public CommonResult checkToken(@RequestParam String token) {
// 不会记录日志(高频调用接口)
}
}
四、注解属性说明
| 属性 | 类型 | 说明 | 默认值 | 示例 |
|---|---|---|---|---|
| module | String | 模块名称 | 空字符串 | "用户管理" |
| description | String | 日志描述 | 空字符串 | "创建用户" |
| ignore | boolean | 是否忽略记录 | false | true/false |
五、已添加注解的控制器
以下控制器已经添加了 @Log 注解:
-
LoginController - 登录认证模块
- 路径:
/api/login/** - 模块名: "登录认证"
- 路径:
-
CmsContentController - 内容管理模块
- 路径:
/api/cmsContent/** - 模块名: "内容管理"
- 路径:
-
AccountController - 账户管理模块
- 路径:
/api/account/** - 模块名: "账户管理"
- 路径:
-
AccountFrozenController - 账户冻结模块
- 路径:
/api/accountFrozen/** - 模块名: "账户冻结"
- 路径:
六、日志记录内容
系统会自动记录以下信息:
6.1 请求信息
- 请求方法(GET、POST等)
- 请求URL
- 请求头
- 请求体
- 客户端IP
- IP归属地
- 浏览器信息
- 操作系统
6.2 响应信息
- 响应状态码
- 响应头
- 响应体(如果可用)
- 执行耗时(毫秒)
6.3 其他信息
- 模块名称
- 日志描述
- 成功/失败状态
- 错误信息(如果失败)
- 创建时间
七、日志查询
7.1 数据库查询
-- 查询最近的10条日志
SELECT * FROM sys_log ORDER BY create_time DESC LIMIT 10;
-- 按模块查询
SELECT * FROM sys_log WHERE module = '登录认证' ORDER BY create_time DESC;
-- 查询失败的日志
SELECT * FROM sys_log WHERE status = 2 ORDER BY create_time DESC;
-- 按IP查询
SELECT * FROM sys_log WHERE ip = '192.168.1.100' ORDER BY create_time DESC;
-- 按时间范围查询
SELECT * FROM sys_log
WHERE create_time BETWEEN '2026-04-14 00:00:00' AND '2026-04-14 23:59:59'
ORDER BY create_time DESC;
7.2 通过 API 查询
可以使用现有的 SysLogController 提供的接口查询日志:
# 分页查询
POST /api/sysLog/getPageList
{
"pageNum": 1,
"pageSize": 10,
"module": "登录认证",
"status": 1
}
八、性能优化
8.1 异步保存
日志保存采用异步方式,不会阻塞主业务流程:
@Async
public void saveLogAsync(LogRecord logRecord) {
// 异步保存逻辑
}
8.2 数据库索引
日志表已添加以下索引以优化查询性能:
idx_module: 模块查询优化idx_ip: IP查询优化idx_create_time: 时间范围查询优化idx_status: 状态查询优化
8.3 定期清理
建议定期清理历史日志,避免数据量过大:
-- 保留最近6个月的日志
DELETE FROM sys_log WHERE create_time < DATE_SUB(NOW(), INTERVAL 6 MONTH);
九、常见问题
9.1 日志未记录
可能原因:
- 方法标注了
@Log(ignore = true) - 异步线程池配置问题
排查步骤:
- 检查控制器是否添加了
@Log注解 - 查看应用日志是否有错误信息
- 确认
@EnableAsync已启用
9.2 响应体为空
原因: 拦截器无法直接读取响应体
解决方案:
- 当前版本暂时不记录响应体
- 如需记录,需要使用 ContentCachingResponseWrapper
9.3 用户ID为空
原因: 尚未实现从 Token 解析用户ID的逻辑
解决方案:
- 在 LogInterceptor 的
saveLogAsync方法中添加用户ID解析逻辑 - 根据实际使用的认证框架(如 Sa-Token)实现
十、扩展开发
10.1 添加用户ID解析
在 LogInterceptor.saveLogAsync 方法中添加:
// 从 Token 中解析用户ID
try {
String token = request.getHeaders().get("Authorization");
if (token != null && token.startsWith("Bearer ")) {
token = token.substring(7);
// 使用 Sa-Token 解析用户ID
Object loginId = StpUtil.getLoginIdByToken(token);
if (loginId != null) {
sysLog.setCreateUser(Long.parseLong(loginId.toString()));
}
}
} catch (Exception e) {
logger.warn("解析用户ID失败: {}", e.getMessage());
}
10.2 自定义日志过滤
可以在 LogInterceptor.preHandle 方法中添加自定义过滤逻辑:
// 排除敏感接口
String requestUri = request.getRequestURI();
if (requestUri.contains("/sensitive/")) {
return true; // 不记录日志
}
十一、技术架构
11.1 核心组件
┌─────────────────────────────────────┐
│ Controller (@Log 注解) │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ LogInterceptor (拦截器) │
│ - preHandle: 捕获请求信息 │
│ - afterCompletion: 捕获响应信息 │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ LogInterceptor.saveLogAsync │
│ (@Async 异步保存) │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ SysLogMapper (持久层) │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ sys_log (MySQL 数据库表) │
└─────────────────────────────────────┘
11.2 相关文件
| 文件路径 | 说明 |
|---|---|
annotation/Log.java |
@Log 注解定义 |
entity/LogRecord.java |
日志记录对象 |
entity/SysLog.java |
日志实体类 |
interceptor/LogInterceptor.java |
日志拦截器 |
config/LogConfiguration.java |
日志配置类 |
mapper/SysLogMapper.java |
日志 Mapper 接口 |
resources/mapper/SysLogMapper.xml |
日志 SQL 映射 |
db/alter_sys_log_table.sql |
数据库建表脚本 |
十二、总结
@Log 注解为 skills 项目提供了强大的操作日志记录功能,具有以下优势:
- ✅ 简单易用: 只需添加注解即可启用
- ✅ 性能优异: 异步保存,不影响业务性能
- ✅ 信息完整: 自动捕获请求/响应的详细信息
- ✅ 灵活配置: 支持类级别和方法级别的配置
- ✅ 易于扩展: 可以根据需求自定义日志记录逻辑
通过合理使用 @Log 注解,可以实现:
- 操作审计追溯
- 安全事件监控
- 接口调用统计
- 问题排查分析
文档版本: v1.0
最后更新: 2026-04-14
作者: Lingma AI Assistant