feat: 在ScriptClient中添加操作日志记录功能,优化设备状态接口调用的成功与失败响应处理;在DeviceStats中优化登录时间检查逻辑;启用定时任务检查空闲设备状态
This commit is contained in:
BIN
logs/server.2025-09-20.0.log.gz
Normal file
BIN
logs/server.2025-09-20.0.log.gz
Normal file
Binary file not shown.
@@ -0,0 +1,72 @@
|
||||
package com.gameplatform.server.controller;
|
||||
|
||||
import com.gameplatform.server.mapper.log.ScriptOperationLogMapper;
|
||||
import com.gameplatform.server.model.entity.log.ScriptOperationLog;
|
||||
import com.gameplatform.server.model.enums.ScriptOperationType;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 脚本操作日志查询接口
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/admin/script-operation-log")
|
||||
@Slf4j
|
||||
public class ScriptOperationLogController {
|
||||
|
||||
@Autowired
|
||||
private ScriptOperationLogMapper logMapper;
|
||||
|
||||
/**
|
||||
* 根据设备ID查询操作记录
|
||||
*/
|
||||
// @GetMapping("/machine/{machineId}")
|
||||
// public List<ScriptOperationLog> getByMachineId(@PathVariable String machineId,
|
||||
// @RequestParam(defaultValue = "10") Integer limit) {
|
||||
// return logMapper.findByMachineId(machineId, limit);
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * 根据操作类型查询记录
|
||||
// */
|
||||
// @GetMapping("/type/{operationType}")
|
||||
// public List<ScriptOperationLog> getByOperationType(@PathVariable ScriptOperationType operationType,
|
||||
// @RequestParam(defaultValue = "10") Integer limit) {
|
||||
// return logMapper.findByOperationType(operationType, limit);
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * 查询失败的操作记录
|
||||
// */
|
||||
// @GetMapping("/failed")
|
||||
// public List<ScriptOperationLog> getFailedOperations(@RequestParam(defaultValue = "10") Integer limit) {
|
||||
// LocalDateTime yesterday = LocalDateTime.now().minusDays(1);
|
||||
// LocalDateTime now = LocalDateTime.now();
|
||||
// return logMapper.findFailedOperations(yesterday, now, limit);
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * 获取操作统计信息
|
||||
// */
|
||||
// @GetMapping("/statistics")
|
||||
// public List<Map<String, Object>> getStatistics(@RequestParam(defaultValue = "1") Integer days) {
|
||||
// LocalDateTime startTime = LocalDateTime.now().minusDays(days);
|
||||
// LocalDateTime endTime = LocalDateTime.now();
|
||||
// return logMapper.getOperationStatistics(startTime, endTime);
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * 查询最近的操作记录
|
||||
// */
|
||||
// @GetMapping("/recent")
|
||||
// public List<ScriptOperationLog> getRecentOperations(@RequestParam(defaultValue = "20") Integer limit) {
|
||||
// LocalDateTime yesterday = LocalDateTime.now().minusDays(1);
|
||||
// LocalDateTime now = LocalDateTime.now();
|
||||
// return logMapper.findByTimeRange(yesterday, now, limit);
|
||||
// }
|
||||
}
|
||||
@@ -308,7 +308,8 @@ public class DeviceStats {
|
||||
int completed = 0;
|
||||
for (LinkTask task : loggedInTasks) {
|
||||
LocalDateTime loginAt = task.getLoginAt();
|
||||
boolean over3m = loginAt != null && loginAt.isBefore(now.minusMinutes(3));
|
||||
// 检查登录时间到现在是否已经超过3分钟
|
||||
boolean over3m = loginAt != null && Duration.between(loginAt, now).toMinutes() >= 3;
|
||||
if (!over3m) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
package com.gameplatform.server.mapper.log;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.gameplatform.server.model.entity.log.ScriptOperationLog;
|
||||
import com.gameplatform.server.model.enums.ScriptOperationType;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 脚本操作记录Mapper
|
||||
*/
|
||||
@Mapper
|
||||
public interface ScriptOperationLogMapper extends BaseMapper<ScriptOperationLog> {
|
||||
|
||||
/**
|
||||
* 插入操作记录
|
||||
*/
|
||||
int insert(ScriptOperationLog log);
|
||||
|
||||
/**
|
||||
* 更新操作记录
|
||||
*/
|
||||
int update(ScriptOperationLog log);
|
||||
|
||||
/**
|
||||
* 根据ID查询
|
||||
*/
|
||||
ScriptOperationLog findById(@Param("id") Long id);
|
||||
|
||||
/**
|
||||
* 根据设备ID查询操作记录
|
||||
*/
|
||||
List<ScriptOperationLog> findByMachineId(@Param("machineId") String machineId,
|
||||
@Param("limit") Integer limit);
|
||||
|
||||
/**
|
||||
* 根据操作类型查询记录
|
||||
*/
|
||||
List<ScriptOperationLog> findByOperationType(@Param("operationType") ScriptOperationType operationType,
|
||||
@Param("limit") Integer limit);
|
||||
|
||||
/**
|
||||
* 根据时间范围查询操作记录
|
||||
*/
|
||||
List<ScriptOperationLog> findByTimeRange(@Param("startTime") LocalDateTime startTime,
|
||||
@Param("endTime") LocalDateTime endTime,
|
||||
@Param("limit") Integer limit);
|
||||
|
||||
/**
|
||||
* 查询某个设备特定操作类型的记录
|
||||
*/
|
||||
List<ScriptOperationLog> findByMachineIdAndOperationType(@Param("machineId") String machineId,
|
||||
@Param("operationType") ScriptOperationType operationType,
|
||||
@Param("limit") Integer limit);
|
||||
|
||||
/**
|
||||
* 查询失败的操作记录
|
||||
*/
|
||||
List<ScriptOperationLog> findFailedOperations(@Param("startTime") LocalDateTime startTime,
|
||||
@Param("endTime") LocalDateTime endTime,
|
||||
@Param("limit") Integer limit);
|
||||
|
||||
/**
|
||||
* 统计某个时间段内各操作类型的成功率
|
||||
*/
|
||||
List<java.util.Map<String, Object>> getOperationStatistics(@Param("startTime") LocalDateTime startTime,
|
||||
@Param("endTime") LocalDateTime endTime);
|
||||
|
||||
/**
|
||||
* 删除指定时间之前的记录(用于数据清理)
|
||||
*/
|
||||
int deleteOldRecords(@Param("beforeTime") LocalDateTime beforeTime);
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
package com.gameplatform.server.model.entity.log;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.gameplatform.server.model.enums.ScriptOperationType;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 脚本操作记录实体
|
||||
*/
|
||||
@TableName("script_operation_log")
|
||||
public class ScriptOperationLog {
|
||||
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
@TableField("operation_type")
|
||||
private ScriptOperationType operationType;
|
||||
|
||||
@TableField("machine_id")
|
||||
private String machineId;
|
||||
|
||||
@TableField("request_url")
|
||||
private String requestUrl;
|
||||
|
||||
@TableField("request_params")
|
||||
private String requestParams; // JSON字符串
|
||||
|
||||
@TableField("response_result")
|
||||
private String responseResult;
|
||||
|
||||
@TableField("success")
|
||||
private Boolean success;
|
||||
|
||||
@TableField("error_message")
|
||||
private String errorMessage;
|
||||
|
||||
@TableField("duration_ms")
|
||||
private Integer durationMs;
|
||||
|
||||
@TableField("request_time")
|
||||
private LocalDateTime requestTime;
|
||||
|
||||
@TableField("response_time")
|
||||
private LocalDateTime responseTime;
|
||||
|
||||
@TableField("created_at")
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
@TableField("updated_at")
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
// 构造函数
|
||||
public ScriptOperationLog() {}
|
||||
|
||||
public ScriptOperationLog(ScriptOperationType operationType, String machineId, String requestUrl) {
|
||||
this.operationType = operationType;
|
||||
this.machineId = machineId;
|
||||
this.requestUrl = requestUrl;
|
||||
this.requestTime = LocalDateTime.now();
|
||||
this.createdAt = LocalDateTime.now();
|
||||
this.updatedAt = LocalDateTime.now();
|
||||
this.success = false; // 默认失败,成功时再更新
|
||||
}
|
||||
|
||||
// Getter和Setter方法
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public ScriptOperationType getOperationType() {
|
||||
return operationType;
|
||||
}
|
||||
|
||||
public void setOperationType(ScriptOperationType operationType) {
|
||||
this.operationType = operationType;
|
||||
}
|
||||
|
||||
public String getMachineId() {
|
||||
return machineId;
|
||||
}
|
||||
|
||||
public void setMachineId(String machineId) {
|
||||
this.machineId = machineId;
|
||||
}
|
||||
|
||||
public String getRequestUrl() {
|
||||
return requestUrl;
|
||||
}
|
||||
|
||||
public void setRequestUrl(String requestUrl) {
|
||||
this.requestUrl = requestUrl;
|
||||
}
|
||||
|
||||
public String getRequestParams() {
|
||||
return requestParams;
|
||||
}
|
||||
|
||||
public void setRequestParams(String requestParams) {
|
||||
this.requestParams = requestParams;
|
||||
}
|
||||
|
||||
public String getResponseResult() {
|
||||
return responseResult;
|
||||
}
|
||||
|
||||
public void setResponseResult(String responseResult) {
|
||||
this.responseResult = responseResult;
|
||||
}
|
||||
|
||||
public Boolean getSuccess() {
|
||||
return success;
|
||||
}
|
||||
|
||||
public void setSuccess(Boolean success) {
|
||||
this.success = success;
|
||||
}
|
||||
|
||||
public String getErrorMessage() {
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
public void setErrorMessage(String errorMessage) {
|
||||
this.errorMessage = errorMessage;
|
||||
}
|
||||
|
||||
public Integer getDurationMs() {
|
||||
return durationMs;
|
||||
}
|
||||
|
||||
public void setDurationMs(Integer durationMs) {
|
||||
this.durationMs = durationMs;
|
||||
}
|
||||
|
||||
public LocalDateTime getRequestTime() {
|
||||
return requestTime;
|
||||
}
|
||||
|
||||
public void setRequestTime(LocalDateTime requestTime) {
|
||||
this.requestTime = requestTime;
|
||||
}
|
||||
|
||||
public LocalDateTime getResponseTime() {
|
||||
return responseTime;
|
||||
}
|
||||
|
||||
public void setResponseTime(LocalDateTime responseTime) {
|
||||
this.responseTime = responseTime;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public void setCreatedAt(LocalDateTime createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
public LocalDateTime getUpdatedAt() {
|
||||
return updatedAt;
|
||||
}
|
||||
|
||||
public void setUpdatedAt(LocalDateTime updatedAt) {
|
||||
this.updatedAt = updatedAt;
|
||||
}
|
||||
|
||||
// 便捷方法:设置成功响应
|
||||
public void setSuccessResponse(String result, LocalDateTime responseTime, long durationMs) {
|
||||
this.responseResult = result;
|
||||
this.success = true;
|
||||
this.responseTime = responseTime;
|
||||
this.durationMs = (int) durationMs;
|
||||
this.updatedAt = LocalDateTime.now();
|
||||
}
|
||||
|
||||
// 便捷方法:设置失败响应
|
||||
public void setFailureResponse(String errorMessage, LocalDateTime responseTime, long durationMs) {
|
||||
this.errorMessage = errorMessage;
|
||||
this.success = false;
|
||||
this.responseTime = responseTime;
|
||||
this.durationMs = (int) durationMs;
|
||||
this.updatedAt = LocalDateTime.now();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ScriptOperationLog{" +
|
||||
"id=" + id +
|
||||
", operationType=" + operationType +
|
||||
", machineId='" + machineId + '\'' +
|
||||
", requestUrl='" + requestUrl + '\'' +
|
||||
", success=" + success +
|
||||
", durationMs=" + durationMs +
|
||||
", requestTime=" + requestTime +
|
||||
", responseTime=" + responseTime +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.gameplatform.server.model.enums;
|
||||
|
||||
/**
|
||||
* 脚本操作类型枚举
|
||||
*/
|
||||
public enum ScriptOperationType {
|
||||
SELECT_REGION("选区操作"),
|
||||
REFRESH("判断刷新"),
|
||||
SAVE_TOTAL_TIMES("保存总次数"),
|
||||
REFUND_ORDER("退单操作");
|
||||
|
||||
private final String description;
|
||||
|
||||
ScriptOperationType(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,9 @@ package com.gameplatform.server.service.external;
|
||||
|
||||
import com.gameplatform.server.annotation.RepeatCall;
|
||||
import com.gameplatform.server.model.dto.device.DeviceStatusResponse;
|
||||
import com.gameplatform.server.model.entity.log.ScriptOperationLog;
|
||||
import com.gameplatform.server.service.device.DeviceStatusService;
|
||||
import com.gameplatform.server.service.log.ScriptOperationLogService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
@@ -27,6 +29,7 @@ public class ScriptClient {
|
||||
private final String appBaseUrl;
|
||||
private final DeviceStatusService deviceStatusService;
|
||||
private final ApplicationEventPublisher eventPublisher;
|
||||
private final ScriptOperationLogService operationLogService;
|
||||
|
||||
public ScriptClient(
|
||||
@Value("${script.base-url}") String baseUrl,
|
||||
@@ -35,13 +38,15 @@ public class ScriptClient {
|
||||
@Value("${script.read-timeout-ms:5000}") int readTimeoutMs,
|
||||
@Value("${app.base-url}") String appBaseUrl,
|
||||
DeviceStatusService deviceStatusService,
|
||||
ApplicationEventPublisher eventPublisher
|
||||
ApplicationEventPublisher eventPublisher,
|
||||
ScriptOperationLogService operationLogService
|
||||
) {
|
||||
this.baseUrl = baseUrl;
|
||||
this.apiBaseUrl = apiBaseUrl;
|
||||
this.appBaseUrl = appBaseUrl;
|
||||
this.deviceStatusService = deviceStatusService;
|
||||
this.eventPublisher = eventPublisher;
|
||||
this.operationLogService = operationLogService;
|
||||
this.webClient = WebClient.builder()
|
||||
.baseUrl(baseUrl)
|
||||
.exchangeStrategies(ExchangeStrategies.builder()
|
||||
@@ -188,11 +193,16 @@ public class ScriptClient {
|
||||
log.warn("选区操作失败: 区域={} 必须是Q或V", region);
|
||||
return Mono.just("选区操作失败");
|
||||
}
|
||||
|
||||
// 构建选区URL,使用设备编号作为参数名,区域作为参数值
|
||||
// 示例: {apiBaseUrl}/yijianwan_netfile/saveMsg?文件名=判断系统&f1=Q
|
||||
String url = String.format(apiBaseUrl + "/yijianwan_netfile/saveMsg?文件名=判断系统&%s=%s", deviceId, region);
|
||||
log.info("选区操作: 设备={}, 区域={}, url={}", deviceId, region, url);
|
||||
|
||||
// 创建操作日志记录
|
||||
ScriptOperationLog operationLog = operationLogService.logSelectRegion(deviceId, url, region);
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
return webClient.get() // 根据您的curl示例,这应该是GET请求
|
||||
.uri(url)
|
||||
.accept(MediaType.TEXT_PLAIN)
|
||||
@@ -201,9 +211,13 @@ public class ScriptClient {
|
||||
.timeout(Duration.ofSeconds(10))
|
||||
.doOnSuccess(result -> {
|
||||
log.info("选区操作成功: 设备={}, 区域={}, 结果={}", deviceId, region, result);
|
||||
// 记录成功响应
|
||||
operationLogService.recordSuccess(operationLog, result, startTime);
|
||||
})
|
||||
.doOnError(e -> {
|
||||
log.error("选区操作失败: 设备={}, 区域={}, 错误={}", deviceId, region, e.toString());
|
||||
// 记录失败响应
|
||||
operationLogService.recordFailure(operationLog, e.toString(), startTime);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -216,14 +230,27 @@ public class ScriptClient {
|
||||
public Mono<String> refresh(String machineId) {
|
||||
String url = String.format(apiBaseUrl + "/yijianwan_netfile/saveMsg?文件名=判断刷新&%s=刷新", machineId);
|
||||
log.info("调用判断刷新接口: {}", url);
|
||||
|
||||
// 创建操作日志记录
|
||||
ScriptOperationLog operationLog = operationLogService.logRefresh(machineId, url);
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
return webClient.get()
|
||||
.uri(url)
|
||||
.accept(MediaType.TEXT_PLAIN)
|
||||
.retrieve()
|
||||
.bodyToMono(String.class)
|
||||
.timeout(Duration.ofSeconds(10))
|
||||
.doOnSuccess(result -> log.info("判断刷新接口调用成功: result={}", result))
|
||||
.doOnError(e -> log.warn("判断刷新接口调用失败: {}", e.toString()));
|
||||
.doOnSuccess(result -> {
|
||||
log.info("判断刷新接口调用成功: result={}", result);
|
||||
// 记录成功响应
|
||||
operationLogService.recordSuccess(operationLog, result, startTime);
|
||||
})
|
||||
.doOnError(e -> {
|
||||
log.warn("判断刷新接口调用失败: {}", e.toString());
|
||||
// 记录失败响应
|
||||
operationLogService.recordFailure(operationLog, e.toString(), startTime);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -346,22 +373,36 @@ public class ScriptClient {
|
||||
|
||||
/**
|
||||
* 保存总次数(使用f4参数格式)
|
||||
* @param machineId 设备ID
|
||||
* @param times 总次数
|
||||
* @return 保存结果
|
||||
*/
|
||||
@RepeatCall(times = 3, description = "保存总次数")
|
||||
public Mono<String> saveTotalTimes(String meachainId,int times) {
|
||||
String url = String.format(apiBaseUrl + "/yijianwan_netfile/saveMsg?文件名=总次数&%s=%d", meachainId,times);
|
||||
public Mono<String> saveTotalTimes(String machineId, int times) {
|
||||
String url = String.format(apiBaseUrl + "/yijianwan_netfile/saveMsg?文件名=总次数&%s=%d", machineId, times);
|
||||
log.info("保存刷副本的次数的url: {}", url);
|
||||
log.info("开始调用保存总次数接口: times={}, url={}", times, url);
|
||||
|
||||
// 创建操作日志记录
|
||||
ScriptOperationLog operationLog = operationLogService.logSaveTotalTimes(machineId, url, times);
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
return webClient.get()
|
||||
.uri(url)
|
||||
.accept(MediaType.TEXT_PLAIN)
|
||||
.retrieve()
|
||||
.bodyToMono(String.class)
|
||||
.timeout(Duration.ofSeconds(10))
|
||||
.doOnSuccess(result -> log.info("保存总次数接口调用成功: url={}, result={}", url, result))
|
||||
.doOnError(e -> log.warn("保存总次数接口调用失败: times={}, error={}", times, e.toString()));
|
||||
.doOnSuccess(result -> {
|
||||
log.info("保存总次数接口调用成功: url={}, result={}", url, result);
|
||||
// 记录成功响应
|
||||
operationLogService.recordSuccess(operationLog, result, startTime);
|
||||
})
|
||||
.doOnError(e -> {
|
||||
log.warn("保存总次数接口调用失败: times={}, error={}", times, e.toString());
|
||||
// 记录失败响应
|
||||
operationLogService.recordFailure(operationLog, e.toString(), startTime);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -403,6 +444,10 @@ public class ScriptClient {
|
||||
String url = String.format(apiBaseUrl + "/yijianwan_netfile/saveMsg?文件名=判断退单&%s=T", machineId);
|
||||
log.info("调用退单接口: 设备={}, url={}", machineId, url);
|
||||
|
||||
// 创建操作日志记录
|
||||
ScriptOperationLog operationLog = operationLogService.logRefundOrder(machineId, url);
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
return webClient.get()
|
||||
.uri(url)
|
||||
.accept(MediaType.TEXT_PLAIN)
|
||||
@@ -411,9 +456,13 @@ public class ScriptClient {
|
||||
.timeout(Duration.ofSeconds(10))
|
||||
.doOnSuccess(result -> {
|
||||
log.info("退单接口调用成功: 设备={}, 结果={}", machineId, result);
|
||||
// 记录成功响应
|
||||
operationLogService.recordSuccess(operationLog, result, startTime);
|
||||
})
|
||||
.doOnError(e -> {
|
||||
log.error("退单接口调用失败: 设备={}, 错误={}", machineId, e.toString());
|
||||
// 记录失败响应
|
||||
operationLogService.recordFailure(operationLog, e.toString(), startTime);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
package com.gameplatform.server.service.log;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.gameplatform.server.mapper.log.ScriptOperationLogMapper;
|
||||
import com.gameplatform.server.model.entity.log.ScriptOperationLog;
|
||||
import com.gameplatform.server.model.enums.ScriptOperationType;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 脚本操作日志服务
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class ScriptOperationLogService {
|
||||
|
||||
@Autowired
|
||||
private ScriptOperationLogMapper logMapper;
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
/**
|
||||
* 创建操作记录
|
||||
*/
|
||||
public ScriptOperationLog createOperationLog(ScriptOperationType operationType, String machineId, String requestUrl) {
|
||||
ScriptOperationLog operationLog = new ScriptOperationLog(operationType, machineId, requestUrl);
|
||||
try {
|
||||
logMapper.insert(operationLog);
|
||||
log.debug("创建脚本操作记录: id={}, type={}, machine={}", operationLog.getId(), operationType, machineId);
|
||||
return operationLog;
|
||||
} catch (Exception e) {
|
||||
log.error("创建脚本操作记录失败: type={}, machine={}, error={}", operationType, machineId, e.getMessage(), e);
|
||||
return operationLog; // 即使保存失败也返回对象,避免影响主流程
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录选区操作
|
||||
*/
|
||||
public ScriptOperationLog logSelectRegion(String machineId, String requestUrl, String region) {
|
||||
ScriptOperationLog log = createOperationLog(ScriptOperationType.SELECT_REGION, machineId, requestUrl);
|
||||
|
||||
// 设置请求参数
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("region", region);
|
||||
setRequestParams(log, params);
|
||||
|
||||
return log;
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录刷新操作
|
||||
*/
|
||||
public ScriptOperationLog logRefresh(String machineId, String requestUrl) {
|
||||
ScriptOperationLog log = createOperationLog(ScriptOperationType.REFRESH, machineId, requestUrl);
|
||||
|
||||
// 设置请求参数
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("action", "刷新");
|
||||
setRequestParams(log, params);
|
||||
|
||||
return log;
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录保存总次数操作
|
||||
*/
|
||||
public ScriptOperationLog logSaveTotalTimes(String machineId, String requestUrl, int times) {
|
||||
ScriptOperationLog log = createOperationLog(ScriptOperationType.SAVE_TOTAL_TIMES, machineId, requestUrl);
|
||||
|
||||
// 设置请求参数
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("times", times);
|
||||
setRequestParams(log, params);
|
||||
|
||||
return log;
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录退单操作
|
||||
*/
|
||||
public ScriptOperationLog logRefundOrder(String machineId, String requestUrl) {
|
||||
ScriptOperationLog log = createOperationLog(ScriptOperationType.REFUND_ORDER, machineId, requestUrl);
|
||||
|
||||
// 设置请求参数
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("action", "T");
|
||||
setRequestParams(log, params);
|
||||
|
||||
return log;
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录成功响应
|
||||
*/
|
||||
public void recordSuccess(ScriptOperationLog operationLog, String result, long startTime) {
|
||||
try {
|
||||
LocalDateTime responseTime = LocalDateTime.now();
|
||||
long duration = System.currentTimeMillis() - startTime;
|
||||
|
||||
operationLog.setSuccessResponse(result, responseTime, duration);
|
||||
logMapper.update(operationLog);
|
||||
|
||||
log.debug("记录操作成功: id={}, duration={}ms", operationLog.getId(), duration);
|
||||
} catch (Exception e) {
|
||||
log.error("记录操作成功失败: id={}, error={}", operationLog.getId(), e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录失败响应
|
||||
*/
|
||||
public void recordFailure(ScriptOperationLog operationLog, String errorMessage, long startTime) {
|
||||
try {
|
||||
LocalDateTime responseTime = LocalDateTime.now();
|
||||
long duration = System.currentTimeMillis() - startTime;
|
||||
|
||||
operationLog.setFailureResponse(errorMessage, responseTime, duration);
|
||||
logMapper.update(operationLog);
|
||||
|
||||
log.debug("记录操作失败: id={}, duration={}ms, error={}", operationLog.getId(), duration, errorMessage);
|
||||
} catch (Exception e) {
|
||||
log.error("记录操作失败失败: id={}, error={}", operationLog.getId(), e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置请求参数(转换为JSON字符串)
|
||||
*/
|
||||
private void setRequestParams(ScriptOperationLog operationLog, Map<String, Object> params) {
|
||||
try {
|
||||
String paramsJson = objectMapper.writeValueAsString(params);
|
||||
operationLog.setRequestParams(paramsJson);
|
||||
logMapper.update(operationLog);
|
||||
} catch (JsonProcessingException e) {
|
||||
log.warn("转换请求参数为JSON失败: params={}, error={}", params, e.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.error("设置请求参数失败: id={}, error={}", operationLog.getId(), e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理旧记录(可以通过定时任务调用)
|
||||
*/
|
||||
public int cleanOldRecords(int daysToKeep) {
|
||||
try {
|
||||
LocalDateTime cutoffTime = LocalDateTime.now().minusDays(daysToKeep);
|
||||
int deletedCount = logMapper.deleteOldRecords(cutoffTime);
|
||||
log.info("清理脚本操作记录: 删除{}条{}天前的记录", deletedCount, daysToKeep);
|
||||
return deletedCount;
|
||||
} catch (Exception e) {
|
||||
log.error("清理旧记录失败: error={}", e.getMessage(), e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import com.gameplatform.server.model.dto.device.DeviceStatusResponse;
|
||||
import com.gameplatform.server.service.device.DeviceStatusCheckService;
|
||||
import com.gameplatform.server.service.external.ScriptClient;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
import reactor.core.Exceptions;
|
||||
import reactor.core.publisher.Mono;
|
||||
@@ -29,7 +30,7 @@ public class DeviceStatusCheckTask {
|
||||
/**
|
||||
* 每分钟检查一次空闲设备,并更新相关链接任务状态
|
||||
*/
|
||||
// @Scheduled(fixedRate = 60000) // 每60秒执行一次
|
||||
@Scheduled(fixedRate = 60000) // 每60秒执行一次
|
||||
public void checkIdleDevicesAndUpdateTasks() {
|
||||
log.debug("开始定时检查空闲设备");
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
-- 脚本操作记录表
|
||||
CREATE TABLE script_operation_log (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
operation_type VARCHAR(50) NOT NULL COMMENT '操作类型: SELECT_REGION, REFRESH, SAVE_TOTAL_TIMES, REFUND_ORDER',
|
||||
machine_id VARCHAR(50) NOT NULL COMMENT '设备/机器ID',
|
||||
request_url TEXT NOT NULL COMMENT '请求URL',
|
||||
request_params JSON COMMENT '请求参数(JSON格式)',
|
||||
response_result TEXT COMMENT '响应结果',
|
||||
success BOOLEAN NOT NULL DEFAULT FALSE COMMENT '是否成功',
|
||||
error_message TEXT COMMENT '错误信息',
|
||||
duration_ms INT COMMENT '请求耗时(毫秒)',
|
||||
request_time DATETIME NOT NULL COMMENT '请求发送时间',
|
||||
response_time DATETIME COMMENT '响应接收时间',
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
INDEX idx_operation_type (operation_type),
|
||||
INDEX idx_machine_id (machine_id),
|
||||
INDEX idx_request_time (request_time),
|
||||
INDEX idx_success (success)
|
||||
) COMMENT '脚本操作记录表';
|
||||
128
src/main/resources/mapper/log/ScriptOperationLogMapper.xml
Normal file
128
src/main/resources/mapper/log/ScriptOperationLogMapper.xml
Normal file
@@ -0,0 +1,128 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.gameplatform.server.mapper.log.ScriptOperationLogMapper">
|
||||
|
||||
<resultMap id="ScriptOperationLogMap" type="com.gameplatform.server.model.entity.log.ScriptOperationLog">
|
||||
<id property="id" column="id" />
|
||||
<result property="operationType" column="operation_type" typeHandler="org.apache.ibatis.type.EnumTypeHandler" />
|
||||
<result property="machineId" column="machine_id" />
|
||||
<result property="requestUrl" column="request_url" />
|
||||
<result property="requestParams" column="request_params" />
|
||||
<result property="responseResult" column="response_result" />
|
||||
<result property="success" column="success" />
|
||||
<result property="errorMessage" column="error_message" />
|
||||
<result property="durationMs" column="duration_ms" />
|
||||
<result property="requestTime" column="request_time" />
|
||||
<result property="responseTime" column="response_time" />
|
||||
<result property="createdAt" column="created_at" />
|
||||
<result property="updatedAt" column="updated_at" />
|
||||
</resultMap>
|
||||
|
||||
<sql id="BaseColumns">
|
||||
id, operation_type, machine_id, request_url, request_params, response_result,
|
||||
success, error_message, duration_ms, request_time, response_time, created_at, updated_at
|
||||
</sql>
|
||||
|
||||
<select id="findById" parameterType="long" resultMap="ScriptOperationLogMap">
|
||||
SELECT <include refid="BaseColumns" />
|
||||
FROM script_operation_log
|
||||
WHERE id = #{id}
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
<select id="findByMachineId" resultMap="ScriptOperationLogMap">
|
||||
SELECT <include refid="BaseColumns" />
|
||||
FROM script_operation_log
|
||||
WHERE machine_id = #{machineId}
|
||||
ORDER BY request_time DESC
|
||||
<if test="limit != null">
|
||||
LIMIT #{limit}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<select id="findByOperationType" resultMap="ScriptOperationLogMap">
|
||||
SELECT <include refid="BaseColumns" />
|
||||
FROM script_operation_log
|
||||
WHERE operation_type = #{operationType}
|
||||
ORDER BY request_time DESC
|
||||
<if test="limit != null">
|
||||
LIMIT #{limit}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<select id="findByTimeRange" resultMap="ScriptOperationLogMap">
|
||||
SELECT <include refid="BaseColumns" />
|
||||
FROM script_operation_log
|
||||
WHERE request_time BETWEEN #{startTime} AND #{endTime}
|
||||
ORDER BY request_time DESC
|
||||
<if test="limit != null">
|
||||
LIMIT #{limit}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<select id="findByMachineIdAndOperationType" resultMap="ScriptOperationLogMap">
|
||||
SELECT <include refid="BaseColumns" />
|
||||
FROM script_operation_log
|
||||
WHERE machine_id = #{machineId} AND operation_type = #{operationType}
|
||||
ORDER BY request_time DESC
|
||||
<if test="limit != null">
|
||||
LIMIT #{limit}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<select id="findFailedOperations" resultMap="ScriptOperationLogMap">
|
||||
SELECT <include refid="BaseColumns" />
|
||||
FROM script_operation_log
|
||||
WHERE success = false
|
||||
<if test="startTime != null and endTime != null">
|
||||
AND request_time BETWEEN #{startTime} AND #{endTime}
|
||||
</if>
|
||||
ORDER BY request_time DESC
|
||||
<if test="limit != null">
|
||||
LIMIT #{limit}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<select id="getOperationStatistics" resultType="java.util.Map">
|
||||
SELECT
|
||||
operation_type,
|
||||
COUNT(*) as total_count,
|
||||
SUM(CASE WHEN success = true THEN 1 ELSE 0 END) as success_count,
|
||||
SUM(CASE WHEN success = false THEN 1 ELSE 0 END) as failed_count,
|
||||
ROUND(AVG(duration_ms), 2) as avg_duration_ms,
|
||||
ROUND(SUM(CASE WHEN success = true THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 2) as success_rate
|
||||
FROM script_operation_log
|
||||
WHERE request_time BETWEEN #{startTime} AND #{endTime}
|
||||
GROUP BY operation_type
|
||||
ORDER BY operation_type
|
||||
</select>
|
||||
|
||||
<insert id="insert" parameterType="com.gameplatform.server.model.entity.log.ScriptOperationLog" useGeneratedKeys="true" keyProperty="id">
|
||||
INSERT INTO script_operation_log (
|
||||
operation_type, machine_id, request_url, request_params, response_result,
|
||||
success, error_message, duration_ms, request_time, response_time, created_at, updated_at
|
||||
) VALUES (
|
||||
#{operationType}, #{machineId}, #{requestUrl}, #{requestParams}, #{responseResult},
|
||||
#{success}, #{errorMessage}, #{durationMs}, #{requestTime}, #{responseTime}, #{createdAt}, #{updatedAt}
|
||||
)
|
||||
</insert>
|
||||
|
||||
<update id="update" parameterType="com.gameplatform.server.model.entity.log.ScriptOperationLog">
|
||||
UPDATE script_operation_log
|
||||
<set>
|
||||
<if test="responseResult != null">response_result = #{responseResult},</if>
|
||||
<if test="success != null">success = #{success},</if>
|
||||
<if test="errorMessage != null">error_message = #{errorMessage},</if>
|
||||
<if test="durationMs != null">duration_ms = #{durationMs},</if>
|
||||
<if test="responseTime != null">response_time = #{responseTime},</if>
|
||||
updated_at = #{updatedAt}
|
||||
</set>
|
||||
WHERE id = #{id}
|
||||
</update>
|
||||
|
||||
<delete id="deleteOldRecords">
|
||||
DELETE FROM script_operation_log
|
||||
WHERE created_at < #{beforeTime}
|
||||
</delete>
|
||||
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user