📅 创建日期:2026-06-16
⚠️ 重要提示:异步线程中无法获取HTTP请求信息,必须在Controller层填充
OperationAuditLogService使用@Async异步记录日志,在异步线程中无法通过RequestContextHolder获取HTTP请求信息(IP、User-Agent等)。
提供两种使用方式:
logWithRequestInfo()方法,自动在同步线程中获取请求信息getClientIpFromRequest()和getUserAgentFromRequest()手动获取@RestController
@RequestMapping("/api/admin/user-level-config")
@RequiredArgsConstructor
public class UserLevelConfigController {
private final OperationAuditLogService auditLogService;
/**
* 创建等级配置版本
*/
@PostMapping("/version")
public Result<Long> createVersion(@RequestBody CreateVersionRequest request,
@AuthenticationPrincipal UserDetails userDetails) {
Long versionId = userLevelConfigService.createVersion(request);
// ✅ 推荐用法:一行代码搞定
auditLogService.logWithRequestInfo(
AuditLogBuilder.builder()
.operatorId(userDetails.getUserId())
.operatorName(userDetails.getNickname())
.operatorRole("ADMIN")
.operationType(OperationType.LEVEL_VERSION_CREATE.getCode())
.module("等级配置")
.description("创建等级配置版本: " + request.getVersion())
.targetType("LEVEL_CONFIG")
.targetId(versionId)
.targetIdentifier(request.getVersion())
.result("SUCCESS")
.isSensitive(false)
.remark("版本号: " + request.getVersion())
);
return Result.success(versionId);
}
}
优点:
@PostMapping("/bind")
public Result<Void> bindAccount(@RequestBody BindAccountRequest request,
@AuthenticationPrincipal UserDetails userDetails) {
platformAccountService.bindAccount(userDetails.getUserId(), request);
// 手动构建builder
AuditLogBuilder builder = AuditLogBuilder.builder()
.operatorId(userDetails.getUserId())
.operatorName(userDetails.getNickname())
.operatorRole("USER")
.operationType(OperationType.ACCOUNT_BIND.getCode())
.module("平台账号")
.description("绑定" + request.getPlatformName() + "账号")
.targetType("ACCOUNT")
.targetIdentifier(request.getPlatformCode())
.result("SUCCESS");
// ✅ 手动填充请求信息
builder.ipAddress(OperationAuditLogService.getClientIpFromRequest());
builder.userAgent(OperationAuditLogService.getUserAgentFromRequest());
// 异步记录
auditLogService.logOperation(builder);
return Result.success();
}
@PostMapping("/migrate-users")
public Result<Integer> batchMigrateUsers(@RequestBody MigrateUsersRequest request,
@AuthenticationPrincipal UserDetails userDetails) {
int count = userLevelConfigService.batchMigrateUsers(
request.getTargetVersionId(),
request.getUserIds(),
userDetails.getUserId(),
request.getRemark()
);
// ✅ 使用快捷方法
auditLogService.logSuccess(
userDetails.getUserId(),
userDetails.getNickname(),
"ADMIN",
OperationType.LEVEL_USER_BATCH_MIGRATE,
"批量迁移用户",
null, // targetId
null, // beforeData
Map.of("migratedCount", count), // afterData
request.getRemark()
);
// 注意:快捷方法不会自动填充请求信息,需要手动调用logWithRequestInfo或手动填充
return Result.success(count);
}
try {
platformAccountService.verifyAccount(userId, platformCode);
} catch (Exception e) {
// ✅ 记录失败操作
auditLogService.logFailure(
userId,
userName,
"USER",
OperationType.ACCOUNT_VERIFY,
"验证" + platformName + "账号",
null,
e.getMessage()
);
throw new BusinessException("账号验证失败: " + e.getMessage());
}
/**
* 批量迁移用户到新版本(敏感操作)
*/
@PostMapping("/migrate-users")
public Result<Integer> batchMigrateUsers(@RequestBody MigrateUsersRequest request,
@AuthenticationPrincipal UserDetails userDetails) {
Long operatorId = userDetails.getUserId();
String operatorName = userDetails.getNickname();
try {
// 执行迁移
int count = userLevelConfigService.batchMigrateUsers(
request.getTargetVersionId(),
request.getUserIds(),
operatorId,
request.getRemark()
);
// ✅ 记录成功日志(敏感操作)
auditLogService.logWithRequestInfo(
AuditLogBuilder.builder()
.operatorId(operatorId)
.operatorName(operatorName)
.operatorRole("ADMIN")
.operationType(OperationType.LEVEL_USER_BATCH_MIGRATE.getCode())
.module("等级配置")
.description("批量迁移" + count + "个用户到新版本")
.targetType("USER")
.targetId(null)
.targetIdentifier("批量迁移")
.beforeData(Map.of("userCount", request.getUserIds().size()))
.afterData(Map.of("migratedCount", count))
.result("SUCCESS")
.isSensitive(true) // ⚠️ 标记为敏感操作
.remark(request.getRemark())
);
return Result.success(count);
} catch (Exception e) {
// ✅ 记录失败日志
auditLogService.logWithRequestInfo(
AuditLogBuilder.builder()
.operatorId(operatorId)
.operatorName(operatorName)
.operatorRole("ADMIN")
.operationType(OperationType.LEVEL_USER_BATCH_MIGRATE.getCode())
.module("等级配置")
.description("批量迁移用户失败")
.targetType("USER")
.result("FAILED")
.errorMessage(e.getMessage())
.isSensitive(true) // ⚠️ 敏感操作
);
throw new BusinessException("批量迁移失败: " + e.getMessage());
}
}
/**
* 调整用户等级
*/
@PutMapping("/user/{userId}/level")
public Result<Void> adjustUserLevel(@PathVariable Long userId,
@RequestBody AdjustLevelRequest request,
@AuthenticationPrincipal UserDetails userDetails) {
// 查询调整前的等级
UserLevelVersionRelation oldRelation = versionRelationMapper.selectByUserId(userId);
String oldLevelCode = oldRelation.getLevelCode();
// 执行调整
userLevelConfigService.adjustUserLevel(userId, request.getNewLevelCode());
// ✅ 记录数据变更(包含前后快照)
auditLogService.logWithRequestInfo(
AuditLogBuilder.builder()
.operatorId(userDetails.getUserId())
.operatorName(userDetails.getNickname())
.operatorRole("ADMIN")
.operationType(OperationType.LEVEL_USER_ADJUST.getCode())
.module("等级配置")
.description("调整用户等级: " + oldLevelCode + " → " + request.getNewLevelCode())
.targetType("USER")
.targetId(userId)
.targetIdentifier("用户ID: " + userId)
.beforeData(Map.of(
"levelCode", oldLevelCode,
"configVersionId", oldRelation.getConfigVersionId()
))
.afterData(Map.of(
"levelCode", request.getNewLevelCode()
))
.result("SUCCESS")
.isSensitive(true)
.remark(request.getReason())
);
return Result.success();
}
@Service
public class UserService {
@Autowired
private OperationAuditLogService auditLogService;
public void updateUser(Long userId, UserInfo userInfo) {
// 业务逻辑...
// ❌ 错误:在Service层调用,无法获取HTTP请求信息
auditLogService.logOperation(
AuditLogBuilder.builder()
.operatorId(userId)
// ...
);
}
}
正确做法:在Controller层调用,或使用logWithRequestInfo()
// ❌ 错误:删除用户是敏感操作,但没有标记
auditLogService.logWithRequestInfo(
AuditLogBuilder.builder()
.operationType(OperationType.USER_DELETE.getCode())
.isSensitive(false) // ❌ 应该是true
);
正确做法:
// ✅ 正确:标记为敏感操作
auditLogService.logWithRequestInfo(
AuditLogBuilder.builder()
.operationType(OperationType.USER_DELETE.getCode())
.isSensitive(true) // ✅ 敏感操作
);
@Async
public void asyncMethod() {
// ❌ 错误:异步线程中RequestContextHolder为null
String ip = OperationAuditLogService.getClientIpFromRequest(); // 返回"unknown"
}
正确做法:在调用异步方法前获取并传递
public void syncMethod() {
// ✅ 在同步线程中获取
String ip = OperationAuditLogService.getClientIpFromRequest();
String userAgent = OperationAuditLogService.getUserAgentFromRequest();
// 传递给异步方法
asyncMethod(ip, userAgent);
}
@Async
public void asyncMethod(String ip, String userAgent) {
// 使用传入的参数
}
// 查询最近50条操作日志
List<OperationAuditLog> logs = auditLogService.getUserOperationLogs(userId, 50);
// 查询某个等级配置版本的所有操作历史
List<OperationAuditLog> history = auditLogService.getTargetOperationHistory(
"LEVEL_CONFIG",
versionId,
100
);
Page<OperationAuditLog> page = auditLogService.queryAuditLogs(
"等级配置", // module
"LEVEL_VERSION_ACTIVATE", // operationType
null, // operatorId
startTime, // startTime
endTime, // endTime
true, // isSensitive(只查敏感操作)
1, // pageNum
20 // pageSize
);
// 查询最近7天的敏感操作
LocalDateTime sevenDaysAgo = LocalDateTime.now().minusDays(7);
List<OperationAuditLog> sensitiveLogs = auditLogService.getSensitiveLogs(sevenDaysAgo);
@RestController
public class MyController {
@Autowired
private OperationAuditLogService auditLogService;
@PostMapping("/xxx")
public Result<?> doSomething(...) {
// 执行业务逻辑
service.doBusiness();
// ✅ 在Controller层记录日志
auditLogService.logWithRequestInfo(...);
return Result.success();
}
}
try {
service.doBusiness();
// 记录成功
auditLogService.logWithRequestInfo(...result("SUCCESS")...);
} catch (Exception e) {
// 记录失败
auditLogService.logWithRequestInfo(...result("FAILED").errorMessage(e.getMessage())...);
throw e;
}
以下操作应标记为敏感操作(isSensitive=true):
对于数据变更操作,记录beforeData和afterData:
.beforeData(Map.of("oldValue", oldValue))
.afterData(Map.of("newValue", newValue))
如有问题,请联系开发团队。
📌 总结:
logWithRequestInfo()方法,自动获取请求信息isSensitive=true