feat: 优化日志记录,避免在登录和错误处理时输出敏感信息
This commit is contained in:
@@ -28,7 +28,8 @@ public class AuthController {
|
|||||||
@PostMapping("/login")
|
@PostMapping("/login")
|
||||||
@ResponseStatus(HttpStatus.OK)
|
@ResponseStatus(HttpStatus.OK)
|
||||||
public Mono<LoginResponse> login(@Valid @RequestBody LoginRequest req) {
|
public Mono<LoginResponse> login(@Valid @RequestBody LoginRequest req) {
|
||||||
log.info("/api/auth/login called username={}", req.getUsername());
|
// Avoid logging raw usernames at info level
|
||||||
|
log.debug("/api/auth/login called");
|
||||||
return authService.login(req);
|
return authService.login(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ public class QrProxyController {
|
|||||||
// 通过codeNo查询machineId
|
// 通过codeNo查询machineId
|
||||||
String machineId = linkStatusService.getMechainIdByCode(codeNo);
|
String machineId = linkStatusService.getMechainIdByCode(codeNo);
|
||||||
if (machineId == null) {
|
if (machineId == null) {
|
||||||
log.warn("无法找到codeNo对应的machineId: {}", codeNo);
|
log.warn("无法找到codeNo对应的machineId");
|
||||||
return createNotFoundResponseMono();
|
return createNotFoundResponseMono();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,11 +70,11 @@ public class QrProxyController {
|
|||||||
.header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=qr.png")
|
.header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=qr.png")
|
||||||
.body(bytes))
|
.body(bytes))
|
||||||
.onErrorResume(WebClientResponseException.NotFound.class, ex -> {
|
.onErrorResume(WebClientResponseException.NotFound.class, ex -> {
|
||||||
log.warn("图片不存在: path={}", path);
|
log.warn("图片不存在");
|
||||||
return createNotFoundResponseMono();
|
return createNotFoundResponseMono();
|
||||||
})
|
})
|
||||||
.onErrorResume(WebClientResponseException.class, ex -> {
|
.onErrorResume(WebClientResponseException.class, ex -> {
|
||||||
log.warn("获取图片失败: path={}, status={}, error={}", path, ex.getStatusCode(), ex.getMessage());
|
log.warn("获取图片失败: status={}, error={}", ex.getStatusCode(), ex.getMessage());
|
||||||
return Mono.just(ResponseEntity.status(ex.getStatusCode()).build());
|
return Mono.just(ResponseEntity.status(ex.getStatusCode()).build());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -86,7 +86,7 @@ public class QrProxyController {
|
|||||||
.flatMap(linkStatus -> {
|
.flatMap(linkStatus -> {
|
||||||
String machineId = linkStatus.getMachineId();
|
String machineId = linkStatus.getMachineId();
|
||||||
if (machineId == null) {
|
if (machineId == null) {
|
||||||
log.warn("无法找到codeNo对应的machineId: {}", codeNo);
|
log.warn("无法找到codeNo对应的machineId");
|
||||||
return createNotFoundResponseMono();
|
return createNotFoundResponseMono();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,16 +98,16 @@ public class QrProxyController {
|
|||||||
.header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=homepage.png")
|
.header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=homepage.png")
|
||||||
.body(bytes))
|
.body(bytes))
|
||||||
.onErrorResume(WebClientResponseException.NotFound.class, ex -> {
|
.onErrorResume(WebClientResponseException.NotFound.class, ex -> {
|
||||||
log.warn("图片不存在: path={}", path);
|
log.warn("图片不存在");
|
||||||
return createNotFoundResponseMono();
|
return createNotFoundResponseMono();
|
||||||
})
|
})
|
||||||
.onErrorResume(WebClientResponseException.class, ex -> {
|
.onErrorResume(WebClientResponseException.class, ex -> {
|
||||||
log.warn("获取图片失败: path={}, status={}, error={}", path, ex.getStatusCode(), ex.getMessage());
|
log.warn("获取图片失败: status={}, error={}", ex.getStatusCode(), ex.getMessage());
|
||||||
return Mono.just(ResponseEntity.status(ex.getStatusCode()).build());
|
return Mono.just(ResponseEntity.status(ex.getStatusCode()).build());
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.onErrorResume(Exception.class, ex -> {
|
.onErrorResume(Exception.class, ex -> {
|
||||||
log.error("获取链接状态失败: codeNo={}, error={}", codeNo, ex.getMessage());
|
log.error("获取链接状态失败: {}", ex.getMessage());
|
||||||
return createInternalServerErrorResponseMono();
|
return createInternalServerErrorResponseMono();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -119,7 +119,7 @@ public class QrProxyController {
|
|||||||
.flatMap(linkStatus -> {
|
.flatMap(linkStatus -> {
|
||||||
String machineId = linkStatus.getMachineId();
|
String machineId = linkStatus.getMachineId();
|
||||||
if (machineId == null) {
|
if (machineId == null) {
|
||||||
log.warn("无法找到codeNo对应的machineId: {}", codeNo);
|
log.warn("无法找到codeNo对应的machineId");
|
||||||
return createNotFoundResponseMono();
|
return createNotFoundResponseMono();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,16 +131,16 @@ public class QrProxyController {
|
|||||||
.header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=first-reward.png")
|
.header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=first-reward.png")
|
||||||
.body(bytes))
|
.body(bytes))
|
||||||
.onErrorResume(WebClientResponseException.NotFound.class, ex -> {
|
.onErrorResume(WebClientResponseException.NotFound.class, ex -> {
|
||||||
log.warn("图片不存在: path={}", path);
|
log.warn("图片不存在");
|
||||||
return createNotFoundResponseMono();
|
return createNotFoundResponseMono();
|
||||||
})
|
})
|
||||||
.onErrorResume(WebClientResponseException.class, ex -> {
|
.onErrorResume(WebClientResponseException.class, ex -> {
|
||||||
log.warn("获取图片失败: path={}, status={}, error={}", path, ex.getStatusCode(), ex.getMessage());
|
log.warn("获取图片失败: status={}, error={}", ex.getStatusCode(), ex.getMessage());
|
||||||
return Mono.just(ResponseEntity.status(ex.getStatusCode()).build());
|
return Mono.just(ResponseEntity.status(ex.getStatusCode()).build());
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.onErrorResume(Exception.class, ex -> {
|
.onErrorResume(Exception.class, ex -> {
|
||||||
log.error("获取链接状态失败: codeNo={}, error={}", codeNo, ex.getMessage());
|
log.error("获取链接状态失败: {}", ex.getMessage());
|
||||||
return createInternalServerErrorResponseMono();
|
return createInternalServerErrorResponseMono();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -152,7 +152,7 @@ public class QrProxyController {
|
|||||||
.flatMap(linkStatus -> {
|
.flatMap(linkStatus -> {
|
||||||
String machineId = linkStatus.getMachineId();
|
String machineId = linkStatus.getMachineId();
|
||||||
if (machineId == null) {
|
if (machineId == null) {
|
||||||
log.warn("无法找到codeNo对应的machineId: {}", codeNo);
|
log.warn("无法找到codeNo对应的machineId");
|
||||||
return createNotFoundResponseMono();
|
return createNotFoundResponseMono();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,16 +164,16 @@ public class QrProxyController {
|
|||||||
.header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=mid-reward.png")
|
.header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=mid-reward.png")
|
||||||
.body(bytes))
|
.body(bytes))
|
||||||
.onErrorResume(WebClientResponseException.NotFound.class, ex -> {
|
.onErrorResume(WebClientResponseException.NotFound.class, ex -> {
|
||||||
log.warn("图片不存在: path={}", path);
|
log.warn("图片不存在");
|
||||||
return createNotFoundResponseMono();
|
return createNotFoundResponseMono();
|
||||||
})
|
})
|
||||||
.onErrorResume(WebClientResponseException.class, ex -> {
|
.onErrorResume(WebClientResponseException.class, ex -> {
|
||||||
log.warn("获取图片失败: path={}, status={}, error={}", path, ex.getStatusCode(), ex.getMessage());
|
log.warn("获取图片失败: status={}, error={}", ex.getStatusCode(), ex.getMessage());
|
||||||
return Mono.just(ResponseEntity.status(ex.getStatusCode()).build());
|
return Mono.just(ResponseEntity.status(ex.getStatusCode()).build());
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.onErrorResume(Exception.class, ex -> {
|
.onErrorResume(Exception.class, ex -> {
|
||||||
log.error("获取链接状态失败: codeNo={}, error={}", codeNo, ex.getMessage());
|
log.error("获取链接状态失败: {}", ex.getMessage());
|
||||||
return createInternalServerErrorResponseMono();
|
return createInternalServerErrorResponseMono();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -315,4 +315,3 @@ public class QrProxyController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package com.gameplatform.server.mapper.lock;
|
||||||
|
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import org.apache.ibatis.annotations.Select;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface LockMapper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to acquire a named MySQL advisory lock. Returns 1 if acquired, 0 if timeout, NULL on error.
|
||||||
|
*/
|
||||||
|
@Select("SELECT GET_LOCK(#{name}, #{timeoutSeconds})")
|
||||||
|
Integer getLock(@Param("name") String name, @Param("timeoutSeconds") int timeoutSeconds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Release the named advisory lock. Returns 1 if released, 0 if not held, NULL on error.
|
||||||
|
*/
|
||||||
|
@Select("SELECT RELEASE_LOCK(#{name})")
|
||||||
|
Integer releaseLock(@Param("name") String name);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -124,7 +124,12 @@ public class MachineCooldownService {
|
|||||||
*/
|
*/
|
||||||
@Transactional
|
@Transactional
|
||||||
public void addMachineToCooldown(String machineId, String reason) {
|
public void addMachineToCooldown(String machineId, String reason) {
|
||||||
addMachineToCooldown(machineId, reason, null);
|
try {
|
||||||
|
addMachineToCooldown(machineId, reason, null);
|
||||||
|
} catch (RuntimeException ex) {
|
||||||
|
// 当上层已完成占用(或并发占用导致唯一键冲突)时,吞掉异常以便上层逻辑继续
|
||||||
|
log.warn("添加冷却记录失败或已存在,machineId={},原因={}(忽略)", machineId, ex.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -144,10 +149,10 @@ public class MachineCooldownService {
|
|||||||
LocalDateTime cooldownEndTime = now.plusMinutes(COOLDOWN_MINUTES);
|
LocalDateTime cooldownEndTime = now.plusMinutes(COOLDOWN_MINUTES);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 先移除该设备现有的活跃冷却记录
|
// 先移除该设备现有的活跃冷却记录(若存在非并发场景下的残留)
|
||||||
machineCooldownMapper.removeMachineCooldown(machineId);
|
machineCooldownMapper.removeMachineCooldown(machineId);
|
||||||
|
|
||||||
// 创建新的冷却记录
|
// 创建新的冷却记录(依赖数据库唯一约束防止并发重复占用)
|
||||||
MachineCooldown cooldown = new MachineCooldown(
|
MachineCooldown cooldown = new MachineCooldown(
|
||||||
machineId, now, cooldownEndTime, reason, linkTaskId);
|
machineId, now, cooldownEndTime, reason, linkTaskId);
|
||||||
machineCooldownMapper.insert(cooldown);
|
machineCooldownMapper.insert(cooldown);
|
||||||
@@ -160,8 +165,8 @@ public class MachineCooldownService {
|
|||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("将机器{}加入冷却队列失败:{}", machineId, e.getMessage(), e);
|
log.error("将机器{}加入冷却队列失败:{}", machineId, e.getMessage(), e);
|
||||||
// 即使数据库操作失败,也要更新缓存作为备用
|
// 抛出异常,交由上层流程回滚/重试,避免同一设备被并发占用
|
||||||
machineCooldownCache.put(machineId, now);
|
throw new RuntimeException("设备正忙或分配冲突,请稍后重试");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
-- Add a unique constraint to ensure a device has at most one ACTIVE cooldown record at a time.
|
||||||
|
-- This helps prevent concurrent assignments of the same machine to multiple links.
|
||||||
|
|
||||||
|
ALTER TABLE machine_cooldown
|
||||||
|
ADD UNIQUE KEY ux_machine_cooldown_active (machine_id, status);
|
||||||
|
|
||||||
Reference in New Issue
Block a user