340 lines
9.3 KiB
Markdown
340 lines
9.3 KiB
Markdown
# @Log 注解使用指南
|
||
|
||
## 一、概述
|
||
|
||
`@Log` 注解是 skills 项目中用于记录操作日志的核心功能。它基于 **AOP(面向切面编程)** 和 **拦截器** 机制实现,能够自动捕获 Controller 层方法的请求和响应信息,并异步保存到数据库的 `sys_log` 表中。
|
||
|
||
## 二、核心特性
|
||
|
||
✅ **无侵入性**: 只需添加 `@Log` 注解,无需修改业务代码
|
||
✅ **自动化**: 请求/响应信息自动捕获,无需手动记录
|
||
✅ **高性能**: 异步保存,不影响接口响应速度
|
||
✅ **智能化**: 自动识别浏览器、操作系统、IP等信息
|
||
✅ **可扩展**: 支持类级别和方法级别的注解配置
|
||
|
||
## 三、快速开始
|
||
|
||
### 3.1 数据库初始化
|
||
|
||
执行 SQL 脚本创建或更新日志表:
|
||
|
||
```bash
|
||
# 在项目根目录执行
|
||
mysql -u root -p skills < backend/db/alter_sys_log_table.sql
|
||
```
|
||
|
||
### 3.2 在控制器上添加注解
|
||
|
||
#### 方式一:类级别注解(推荐)
|
||
|
||
在 Controller 类上添加 `@Log` 注解,该类下所有方法都会记录日志:
|
||
|
||
```java
|
||
@Log(module = "用户管理")
|
||
@RestController
|
||
@RequestMapping("/api/user")
|
||
public class UserController {
|
||
|
||
@PostMapping("/add")
|
||
public CommonResult addUser(@RequestBody UserReq req) {
|
||
// 自动记录日志
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 方式二:方法级别注解
|
||
|
||
在特定方法上添加 `@Log` 注解,只记录该方法的日志:
|
||
|
||
```java
|
||
@RestController
|
||
@RequestMapping("/api/order")
|
||
public class OrderController {
|
||
|
||
@Log(module = "订单管理", description = "创建订单")
|
||
@PostMapping("/create")
|
||
public CommonResult createOrder(@RequestBody OrderReq req) {
|
||
// 自动记录日志
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 方式三:忽略特定接口
|
||
|
||
对于高频调用的接口,可以设置 `ignore = true` 不记录日志:
|
||
|
||
```java
|
||
@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` 注解:
|
||
|
||
1. **LoginController** - 登录认证模块
|
||
- 路径: `/api/login/**`
|
||
- 模块名: "登录认证"
|
||
|
||
2. **CmsContentController** - 内容管理模块
|
||
- 路径: `/api/cmsContent/**`
|
||
- 模块名: "内容管理"
|
||
|
||
3. **AccountController** - 账户管理模块
|
||
- 路径: `/api/account/**`
|
||
- 模块名: "账户管理"
|
||
|
||
4. **AccountFrozenController** - 账户冻结模块
|
||
- 路径: `/api/accountFrozen/**`
|
||
- 模块名: "账户冻结"
|
||
|
||
## 六、日志记录内容
|
||
|
||
系统会自动记录以下信息:
|
||
|
||
### 6.1 请求信息
|
||
- 请求方法(GET、POST等)
|
||
- 请求URL
|
||
- 请求头
|
||
- 请求体
|
||
- 客户端IP
|
||
- IP归属地
|
||
- 浏览器信息
|
||
- 操作系统
|
||
|
||
### 6.2 响应信息
|
||
- 响应状态码
|
||
- 响应头
|
||
- 响应体(如果可用)
|
||
- 执行耗时(毫秒)
|
||
|
||
### 6.3 其他信息
|
||
- 模块名称
|
||
- 日志描述
|
||
- 成功/失败状态
|
||
- 错误信息(如果失败)
|
||
- 创建时间
|
||
|
||
## 七、日志查询
|
||
|
||
### 7.1 数据库查询
|
||
|
||
```sql
|
||
-- 查询最近的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 提供的接口查询日志:
|
||
|
||
```bash
|
||
# 分页查询
|
||
POST /api/sysLog/getPageList
|
||
{
|
||
"pageNum": 1,
|
||
"pageSize": 10,
|
||
"module": "登录认证",
|
||
"status": 1
|
||
}
|
||
```
|
||
|
||
## 八、性能优化
|
||
|
||
### 8.1 异步保存
|
||
|
||
日志保存采用异步方式,不会阻塞主业务流程:
|
||
|
||
```java
|
||
@Async
|
||
public void saveLogAsync(LogRecord logRecord) {
|
||
// 异步保存逻辑
|
||
}
|
||
```
|
||
|
||
### 8.2 数据库索引
|
||
|
||
日志表已添加以下索引以优化查询性能:
|
||
|
||
- `idx_module`: 模块查询优化
|
||
- `idx_ip`: IP查询优化
|
||
- `idx_create_time`: 时间范围查询优化
|
||
- `idx_status`: 状态查询优化
|
||
|
||
### 8.3 定期清理
|
||
|
||
建议定期清理历史日志,避免数据量过大:
|
||
|
||
```sql
|
||
-- 保留最近6个月的日志
|
||
DELETE FROM sys_log WHERE create_time < DATE_SUB(NOW(), INTERVAL 6 MONTH);
|
||
```
|
||
|
||
## 九、常见问题
|
||
|
||
### 9.1 日志未记录
|
||
|
||
**可能原因**:
|
||
1. 方法标注了 `@Log(ignore = true)`
|
||
2. 异步线程池配置问题
|
||
|
||
**排查步骤**:
|
||
- 检查控制器是否添加了 `@Log` 注解
|
||
- 查看应用日志是否有错误信息
|
||
- 确认 `@EnableAsync` 已启用
|
||
|
||
### 9.2 响应体为空
|
||
|
||
**原因**: 拦截器无法直接读取响应体
|
||
|
||
**解决方案**:
|
||
- 当前版本暂时不记录响应体
|
||
- 如需记录,需要使用 ContentCachingResponseWrapper
|
||
|
||
### 9.3 用户ID为空
|
||
|
||
**原因**: 尚未实现从 Token 解析用户ID的逻辑
|
||
|
||
**解决方案**:
|
||
- 在 LogInterceptor 的 `saveLogAsync` 方法中添加用户ID解析逻辑
|
||
- 根据实际使用的认证框架(如 Sa-Token)实现
|
||
|
||
## 十、扩展开发
|
||
|
||
### 10.1 添加用户ID解析
|
||
|
||
在 `LogInterceptor.saveLogAsync` 方法中添加:
|
||
|
||
```java
|
||
// 从 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` 方法中添加自定义过滤逻辑:
|
||
|
||
```java
|
||
// 排除敏感接口
|
||
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
|