Compare commits
merge into: huangqizhen:master
huangqizhen:622
huangqizhen:feat0702/lhl
huangqizhen:huangqizheng/feature-20250703103159-登陆及相关配置
huangqizhen:huangqizheng/feature-20250704135104-bug修改
huangqizhen:lijianlin/feature-20250623120104-工作台与审核
huangqizhen:master
huangqizhen:milestone-20250702-金币重构一期
huangqizhen:sunjiabei/feature-20250623130922-消费功能
huangqizhen:wangyetao/feature-20250628170337-汇率
pull from: huangqizhen:huangqizheng/feature-20250703103159-登陆及相关配置
huangqizhen:622
huangqizhen:feat0702/lhl
huangqizhen:huangqizheng/feature-20250703103159-登陆及相关配置
huangqizhen:huangqizheng/feature-20250704135104-bug修改
huangqizhen:lijianlin/feature-20250623120104-工作台与审核
huangqizhen:master
huangqizhen:milestone-20250702-金币重构一期
huangqizhen:sunjiabei/feature-20250623130922-消费功能
huangqizhen:wangyetao/feature-20250628170337-汇率
54 Commits
master
...
huangqizhe
125 changed files with 8432 additions and 396 deletions
-
75pom.xml
-
2src/main/java/com/example/demo/DemoApplication.java
-
25src/main/java/com/example/demo/Export/ExportService.java
-
177src/main/java/com/example/demo/Export/ExportServiceImpl.java
-
31src/main/java/com/example/demo/Util/BusinessException.java
-
200src/main/java/com/example/demo/Util/ExcelUploadUtil.java
-
227src/main/java/com/example/demo/Util/ExecutionContextUtil.java
-
173src/main/java/com/example/demo/Util/FeiShuAlertUtil.java
-
2src/main/java/com/example/demo/Util/JWTUtil.java
-
37src/main/java/com/example/demo/Util/RedisLockUtil.java
-
189src/main/java/com/example/demo/Util/RedisUtil.java
-
2src/main/java/com/example/demo/Util/TokenPayload.java
-
18src/main/java/com/example/demo/config/EnvConfig.java
-
2src/main/java/com/example/demo/config/RedisConfig.java
-
66src/main/java/com/example/demo/controller/AdminController.java
-
55src/main/java/com/example/demo/controller/AuditController.java
-
103src/main/java/com/example/demo/controller/ConsumeController.java
-
99src/main/java/com/example/demo/controller/ExportController.java
-
12src/main/java/com/example/demo/controller/GeneralController.java
-
111src/main/java/com/example/demo/controller/GoldDetailController.java
-
70src/main/java/com/example/demo/controller/PermissionController.java
-
69src/main/java/com/example/demo/controller/RateController.java
-
93src/main/java/com/example/demo/controller/RechargeController.java
-
101src/main/java/com/example/demo/controller/RefundController.java
-
28src/main/java/com/example/demo/controller/StatisticsController.java
-
41src/main/java/com/example/demo/controller/UserController.java
-
49src/main/java/com/example/demo/controller/WorkbenchController.java
-
42src/main/java/com/example/demo/domain/DTO/ConsumeDTO.java
-
44src/main/java/com/example/demo/domain/DTO/GoldDetailDTO.java
-
42src/main/java/com/example/demo/domain/DTO/GoldUserDTO.java
-
43src/main/java/com/example/demo/domain/DTO/RechargeDTO.java
-
42src/main/java/com/example/demo/domain/DTO/RefundDTO.java
-
66src/main/java/com/example/demo/domain/entity/Admin.java
-
33src/main/java/com/example/demo/domain/entity/Export.java
-
8src/main/java/com/example/demo/domain/entity/Statistics.java
-
3src/main/java/com/example/demo/domain/entity/User.java
-
28src/main/java/com/example/demo/domain/export/Goldmingxi.java
-
28src/main/java/com/example/demo/domain/vo/AiEmotionExportRecordVO.java
-
18src/main/java/com/example/demo/domain/vo/AuditRequest.java
-
50src/main/java/com/example/demo/domain/vo/ConsumeUser.java
-
25src/main/java/com/example/demo/domain/vo/ExecutionContext.java
-
26src/main/java/com/example/demo/domain/vo/ExportVo.java
-
27src/main/java/com/example/demo/domain/vo/Gold.java
-
42src/main/java/com/example/demo/domain/vo/GoldDetail.java
-
41src/main/java/com/example/demo/domain/vo/GoldUser.java
-
30src/main/java/com/example/demo/domain/vo/Page.java
-
27src/main/java/com/example/demo/domain/vo/Permission.java
-
30src/main/java/com/example/demo/domain/vo/RateDetail.java
-
57src/main/java/com/example/demo/domain/vo/RechargeAudit.java
-
51src/main/java/com/example/demo/domain/vo/RechargeUser.java
-
54src/main/java/com/example/demo/domain/vo/RefundAudit.java
-
50src/main/java/com/example/demo/domain/vo/RefundUser.java
-
67src/main/java/com/example/demo/domain/vo/Result.java
-
17src/main/java/com/example/demo/domain/vo/TestRequest.java
-
25src/main/java/com/example/demo/domain/vo/Total.java
-
45src/main/java/com/example/demo/domain/vo/WorkbenchCard.java
-
65src/main/java/com/example/demo/domain/vo/WorkbenchMarketCard.java
-
13src/main/java/com/example/demo/exception/SystemException.java
-
18src/main/java/com/example/demo/mapper/AdminMapper.java
-
25src/main/java/com/example/demo/mapper/AiEmotionMapper.java
-
25src/main/java/com/example/demo/mapper/AuditMapper.java
-
28src/main/java/com/example/demo/mapper/ConsumeMapper.java
-
23src/main/java/com/example/demo/mapper/ExportMapper.java
-
2src/main/java/com/example/demo/mapper/GeneralMapper.java
-
39src/main/java/com/example/demo/mapper/GoldDetailMapper.java
-
31src/main/java/com/example/demo/mapper/PermissionMapper.java
-
18src/main/java/com/example/demo/mapper/RateMapper.java
-
27src/main/java/com/example/demo/mapper/RechargeMapper.java
-
32src/main/java/com/example/demo/mapper/RefundMapper.java
-
62src/main/java/com/example/demo/mapper/StatisticsMapper.java
-
25src/main/java/com/example/demo/mapper/UserMapper.java
-
23src/main/java/com/example/demo/mapper/WorkBenchMapper.java
-
256src/main/java/com/example/demo/security/TokenFilter.java
-
43src/main/java/com/example/demo/security/UploadFilter.java
-
15src/main/java/com/example/demo/service/AdminService.java
-
19src/main/java/com/example/demo/service/AiEmotionService.java
-
15src/main/java/com/example/demo/service/AuditService.java
-
28src/main/java/com/example/demo/service/ConsumeService.java
-
22src/main/java/com/example/demo/service/ExportExcelService.java
-
19src/main/java/com/example/demo/service/GeneralService.java
-
31src/main/java/com/example/demo/service/GoldDetailService.java
-
30src/main/java/com/example/demo/service/PermissionService.java
-
16src/main/java/com/example/demo/service/RateService.java
-
26src/main/java/com/example/demo/service/RechargeService.java
-
35src/main/java/com/example/demo/service/RefundService.java
-
22src/main/java/com/example/demo/service/StatisticsService.java
-
19src/main/java/com/example/demo/service/UserService.java
-
22src/main/java/com/example/demo/service/WorkbenchService.java
-
84src/main/java/com/example/demo/service/listen/AiEmotionExportListener.java
-
81src/main/java/com/example/demo/service/listen/ConsumeListener.java
-
82src/main/java/com/example/demo/service/listen/GoldListener.java
-
81src/main/java/com/example/demo/service/listen/RechargeListener.java
-
81src/main/java/com/example/demo/service/listen/RefundListener.java
-
69src/main/java/com/example/demo/service/queue/AbstractMessageListener.java
-
70src/main/java/com/example/demo/serviceImpl/AdminServiceImpl.java
-
35src/main/java/com/example/demo/serviceImpl/AiEmotionServiceImpl.java
-
173src/main/java/com/example/demo/serviceImpl/AuditServiceImpl.java
-
169src/main/java/com/example/demo/serviceImpl/ConsumeServiceImpl.java
-
1102src/main/java/com/example/demo/serviceImpl/ExportExcelServiceImpl.java
-
71src/main/java/com/example/demo/serviceImpl/GeneralServiceImpl.java
@ -0,0 +1,25 @@ |
|||||
|
package com.example.demo.Export; |
||||
|
|
||||
|
import com.example.demo.domain.DTO.ConsumeDTO; |
||||
|
import com.example.demo.domain.DTO.GoldDetailDTO; |
||||
|
import com.example.demo.domain.DTO.RechargeDTO; |
||||
|
import com.example.demo.domain.DTO.RefundDTO; |
||||
|
import com.example.demo.domain.vo.Result; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName ExportService |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−07-01 16:06 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
public interface ExportService { |
||||
|
//充值导出 |
||||
|
Result addExportRecharge(RechargeDTO dto); |
||||
|
//退款导出 |
||||
|
Result addExportRefund(RefundDTO dto); |
||||
|
//消费导出 |
||||
|
Result addExportConsume(ConsumeDTO dto); |
||||
|
|
||||
|
} |
@ -0,0 +1,177 @@ |
|||||
|
package com.example.demo.Export; |
||||
|
|
||||
|
import com.example.demo.domain.DTO.ConsumeDTO; |
||||
|
import com.example.demo.domain.DTO.RechargeDTO; |
||||
|
import com.example.demo.domain.DTO.RefundDTO; |
||||
|
import com.example.demo.domain.vo.Result; |
||||
|
import com.example.demo.exception.SystemException; |
||||
|
import com.example.demo.mapper.GoldDetailMapper; |
||||
|
import com.example.demo.Util.RedisUtil; |
||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
|
||||
|
import java.time.LocalDateTime; |
||||
|
import java.time.format.DateTimeFormatter; |
||||
|
import java.util.HashMap; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName ExportServiceImpl |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−07-01 16:11 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
@Service |
||||
|
public class ExportServiceImpl implements ExportService{ |
||||
|
@Autowired |
||||
|
private GoldDetailMapper goldDetailMapper; |
||||
|
@Autowired |
||||
|
private RedisUtil redisUtil; |
||||
|
|
||||
|
@Override |
||||
|
public Result addExportRecharge(RechargeDTO dto) { |
||||
|
// 生成文件名 |
||||
|
String fileName = String.format("%s_%s_%s.xlsx", |
||||
|
"充值明细", |
||||
|
"操作人", |
||||
|
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))); |
||||
|
System.out.println(fileName); |
||||
|
dto.setAccount(123456); |
||||
|
dto.setUrl(""); |
||||
|
dto.setFileName(fileName); |
||||
|
dto.setDataNum(0); |
||||
|
try{ |
||||
|
// 调用方式 |
||||
|
GoldDetailMapper.ExportRecordIdHolder idHolder = new GoldDetailMapper.ExportRecordIdHolder(); |
||||
|
goldDetailMapper.insertExportRecord( |
||||
|
idHolder, // 用于接收主键 |
||||
|
dto.getAccount(), |
||||
|
dto.getType(), |
||||
|
dto.getState(), |
||||
|
dto.getUrl(), |
||||
|
dto.getFileName(), |
||||
|
dto.getDataNum() |
||||
|
); |
||||
|
// 获取主键 |
||||
|
Long recordId = idHolder.getId(); |
||||
|
// 2. 构造完整的 JSON 数据(包含所有请求参数) |
||||
|
Map<String, Object> exportData = new HashMap<>(); |
||||
|
exportData.put("recordId", recordId); |
||||
|
|
||||
|
// 手动构造请求数据(避免 toString() 只返回部分字段) |
||||
|
Map<String, Object> requestData = new HashMap<>(); |
||||
|
requestData.put("text", dto.getText()); |
||||
|
requestData.put("sort", dto.getSort()); |
||||
|
requestData.put("field", dto.getField()); |
||||
|
requestData.put("deptId", dto.getDeptid()); |
||||
|
exportData.put("requestData", requestData); |
||||
|
|
||||
|
// 3. 发送到 Redis 消息队列 |
||||
|
String jsonData = new ObjectMapper().writeValueAsString(exportData); |
||||
|
redisUtil.sendMessage("recharge:queue:export_queue", jsonData); |
||||
|
}catch (Exception e){ |
||||
|
e.printStackTrace(); |
||||
|
throw new SystemException("导出数据异常,请稍后重试", e); |
||||
|
} |
||||
|
return Result.success(); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public Result addExportRefund(RefundDTO dto) { |
||||
|
// 生成文件名 |
||||
|
String fileName = String.format("%s_%s_%s.xlsx", |
||||
|
"退款明细", |
||||
|
"操作人", |
||||
|
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))); |
||||
|
System.out.println(fileName); |
||||
|
dto.setAccount(123456); |
||||
|
dto.setUrl(""); |
||||
|
dto.setFileName(fileName); |
||||
|
dto.setDataNum(0); |
||||
|
try{ |
||||
|
// 调用方式 |
||||
|
GoldDetailMapper.ExportRecordIdHolder idHolder = new GoldDetailMapper.ExportRecordIdHolder(); |
||||
|
goldDetailMapper.insertExportRecord( |
||||
|
idHolder, // 用于接收主键 |
||||
|
dto.getAccount(), |
||||
|
dto.getType(), |
||||
|
dto.getState(), |
||||
|
dto.getUrl(), |
||||
|
dto.getFileName(), |
||||
|
dto.getDataNum() |
||||
|
); |
||||
|
// 获取主键 |
||||
|
Long recordId = idHolder.getId(); |
||||
|
// 2. 构造完整的 JSON 数据(包含所有请求参数) |
||||
|
Map<String, Object> exportData = new HashMap<>(); |
||||
|
exportData.put("recordId", recordId); |
||||
|
|
||||
|
// 手动构造请求数据(避免 toString() 只返回部分字段) |
||||
|
Map<String, Object> requestData = new HashMap<>(); |
||||
|
requestData.put("text", dto.getText()); |
||||
|
requestData.put("sort", dto.getSort()); |
||||
|
requestData.put("field", dto.getField()); |
||||
|
requestData.put("deptId", dto.getDeptid()); |
||||
|
exportData.put("requestData", requestData); |
||||
|
|
||||
|
// 3. 发送到 Redis 消息队列 |
||||
|
String jsonData = new ObjectMapper().writeValueAsString(exportData); |
||||
|
redisUtil.sendMessage("refund:queue:export_queue", jsonData); |
||||
|
}catch (Exception e){ |
||||
|
e.printStackTrace(); |
||||
|
throw new SystemException("导出数据异常,请稍后重试", e); |
||||
|
} |
||||
|
return Result.success(); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public Result addExportConsume(ConsumeDTO dto) { |
||||
|
// 生成文件名 |
||||
|
String fileName = String.format("%s_%s_%s.xlsx", |
||||
|
"消费明细", |
||||
|
"操作人", |
||||
|
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))); |
||||
|
System.out.println(fileName); |
||||
|
dto.setAccount(123456); |
||||
|
dto.setUrl(""); |
||||
|
dto.setFileName(fileName); |
||||
|
dto.setDataNum(0); |
||||
|
try{ |
||||
|
// 调用方式 |
||||
|
GoldDetailMapper.ExportRecordIdHolder idHolder = new GoldDetailMapper.ExportRecordIdHolder(); |
||||
|
goldDetailMapper.insertExportRecord( |
||||
|
idHolder, // 用于接收主键 |
||||
|
dto.getAccount(), |
||||
|
dto.getType(), |
||||
|
dto.getState(), |
||||
|
dto.getUrl(), |
||||
|
dto.getFileName(), |
||||
|
dto.getDataNum() |
||||
|
); |
||||
|
// 获取主键 |
||||
|
Long recordId = idHolder.getId(); |
||||
|
// 2. 构造完整的 JSON 数据(包含所有请求参数) |
||||
|
Map<String, Object> exportData = new HashMap<>(); |
||||
|
exportData.put("recordId", recordId); |
||||
|
|
||||
|
// 手动构造请求数据(避免 toString() 只返回部分字段) |
||||
|
Map<String, Object> requestData = new HashMap<>(); |
||||
|
requestData.put("text", dto.getText()); |
||||
|
requestData.put("sort", dto.getSort()); |
||||
|
requestData.put("field", dto.getField()); |
||||
|
requestData.put("deptId", dto.getDeptid()); |
||||
|
exportData.put("requestData", requestData); |
||||
|
|
||||
|
// 3. 发送到 Redis 消息队列 |
||||
|
String jsonData = new ObjectMapper().writeValueAsString(exportData); |
||||
|
redisUtil.sendMessage("refund:queue:export_queue", jsonData); |
||||
|
}catch (Exception e){ |
||||
|
e.printStackTrace(); |
||||
|
throw new SystemException("导出数据异常,请稍后重试", e); |
||||
|
} |
||||
|
return Result.success(); |
||||
|
} |
||||
|
} |
@ -0,0 +1,31 @@ |
|||||
|
package com.example.demo.Util; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName BusinessException |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−06-23 14:58 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
import lombok.Getter; |
||||
|
|
||||
|
/** |
||||
|
* 业务异常,可抛出到前端 |
||||
|
*/ |
||||
|
@Getter |
||||
|
public class BusinessException extends RuntimeException { |
||||
|
private int code; // 业务状态码 |
||||
|
// 使用默认状态码0的构造方法 |
||||
|
public BusinessException(String message) { |
||||
|
this(400, message); // 默认状态码400 |
||||
|
} |
||||
|
|
||||
|
// 指定状态码的构造方法 |
||||
|
public BusinessException(int code, String message) { |
||||
|
super(message); |
||||
|
this.code = code; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,200 @@ |
|||||
|
package com.example.demo.Util; |
||||
|
|
||||
|
import org.slf4j.Logger; |
||||
|
import org.slf4j.LoggerFactory; |
||||
|
import org.springframework.core.io.FileSystemResource; |
||||
|
import org.springframework.http.*; |
||||
|
import org.springframework.http.client.SimpleClientHttpRequestFactory; |
||||
|
import org.springframework.http.converter.StringHttpMessageConverter; |
||||
|
import org.springframework.util.LinkedMultiValueMap; |
||||
|
import org.springframework.util.MultiValueMap; |
||||
|
import org.springframework.web.client.RestTemplate; |
||||
|
|
||||
|
import java.io.File; |
||||
|
import java.io.IOException; |
||||
|
import java.nio.charset.Charset; |
||||
|
import java.util.HashMap; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
/** |
||||
|
* Excel文件上传工具类 |
||||
|
*/ |
||||
|
public class ExcelUploadUtil { |
||||
|
private static final Logger logger = LoggerFactory.getLogger(ExcelUploadUtil.class); |
||||
|
|
||||
|
// 默认配置 |
||||
|
private static final int DEFAULT_CONNECT_TIMEOUT = 30000; // 30秒 |
||||
|
private static final int DEFAULT_READ_TIMEOUT = 60000; // 60秒 |
||||
|
|
||||
|
private final RestTemplate restTemplate; |
||||
|
private final String uploadUrl; |
||||
|
private final Map<String, String> defaultHeaders; |
||||
|
private final Map<String, String> defaultParams; |
||||
|
|
||||
|
/** |
||||
|
* 构造方法 |
||||
|
* |
||||
|
* @param uploadUrl 上传接口URL |
||||
|
*/ |
||||
|
public ExcelUploadUtil(String uploadUrl) { |
||||
|
this(uploadUrl, new HashMap<>(), new HashMap<>()); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 构造方法 |
||||
|
* |
||||
|
* @param uploadUrl 上传接口URL |
||||
|
* @param defaultHeaders 默认请求头 |
||||
|
* @param defaultParams 默认请求参数 |
||||
|
*/ |
||||
|
public ExcelUploadUtil(String uploadUrl, Map<String, String> defaultHeaders, Map<String, String> defaultParams) { |
||||
|
this.uploadUrl = uploadUrl; |
||||
|
this.defaultHeaders = new HashMap<>(defaultHeaders); |
||||
|
this.defaultParams = new HashMap<>(defaultParams); |
||||
|
this.restTemplate = createRestTemplate(DEFAULT_CONNECT_TIMEOUT, DEFAULT_READ_TIMEOUT); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 创建RestTemplate (Spring Boot 1.x 兼容版本) |
||||
|
*/ |
||||
|
private RestTemplate createRestTemplate(int connectTimeout, int readTimeout) { |
||||
|
RestTemplate restTemplate = new RestTemplate(); |
||||
|
|
||||
|
// 添加字符串消息转换器 (Spring 1.x 使用Charset而不是StandardCharsets) |
||||
|
restTemplate.getMessageConverters().add(0, new StringHttpMessageConverter(Charset.forName("UTF-8"))); |
||||
|
|
||||
|
// 设置超时 (Spring 1.x 方式) |
||||
|
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); |
||||
|
factory.setConnectTimeout(connectTimeout); |
||||
|
factory.setReadTimeout(readTimeout); |
||||
|
restTemplate.setRequestFactory(factory); |
||||
|
|
||||
|
return restTemplate; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 上传Excel文件 |
||||
|
* |
||||
|
* @param excelFile Excel文件 |
||||
|
* @param targetDir 目标目录 |
||||
|
* @return 上传结果 |
||||
|
* @throws IOException 文件操作异常 |
||||
|
* @throws UploadException 上传异常 |
||||
|
*/ |
||||
|
public String uploadExcel(File excelFile, String targetDir) throws IOException, UploadException { |
||||
|
return uploadExcel(excelFile, targetDir, new HashMap<>(), new HashMap<>()); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 上传Excel文件(带自定义参数) |
||||
|
* |
||||
|
* @param excelFile Excel文件 |
||||
|
* @param targetDir 目标目录 |
||||
|
* @param customHeaders 自定义请求头 |
||||
|
* @param customParams 自定义请求参数 |
||||
|
* @return 上传结果 |
||||
|
* @throws IOException 文件操作异常 |
||||
|
* @throws UploadException 上传异常 |
||||
|
*/ |
||||
|
public String uploadExcel(File excelFile, String targetDir, |
||||
|
Map<String, String> customHeaders, |
||||
|
Map<String, String> customParams) throws IOException, UploadException { |
||||
|
// 验证文件 |
||||
|
validateFile(excelFile); |
||||
|
|
||||
|
try { |
||||
|
// 准备请求 |
||||
|
HttpEntity<MultiValueMap<String, Object>> requestEntity = prepareRequest(excelFile, targetDir, customHeaders, customParams); |
||||
|
|
||||
|
// 执行上传 |
||||
|
ResponseEntity<String> response = restTemplate.exchange( |
||||
|
uploadUrl, |
||||
|
HttpMethod.POST, |
||||
|
requestEntity, |
||||
|
String.class |
||||
|
); |
||||
|
|
||||
|
// 处理响应 |
||||
|
return handleResponse(response, excelFile.getName()); |
||||
|
} catch (Exception e) { |
||||
|
logger.error("Excel文件上传失败: {}", excelFile.getAbsolutePath(), e); |
||||
|
throw new UploadException("文件上传失败: " + e.getMessage(), e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 验证文件 |
||||
|
*/ |
||||
|
private void validateFile(File file) throws IOException { |
||||
|
if (file == null) { |
||||
|
throw new IOException("文件不能为null"); |
||||
|
} |
||||
|
if (!file.exists()) { |
||||
|
throw new IOException("文件不存在: " + file.getAbsolutePath()); |
||||
|
} |
||||
|
if (!file.isFile()) { |
||||
|
throw new IOException("不是有效的文件: " + file.getAbsolutePath()); |
||||
|
} |
||||
|
if (file.length() == 0) { |
||||
|
throw new IOException("文件内容为空: " + file.getAbsolutePath()); |
||||
|
} |
||||
|
if (!file.getName().toLowerCase().endsWith(".xlsx") && |
||||
|
!file.getName().toLowerCase().endsWith(".xls")) { |
||||
|
throw new IOException("仅支持Excel文件(.xlsx, .xls)"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 准备请求 |
||||
|
*/ |
||||
|
private HttpEntity<MultiValueMap<String, Object>> prepareRequest(File file, String targetDir, |
||||
|
Map<String, String> customHeaders, |
||||
|
Map<String, String> customParams) { |
||||
|
// 设置请求头 |
||||
|
HttpHeaders headers = new HttpHeaders(); |
||||
|
headers.setContentType(MediaType.MULTIPART_FORM_DATA); |
||||
|
|
||||
|
// 添加默认和自定义请求头 |
||||
|
defaultHeaders.forEach(headers::set); |
||||
|
customHeaders.forEach(headers::set); |
||||
|
|
||||
|
// 准备请求体 |
||||
|
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>(); |
||||
|
body.add("file", new FileSystemResource(file)); |
||||
|
body.add("dir", targetDir); |
||||
|
|
||||
|
// 添加默认和自定义参数 |
||||
|
defaultParams.forEach(body::add); |
||||
|
customParams.forEach(body::add); |
||||
|
|
||||
|
return new HttpEntity<>(body, headers); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 处理响应 |
||||
|
*/ |
||||
|
private String handleResponse(ResponseEntity<String> response, String filename) throws UploadException { |
||||
|
if (response.getStatusCode() == HttpStatus.OK) { |
||||
|
logger.info("文件上传成功: {}", filename); |
||||
|
return response.getBody(); |
||||
|
} else { |
||||
|
String errorMsg = String.format("上传接口返回错误状态码: %d, 响应: %s", |
||||
|
response.getStatusCodeValue(), response.getBody()); |
||||
|
logger.error(errorMsg); |
||||
|
throw new UploadException(errorMsg); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 自定义上传异常 |
||||
|
*/ |
||||
|
public static class UploadException extends Exception { |
||||
|
public UploadException(String message) { |
||||
|
super(message); |
||||
|
} |
||||
|
|
||||
|
public UploadException(String message, Throwable cause) { |
||||
|
super(message, cause); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,227 @@ |
|||||
|
package com.example.demo.Util; |
||||
|
|
||||
|
|
||||
|
import com.example.demo.domain.vo.ExecutionContext; |
||||
|
import jakarta.servlet.http.HttpServletRequest; |
||||
|
import org.springframework.web.context.request.RequestContextHolder; |
||||
|
import org.springframework.web.context.request.ServletRequestAttributes; |
||||
|
|
||||
|
|
||||
|
import java.io.BufferedReader; |
||||
|
import java.io.File; |
||||
|
import java.io.IOException; |
||||
|
import java.lang.management.ManagementFactory; |
||||
|
import java.util.*; |
||||
|
import java.util.stream.Collectors; |
||||
|
|
||||
|
public class ExecutionContextUtil { |
||||
|
|
||||
|
/** |
||||
|
* 获取当前执行环境信息 |
||||
|
* @param request 如果是Web请求,传入HttpServletRequest |
||||
|
* @return 执行环境信息对象 |
||||
|
*/ |
||||
|
/** |
||||
|
* 从Spring上下文获取当前HttpServletRequest |
||||
|
*/ |
||||
|
public static ExecutionContext getExecutionContext() { |
||||
|
ExecutionContext context = new ExecutionContext(); |
||||
|
context.setExecutionTime(new Date()); |
||||
|
|
||||
|
HttpServletRequest request = getCurrentHttpRequest(); |
||||
|
|
||||
|
if (isWebEnvironment(request)) { |
||||
|
// Web API 环境 |
||||
|
context.setExecutionType("API"); |
||||
|
context.setApiUrl(getRealRequestUrl(request)); |
||||
|
context.setRequestParams(getRequestParams(request)); |
||||
|
context.setToken(getRequestToken(request)); |
||||
|
context.setMethod(request.getMethod()); |
||||
|
} else { |
||||
|
// 脚本环境 |
||||
|
context.setExecutionType("SCRIPT"); |
||||
|
context.setScriptFile(getMainClassFile()); |
||||
|
} |
||||
|
|
||||
|
return context; |
||||
|
} |
||||
|
|
||||
|
private static HttpServletRequest getCurrentHttpRequest() { |
||||
|
try { |
||||
|
return ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); |
||||
|
} catch (IllegalStateException e) { |
||||
|
// 不在Web请求上下文中 |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static boolean isWebEnvironment(HttpServletRequest request) { |
||||
|
return request != null; |
||||
|
} |
||||
|
|
||||
|
private static String getRealRequestUrl(HttpServletRequest request) { |
||||
|
// 1. 获取协议(优先从代理头获取) |
||||
|
String protocol = getHeaderWithFallback(request, |
||||
|
Arrays.asList("X-Forwarded-Proto", "X-Forwarded-Protocol"), |
||||
|
request.getScheme() |
||||
|
); |
||||
|
|
||||
|
// 2. 获取真实域名(优先从代理头获取原始域名) |
||||
|
String domain = getHeaderWithFallback(request, |
||||
|
Arrays.asList( |
||||
|
"X-Original-Host", // 一些代理服务器设置的原始终端 |
||||
|
"X-Real-Host", // 另一个可能的原始主机头 |
||||
|
"X-Forwarded-Host", // 转发的主机头 |
||||
|
"Host" // 最后回退到常规主机头 |
||||
|
), |
||||
|
request.getServerName() |
||||
|
); |
||||
|
|
||||
|
// 3. 获取端口(智能处理默认端口) |
||||
|
Integer port = getRealPort(request, protocol); |
||||
|
|
||||
|
// 4. 获取原始路径(包括QueryString) |
||||
|
String path = getOriginalUri(request); |
||||
|
|
||||
|
// 组装完整URL |
||||
|
return String.format("%s://%s:%s%s", |
||||
|
protocol, |
||||
|
domain, |
||||
|
port, |
||||
|
path |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
// 辅助方法:带fallback的header获取 |
||||
|
// 方法1:保持强类型(推荐) |
||||
|
private static String getHeaderWithFallback( |
||||
|
HttpServletRequest request, |
||||
|
List<String> headerNames, // 明确要求String列表 |
||||
|
String defaultValue |
||||
|
) { |
||||
|
return headerNames.stream() |
||||
|
.map(request::getHeader) |
||||
|
.filter(Objects::nonNull) |
||||
|
.findFirst() |
||||
|
.orElse(defaultValue); |
||||
|
} |
||||
|
|
||||
|
// 获取真实端口(处理代理情况) |
||||
|
private static int getRealPort(HttpServletRequest request, String protocol) { |
||||
|
// 优先从代理头获取 |
||||
|
String forwardedPort = request.getHeader("X-Forwarded-Port"); |
||||
|
if (forwardedPort != null) { |
||||
|
return Integer.parseInt(forwardedPort); |
||||
|
} |
||||
|
|
||||
|
// 其次从请求获取 |
||||
|
int port = request.getServerPort(); |
||||
|
|
||||
|
// 处理反向代理场景 |
||||
|
if (port == 80 && "https".equals(protocol)) { |
||||
|
return 443; |
||||
|
} |
||||
|
if (port == 443 && "http".equals(protocol)) { |
||||
|
return 80; |
||||
|
} |
||||
|
return port; |
||||
|
} |
||||
|
|
||||
|
// 获取原始URI(包含QueryString) |
||||
|
private static String getOriginalUri(HttpServletRequest request) { |
||||
|
// 优先从代理头获取原始URI |
||||
|
String originalUri = request.getHeader("X-Original-URI"); |
||||
|
if (originalUri != null) { |
||||
|
return originalUri; |
||||
|
} |
||||
|
|
||||
|
// 默认从request获取 |
||||
|
String queryString = request.getQueryString(); |
||||
|
return request.getRequestURI() + |
||||
|
(queryString != null ? "?" + queryString : ""); |
||||
|
} |
||||
|
|
||||
|
private static String getRequestParams(HttpServletRequest request) { |
||||
|
try { |
||||
|
// 1. 优先读取Query String(无需缓存) |
||||
|
String queryString = request.getQueryString(); |
||||
|
if (queryString != null) return queryString; |
||||
|
|
||||
|
// 2. 检查表单参数(GET/POST都适用) |
||||
|
Map<String, String[]> params = request.getParameterMap(); |
||||
|
if (!params.isEmpty()) return formatParams(params); |
||||
|
|
||||
|
// 3. 只有明确是JSON请求时才尝试读取body |
||||
|
if (isJsonRequest(request)) { |
||||
|
return readJsonBodyOnDemand(request); |
||||
|
} |
||||
|
|
||||
|
return "{}"; |
||||
|
} catch (Exception e) { |
||||
|
return "{\"error\":\"failed to read params\"}"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static String readJsonBodyOnDemand(HttpServletRequest request) throws IOException { |
||||
|
// 关键点:直接读取原始InputStream(不缓存) |
||||
|
try (BufferedReader reader = request.getReader()) { |
||||
|
String body = reader.lines().collect(Collectors.joining()); |
||||
|
return body.isEmpty() ? "{}" : body; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
private static boolean isJsonRequest(HttpServletRequest request) { |
||||
|
String contentType = request.getContentType(); |
||||
|
return contentType != null && contentType.contains("application/json"); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
private static String formatParams(Map<String, String[]> params) { |
||||
|
// 优化后的参数格式化方法 |
||||
|
return params.entrySet().stream() |
||||
|
.map(entry -> { |
||||
|
String key = escapeJson(entry.getKey()); |
||||
|
String[] values = entry.getValue(); |
||||
|
if (values.length == 1) { |
||||
|
return "\"" + key + "\":\"" + escapeJson(values[0]) + "\""; |
||||
|
} |
||||
|
return "\"" + key + "\":[" + |
||||
|
Arrays.stream(values) |
||||
|
.map(v -> "\"" + escapeJson(v) + "\"") |
||||
|
.collect(Collectors.joining(",")) + |
||||
|
"]"; |
||||
|
}) |
||||
|
.collect(Collectors.joining(",", "{", "}")); |
||||
|
} |
||||
|
|
||||
|
private static String escapeJson(String raw) { |
||||
|
return raw.replace("\\", "\\\\") |
||||
|
.replace("\"", "\\\"") |
||||
|
.replace("\n", "\\n"); |
||||
|
} |
||||
|
|
||||
|
private static String getRequestToken(HttpServletRequest request) { |
||||
|
String token = request.getHeader("Authorization"); |
||||
|
if (token == null) { |
||||
|
token = request.getHeader("token"); |
||||
|
} |
||||
|
return token; |
||||
|
} |
||||
|
|
||||
|
private static String getMainClassFile() { |
||||
|
try { |
||||
|
// 获取主类名 |
||||
|
String mainClass = ManagementFactory.getRuntimeMXBean().getSystemProperties().get("sun.java.command"); |
||||
|
if (mainClass != null) { |
||||
|
// 简单处理,提取主类名 |
||||
|
String className = mainClass.split(" ")[0]; |
||||
|
// 转换为文件路径 |
||||
|
return className.replace('.', File.separatorChar) + ".java"; |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
return "UnknownScript"; |
||||
|
} |
||||
|
} |
@ -0,0 +1,173 @@ |
|||||
|
package com.example.demo.Util; |
||||
|
|
||||
|
import com.alibaba.fastjson.JSON; |
||||
|
import com.alibaba.fastjson.JSONObject; |
||||
|
import com.example.demo.domain.vo.ExecutionContext; |
||||
|
import com.example.demo.config.EnvConfig; |
||||
|
import org.apache.http.HttpResponse; |
||||
|
import org.apache.http.HttpStatus; |
||||
|
import org.apache.http.client.methods.HttpPost; |
||||
|
import org.apache.http.entity.StringEntity; |
||||
|
import org.apache.http.impl.client.CloseableHttpClient; |
||||
|
import org.apache.http.impl.client.HttpClients; |
||||
|
import org.apache.http.util.EntityUtils; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
import java.io.IOException; |
||||
|
import java.text.SimpleDateFormat; |
||||
|
import java.util.*; |
||||
|
|
||||
|
/** |
||||
|
* 飞书报警信息发送工具类 |
||||
|
*/ |
||||
|
@Component |
||||
|
public class FeiShuAlertUtil { |
||||
|
|
||||
|
private static final String FEISHU_WEBHOOK_URL_PROD = "https://open.feishu.cn/open-apis/bot/v2/hook/1a515b19-b64f-46b7-9486-35842b9539fe"; |
||||
|
private static final String FEISHU_WEBHOOK_URL_TEST = "https://open.feishu.cn/open-apis/bot/v2/hook/384c78aa-8df1-498b-9c47-04e890ed9877"; |
||||
|
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
||||
|
|
||||
|
static { |
||||
|
DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai")); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 发送报警信息到飞书群(紧凑单行格式) |
||||
|
* |
||||
|
* @param context 请求接口 |
||||
|
* @param errorFile 错误文件 |
||||
|
* @param errorLine 错误行数 |
||||
|
* @param errorMsg 错误信息 |
||||
|
* @param params 脚本执行时需要手动传参,如果时API请求则无需传,自动获取参数 |
||||
|
* @return 是否发送成功 |
||||
|
*/ |
||||
|
public static boolean sendAlertMessage(ExecutionContext context, |
||||
|
String errorFile, int errorLine, |
||||
|
String errorMsg, String params) { |
||||
|
JSONObject message = new JSONObject(); |
||||
|
message.put("msg_type", "post"); |
||||
|
|
||||
|
JSONObject content = new JSONObject(); |
||||
|
JSONObject post = new JSONObject(); |
||||
|
JSONObject zhCn = new JSONObject(); |
||||
|
String title = "⚠️ 系统异常报警 ⚠️"; |
||||
|
zhCn.put("title", title); |
||||
|
|
||||
|
List<List<JSONObject>> contentList = new ArrayList<>(); |
||||
|
List<JSONObject> elements = new ArrayList<>(); |
||||
|
|
||||
|
StringBuilder contentBuilder = new StringBuilder(); |
||||
|
contentBuilder.append("------------------------------\n\n"); |
||||
|
|
||||
|
if ("API".equals(context.getExecutionType())) { |
||||
|
contentBuilder.append("**执行类型**: API请求\n\n"); |
||||
|
contentBuilder.append("**请求接口**: ").append(context.getApiUrl()).append("\n\n"); |
||||
|
contentBuilder.append("**请求参数**: ").append(params).append("\n\n"); |
||||
|
contentBuilder.append("**请求方法**: ").append(context.getMethod()).append("\n\n"); |
||||
|
if (context.getToken() != null) { |
||||
|
contentBuilder.append("**请求Token**: ") |
||||
|
.append(context.getToken().length() > 10 ? |
||||
|
context.getToken().substring(0, 10) + "..." : |
||||
|
context.getToken()) |
||||
|
.append("\n\n"); |
||||
|
} |
||||
|
} else { |
||||
|
contentBuilder.append("**执行类型**: 脚本执行\n\n"); |
||||
|
contentBuilder.append("**脚本文件**: ").append(context.getScriptFile()).append("\n\n"); |
||||
|
contentBuilder.append("**请求参数**: ").append(params).append("\n\n"); |
||||
|
} |
||||
|
|
||||
|
contentBuilder.append("**错误位置**: ").append(errorFile).append(":").append(errorLine).append("\n\n"); |
||||
|
contentBuilder.append("**错误信息**: ").append(errorMsg).append("\n\n"); |
||||
|
contentBuilder.append("**执行时间**: ").append(formatDate(context.getExecutionTime())).append("\n\n"); |
||||
|
contentBuilder.append("**报警时间**: ").append(formatDate(new Date())).append("\n\n"); |
||||
|
contentBuilder.append("------------------------------"); |
||||
|
|
||||
|
addContentElement(elements, "text", contentBuilder.toString()); |
||||
|
|
||||
|
contentList.add(elements); |
||||
|
zhCn.put("content", contentList); |
||||
|
post.put("zh_cn", zhCn); |
||||
|
content.put("post", post); |
||||
|
message.put("content", content); |
||||
|
|
||||
|
return sendMessage(message); |
||||
|
} |
||||
|
|
||||
|
private static String formatDate(Date date) { |
||||
|
// 实现日期格式化方法 |
||||
|
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date); |
||||
|
} |
||||
|
|
||||
|
private static void addContentElement(List<JSONObject> elements, String tag, String text) { |
||||
|
JSONObject element = new JSONObject(); |
||||
|
element.put("tag", tag); |
||||
|
element.put("text", text); |
||||
|
elements.add(element); |
||||
|
} |
||||
|
|
||||
|
private static boolean sendMessage(JSONObject message) { |
||||
|
try (CloseableHttpClient httpClient = HttpClients.createDefault()) { |
||||
|
String FEISHU_WEBHOOK_URL; |
||||
|
String environment = EnvConfig.ENV; |
||||
|
System.out.println("当前环境变量:" + environment); |
||||
|
if (Objects.equals(environment, "unknown") || environment.equals("dev")) { |
||||
|
FEISHU_WEBHOOK_URL = FEISHU_WEBHOOK_URL_TEST; |
||||
|
} else { |
||||
|
FEISHU_WEBHOOK_URL = FEISHU_WEBHOOK_URL_PROD; |
||||
|
} |
||||
|
HttpPost httpPost = new HttpPost(FEISHU_WEBHOOK_URL); |
||||
|
httpPost.addHeader("Content-Type", "application/json; charset=utf-8"); |
||||
|
|
||||
|
StringEntity entity = new StringEntity(message.toJSONString(), "UTF-8"); |
||||
|
httpPost.setEntity(entity); |
||||
|
|
||||
|
HttpResponse response = httpClient.execute(httpPost); |
||||
|
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { |
||||
|
String result = EntityUtils.toString(response.getEntity()); |
||||
|
JSONObject obj = JSON.parseObject(result); |
||||
|
return obj.getInteger("code") == 0; |
||||
|
} |
||||
|
} catch (IOException e) { |
||||
|
System.out.println("发送飞书异常" + e.getMessage()); |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 发送普通信息到飞书群 |
||||
|
* |
||||
|
* @param title 消息标题 |
||||
|
* @param content 消息内容 |
||||
|
* @return 是否发送成功 |
||||
|
*/ |
||||
|
public static boolean sendNormalMessage(String title, String content) { |
||||
|
JSONObject message = new JSONObject(); |
||||
|
message.put("msg_type", "post"); |
||||
|
|
||||
|
JSONObject messageContent = new JSONObject(); |
||||
|
JSONObject post = new JSONObject(); |
||||
|
JSONObject zhCn = new JSONObject(); |
||||
|
zhCn.put("title", title); |
||||
|
|
||||
|
List<List<JSONObject>> contentList = new ArrayList<>(); |
||||
|
List<JSONObject> elements = new ArrayList<>(); |
||||
|
|
||||
|
StringBuilder contentBuilder = new StringBuilder(); |
||||
|
contentBuilder.append("------------------------------\n\n"); |
||||
|
contentBuilder.append(content).append("\n\n"); |
||||
|
contentBuilder.append("**发送时间**: ").append(formatDate(new Date())).append("\n\n"); |
||||
|
contentBuilder.append("------------------------------"); |
||||
|
|
||||
|
addContentElement(elements, "text", contentBuilder.toString()); |
||||
|
|
||||
|
contentList.add(elements); |
||||
|
zhCn.put("content", contentList); |
||||
|
post.put("zh_cn", zhCn); |
||||
|
messageContent.put("post", post); |
||||
|
message.put("content", messageContent); |
||||
|
|
||||
|
return sendMessage(message); |
||||
|
} |
||||
|
} |
@ -0,0 +1,37 @@ |
|||||
|
package com.example.demo.Util; |
||||
|
|
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.data.redis.core.StringRedisTemplate; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
import java.util.concurrent.TimeUnit; |
||||
|
|
||||
|
@Component |
||||
|
public class RedisLockUtil { |
||||
|
|
||||
|
@Autowired |
||||
|
private StringRedisTemplate redisTemplate; |
||||
|
|
||||
|
/** |
||||
|
* 尝试获取分布式锁 |
||||
|
* @param lockKey 锁的 Key |
||||
|
* @param requestId 请求 ID(可用 UUID) |
||||
|
* @param expireTime 锁的过期时间(毫秒) |
||||
|
* @return 是否获取成功 |
||||
|
*/ |
||||
|
public boolean tryLock(String lockKey, String requestId, long expireTime) { |
||||
|
return redisTemplate.opsForValue().setIfAbsent(lockKey, requestId, expireTime, TimeUnit.MILLISECONDS); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 释放分布式锁 |
||||
|
* @param lockKey 锁的 Key |
||||
|
* @param requestId 请求 ID |
||||
|
*/ |
||||
|
public void unlock(String lockKey, String requestId) { |
||||
|
String currentValue = redisTemplate.opsForValue().get(lockKey); |
||||
|
if (requestId.equals(currentValue)) { |
||||
|
redisTemplate.delete(lockKey); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,189 @@ |
|||||
|
package com.example.demo.Util; |
||||
|
|
||||
|
import jakarta.annotation.PostConstruct; |
||||
|
import jakarta.annotation.Resource; |
||||
|
import org.springframework.data.redis.connection.RedisConnection; |
||||
|
import org.springframework.data.redis.core.RedisCallback; |
||||
|
import org.springframework.data.redis.core.RedisTemplate; |
||||
|
import org.springframework.data.redis.core.ZSetOperations; |
||||
|
import org.springframework.scheduling.annotation.Scheduled; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
|
||||
|
import java.util.Set; |
||||
|
import java.util.concurrent.*; |
||||
|
|
||||
|
@Component |
||||
|
public class RedisUtil { |
||||
|
|
||||
|
@Resource |
||||
|
private RedisTemplate<String, Object> redisTemplate; |
||||
|
|
||||
|
// 线程池用于处理延迟消息 |
||||
|
private ExecutorService delayMessageExecutor; |
||||
|
|
||||
|
// 延迟消息处理线程数 |
||||
|
private static final int DELAY_THREAD_POOL_SIZE = 4; |
||||
|
|
||||
|
// 延迟队列轮询间隔(毫秒) |
||||
|
private static final long DELAY_QUEUE_POLL_INTERVAL = 1000L; |
||||
|
|
||||
|
@PostConstruct |
||||
|
public void init() { |
||||
|
// 初始化线程池 |
||||
|
delayMessageExecutor = Executors.newFixedThreadPool(DELAY_THREAD_POOL_SIZE); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 发送消息到队列 |
||||
|
* @param queueName 队列名称 |
||||
|
* @param message 消息内容 |
||||
|
*/ |
||||
|
|
||||
|
public void sendMessage(String queueName, Object message) { |
||||
|
redisTemplate.opsForList().rightPush(queueName, message); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 阻塞获取消息(优化版,增加重试机制) |
||||
|
* @param queueName 队列名称 |
||||
|
* @param timeout 超时时间(秒) |
||||
|
* @return 消息内容 |
||||
|
*/ |
||||
|
|
||||
|
public Object blockingGetMessage(String queueName, long timeout) { |
||||
|
// 分段获取,避免长时间阻塞 |
||||
|
long endTime = System.currentTimeMillis() + timeout * 1000; |
||||
|
while (System.currentTimeMillis() < endTime) { |
||||
|
Object message = redisTemplate.opsForList().leftPop(queueName, 1, TimeUnit.SECONDS); |
||||
|
if (message != null) { |
||||
|
return message; |
||||
|
} |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 非阻塞获取消息 |
||||
|
* @param queueName 队列名称 |
||||
|
* @return 消息内容 |
||||
|
*/ |
||||
|
|
||||
|
public Object getMessage(String queueName) { |
||||
|
return redisTemplate.opsForList().leftPop(queueName); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 获取队列长度 |
||||
|
* @param queueName 队列名称 |
||||
|
* @return 队列长度 |
||||
|
*/ |
||||
|
|
||||
|
public Long getQueueSize(String queueName) { |
||||
|
return redisTemplate.opsForList().size(queueName); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 发送延迟消息(优化版) |
||||
|
* @param queueName 队列名称 |
||||
|
* @param message 消息内容 |
||||
|
* @param delay 延迟时间(秒) |
||||
|
*/ |
||||
|
|
||||
|
public void sendDelayMessage(String queueName, Object message, long delay) { |
||||
|
String delayQueueKey = getDelayQueueKey(queueName); |
||||
|
String messageId = generateMessageId(); |
||||
|
|
||||
|
redisTemplate.execute(new RedisCallback<Object>() { |
||||
|
@Override |
||||
|
public Object doInRedis(RedisConnection connection) { |
||||
|
connection.openPipeline(); |
||||
|
// 直接存储消息内容到ZSet的value中 |
||||
|
connection.zAdd( |
||||
|
delayQueueKey.getBytes(), |
||||
|
System.currentTimeMillis() + delay * 1000, |
||||
|
serializeMessage(messageId, message) |
||||
|
); |
||||
|
connection.closePipeline(); |
||||
|
return null; |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 启动延迟消息处理任务 |
||||
|
*/ |
||||
|
|
||||
|
@Scheduled(fixedRate = DELAY_QUEUE_POLL_INTERVAL) |
||||
|
public void processDelayMessages() { |
||||
|
Set<String> delayQueues = redisTemplate.keys("delay:*"); |
||||
|
if (delayQueues != null) { |
||||
|
for (String delayQueue : delayQueues) { |
||||
|
delayMessageExecutor.execute(() -> { |
||||
|
String queueName = delayQueue.substring(6); // 去掉"delay:"前缀 |
||||
|
processSingleDelayQueue(queueName); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 处理单个延迟队列 |
||||
|
*/ |
||||
|
|
||||
|
private void processSingleDelayQueue(String queueName) { |
||||
|
String delayQueueKey = getDelayQueueKey(queueName); |
||||
|
long now = System.currentTimeMillis(); |
||||
|
|
||||
|
// 获取所有已到期的消息 |
||||
|
Set<ZSetOperations.TypedTuple<Object>> messages = redisTemplate.opsForZSet() |
||||
|
.rangeByScoreWithScores(delayQueueKey, 0, now); |
||||
|
|
||||
|
if (messages != null && !messages.isEmpty()) { |
||||
|
for (ZSetOperations.TypedTuple<Object> tuple : messages) { |
||||
|
Object messageWithId = tuple.getValue(); |
||||
|
if (messageWithId != null) { |
||||
|
// 反序列化消息 |
||||
|
Object message = deserializeMessage(messageWithId.toString()); |
||||
|
// 发送到实际队列 |
||||
|
sendMessage(queueName, message); |
||||
|
// 从延迟队列中移除 |
||||
|
redisTemplate.opsForZSet().remove(delayQueueKey, messageWithId); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 生成消息ID |
||||
|
private String generateMessageId() { |
||||
|
return java.util.UUID.randomUUID().toString(); |
||||
|
} |
||||
|
|
||||
|
// 获取延迟队列key |
||||
|
private String getDelayQueueKey(String queueName) { |
||||
|
return "delay:" + queueName; |
||||
|
} |
||||
|
|
||||
|
// 序列化消息(可根据实际需求实现) |
||||
|
private byte[] serializeMessage(String messageId, Object message) { |
||||
|
// 这里简单实现,实际项目中可以使用JSON序列化等 |
||||
|
return (messageId + ":" + message.toString()).getBytes(); |
||||
|
} |
||||
|
|
||||
|
// 反序列化消息(可根据实际需求实现) |
||||
|
private Object deserializeMessage(String serialized) { |
||||
|
// 简单实现,根据实际序列化方式调整 |
||||
|
int separatorIndex = serialized.indexOf(':'); |
||||
|
if (separatorIndex > 0) { |
||||
|
return serialized.substring(separatorIndex + 1); |
||||
|
} |
||||
|
return serialized; |
||||
|
} |
||||
|
} |
@ -0,0 +1,18 @@ |
|||||
|
package com.example.demo.config; |
||||
|
|
||||
|
import org.springframework.context.annotation.Configuration; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName EnvConfig |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−06-29 13:55 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
@Configuration |
||||
|
public class EnvConfig { |
||||
|
public static final String ENV = "dev"; |
||||
|
public static final String ENV_PROD = "prod"; |
||||
|
public static final String ENV_TEST = "test"; |
||||
|
} |
@ -0,0 +1,66 @@ |
|||||
|
package com.example.demo.controller; |
||||
|
|
||||
|
import com.example.demo.Util.JWTUtil; |
||||
|
import com.example.demo.Util.TokenPayload; |
||||
|
import com.example.demo.domain.entity.Admin; |
||||
|
import com.example.demo.domain.vo.Result; |
||||
|
import com.example.demo.service.AdminService; |
||||
|
import com.fasterxml.jackson.core.JsonProcessingException; |
||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.security.core.userdetails.UserDetails; |
||||
|
import org.springframework.web.bind.annotation.*; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName AdminController |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−07-01 10:39 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
@RestController |
||||
|
@RequestMapping("/admin") |
||||
|
@RequiredArgsConstructor |
||||
|
@Slf4j |
||||
|
@CrossOrigin |
||||
|
public class AdminController { |
||||
|
@Autowired |
||||
|
private AdminService adminService; |
||||
|
@PostMapping("/login") |
||||
|
public Result login(@RequestBody Admin admin) { |
||||
|
|
||||
|
try { |
||||
|
admin = adminService.login(admin); |
||||
|
String token = JWTUtil.createJWT(admin); |
||||
|
System.out.println( token); |
||||
|
admin.setPassword(null); |
||||
|
return Result.success(token,admin); |
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
log.error(e.getMessage()); |
||||
|
return Result.error(e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
@PostMapping("/userinfo") |
||||
|
public UserDetails getUserInfo(@RequestBody String requestBody) { |
||||
|
ObjectMapper objectMapper = new ObjectMapper(); |
||||
|
TokenPayload token1; |
||||
|
try { |
||||
|
token1 = objectMapper.readValue(requestBody, TokenPayload.class); |
||||
|
} catch (JsonProcessingException e) { |
||||
|
throw new RuntimeException(e); |
||||
|
} |
||||
|
String token = token1.getToken(); |
||||
|
|
||||
|
System.out.println("1/*/*/*/*//*-*-*-*-*-*-1" +token); |
||||
|
try { |
||||
|
System.out.println("/+/+/+/+/+/+/+//" + JWTUtil.getUserDetailsList(String.valueOf(token), Admin.class)); |
||||
|
return JWTUtil.getUserDetailsList(String.valueOf(token), Admin.class); |
||||
|
} catch (Exception e) { |
||||
|
throw new RuntimeException(e); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,103 @@ |
|||||
|
package com.example.demo.controller; |
||||
|
|
||||
|
import com.example.demo.domain.entity.UserGoldRecord; |
||||
|
import com.example.demo.domain.vo.ConsumeUser; |
||||
|
import com.example.demo.domain.vo.Gold; |
||||
|
import com.example.demo.domain.vo.Page; |
||||
|
import com.example.demo.domain.vo.Result; |
||||
|
import com.example.demo.service.ConsumeService; |
||||
|
import jakarta.validation.Valid; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.util.ObjectUtils; |
||||
|
import org.springframework.web.bind.annotation.*; |
||||
|
|
||||
|
/** |
||||
|
* @program: gold-java |
||||
|
* @ClassName ConsumeController |
||||
|
* @description:消费模块 |
||||
|
* @author: Double |
||||
|
* @create: 2025−06-23 13:06 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
@RestController |
||||
|
@RequestMapping("/consume") |
||||
|
@RequiredArgsConstructor |
||||
|
@Slf4j |
||||
|
@CrossOrigin |
||||
|
public class ConsumeController { |
||||
|
|
||||
|
@Autowired |
||||
|
private ConsumeService consumeService; |
||||
|
|
||||
|
//消耗明细 |
||||
|
@PostMapping("/selectAll") |
||||
|
public Result selcetAll(@RequestBody Page page) { |
||||
|
try { |
||||
|
if (ObjectUtils.isEmpty(page.getPageNum())) { |
||||
|
return Result.error("页码数为空!"); |
||||
|
} |
||||
|
if (ObjectUtils.isEmpty(page.getPageSize())) { |
||||
|
return Result.error("页大小为空!"); |
||||
|
} else { |
||||
|
return Result.success(consumeService.selectAll(page.getPageNum(), page.getPageSize(),page.getConsumeUser())); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
return Result.error("接口调用失败"); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
//消耗明细筛选 |
||||
|
@PostMapping("/selectBy") |
||||
|
public Result selcetBy(@RequestBody Page page) { |
||||
|
try { |
||||
|
if (ObjectUtils.isEmpty(page.getPageNum())) { |
||||
|
return Result.error("页码数为空!"); |
||||
|
} |
||||
|
if (ObjectUtils.isEmpty(page.getPageSize())) { |
||||
|
return Result.error("页大小为空!"); |
||||
|
} else { |
||||
|
return Result.success(consumeService.selectBy(page.getPageNum(), page.getPageSize(), page.getConsumeUser())); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
return Result.error("接口调用失败"); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
//消耗金币统计 |
||||
|
@PostMapping("/statsGold") |
||||
|
public Result statsGold(@RequestBody ConsumeUser consumeUser) { |
||||
|
try { |
||||
|
Gold gold = consumeService.statsGold(consumeUser); |
||||
|
return Result.success(gold); |
||||
|
} catch (Exception e) { |
||||
|
return Result.error("接口调用失败"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
//消耗金币增加 |
||||
|
@PostMapping("/add") |
||||
|
public Result add(@RequestBody ConsumeUser consumeUser) { |
||||
|
try { |
||||
|
return consumeService.add(consumeUser); |
||||
|
// if(consumeUser.getJwcode().equals(94226013)) |
||||
|
// { |
||||
|
// return consumeService.add(consumeUser); |
||||
|
// }else { |
||||
|
// return Result.error("不是测试的精网号,无法添加消费"); |
||||
|
// } |
||||
|
// |
||||
|
} catch (Exception e) { |
||||
|
return Result.error("接口调用失败"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
} |
@ -0,0 +1,99 @@ |
|||||
|
package com.example.demo.controller; |
||||
|
|
||||
|
import com.example.demo.Util.BusinessException; |
||||
|
import com.example.demo.Util.RedisLockUtil; |
||||
|
import com.example.demo.domain.DTO.ConsumeDTO; |
||||
|
import com.example.demo.domain.DTO.RechargeDTO; |
||||
|
import com.example.demo.domain.DTO.RefundDTO; |
||||
|
import com.example.demo.domain.entity.Export; |
||||
|
import com.example.demo.domain.vo.Result; |
||||
|
import com.example.demo.service.ExportExcelService; |
||||
|
import com.example.demo.service.GoldDetailService; |
||||
|
import com.example.demo.Export.ExportService; |
||||
|
import jakarta.validation.Valid; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.web.bind.annotation.*; |
||||
|
|
||||
|
import java.util.List; |
||||
|
import java.util.UUID; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName ExportController |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−06-28 15:22 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
@RestController |
||||
|
@RequestMapping("/export") |
||||
|
@RequiredArgsConstructor |
||||
|
@Slf4j |
||||
|
@CrossOrigin |
||||
|
public class ExportController { |
||||
|
@Autowired |
||||
|
private ExportExcelService exportExcelService; |
||||
|
@Autowired |
||||
|
private RedisLockUtil redisLockUtil; |
||||
|
@Autowired |
||||
|
private GoldDetailService goldDetailService; |
||||
|
@Autowired |
||||
|
private ExportService exportService; |
||||
|
@PostMapping("/export") |
||||
|
public Result export(@RequestBody Export Export){ |
||||
|
return Result.success(exportExcelService.getExcel(Export)); |
||||
|
} |
||||
|
@PostMapping("/exportRecharge") |
||||
|
public Result export(@Valid @RequestBody RechargeDTO dto) { |
||||
|
String lockKey = "export:lock:" + dto.getToken(); // 锁的 Key(可按用户/业务区分) |
||||
|
String requestId = UUID.randomUUID().toString(); // 请求 ID(防止误删锁) |
||||
|
long expireTime = 5000; // 锁过期时间(5秒)s |
||||
|
try { |
||||
|
// 尝试获取锁 |
||||
|
if (!redisLockUtil.tryLock(lockKey, requestId, expireTime)) { |
||||
|
throw new BusinessException("操作太频繁,请稍后重试"); |
||||
|
} |
||||
|
// 执行业务逻辑 |
||||
|
return exportService.addExportRecharge(dto); |
||||
|
} finally { |
||||
|
// 释放锁 |
||||
|
redisLockUtil.unlock(lockKey, requestId); |
||||
|
} |
||||
|
} |
||||
|
@PostMapping("/exportRefund") |
||||
|
public Result export(@Valid @RequestBody RefundDTO dto) { |
||||
|
String lockKey = "export:lock:" + dto.getToken(); // 锁的 Key(可按用户/业务区分) |
||||
|
String requestId = UUID.randomUUID().toString(); // 请求 ID(防止误删锁) |
||||
|
long expireTime = 5000; // 锁过期时间(5秒)s |
||||
|
try { |
||||
|
// 尝试获取锁 |
||||
|
if (!redisLockUtil.tryLock(lockKey, requestId, expireTime)) { |
||||
|
throw new BusinessException("操作太频繁,请稍后重试"); |
||||
|
} |
||||
|
// 执行业务逻辑 |
||||
|
return exportService.addExportRefund(dto); |
||||
|
} finally { |
||||
|
// 释放锁 |
||||
|
redisLockUtil.unlock(lockKey, requestId); |
||||
|
} |
||||
|
} |
||||
|
@PostMapping("/exportConsume") |
||||
|
public Result export(@Valid @RequestBody ConsumeDTO dto) { |
||||
|
String lockKey = "export:lock:" + dto.getToken(); // 锁的 Key(可按用户/业务区分) |
||||
|
String requestId = UUID.randomUUID().toString(); // 请求 ID(防止误删锁) |
||||
|
long expireTime = 5000; // 锁过期时间(5秒)s |
||||
|
try { |
||||
|
// 尝试获取锁 |
||||
|
if (!redisLockUtil.tryLock(lockKey, requestId, expireTime)) { |
||||
|
throw new BusinessException("操作太频繁,请稍后重试"); |
||||
|
} |
||||
|
// 执行业务逻辑 |
||||
|
return exportService.addExportConsume(dto); |
||||
|
} finally { |
||||
|
// 释放锁 |
||||
|
redisLockUtil.unlock(lockKey, requestId); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,111 @@ |
|||||
|
package com.example.demo.controller; |
||||
|
|
||||
|
import com.example.demo.Util.BusinessException; |
||||
|
import com.example.demo.Util.RedisLockUtil; |
||||
|
import com.example.demo.domain.DTO.GoldDetailDTO; |
||||
|
import com.example.demo.domain.DTO.GoldUserDTO; |
||||
|
import com.example.demo.domain.entity.User; |
||||
|
import com.example.demo.domain.vo.GoldDetail; |
||||
|
import com.example.demo.domain.vo.Page; |
||||
|
import com.example.demo.domain.vo.Result; |
||||
|
import com.example.demo.service.GoldDetailService; |
||||
|
import com.example.demo.serviceImpl.AiEmotionServiceImpl; |
||||
|
import jakarta.validation.Valid; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.util.ObjectUtils; |
||||
|
import org.springframework.web.bind.annotation.*; |
||||
|
|
||||
|
import java.util.UUID; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName GoldDetailController |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−06-23 14:41 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
@RestController |
||||
|
@RequestMapping("/goldDetail") |
||||
|
@RequiredArgsConstructor |
||||
|
@Slf4j |
||||
|
@CrossOrigin |
||||
|
public class GoldDetailController { |
||||
|
private final GoldDetailService goldDetailService; |
||||
|
|
||||
|
@Autowired |
||||
|
private RedisLockUtil redisLockUtil; |
||||
|
@Autowired |
||||
|
private AiEmotionServiceImpl aiEmotionServiceImpl; |
||||
|
|
||||
|
@PostMapping("/getGoldDetail") |
||||
|
public Result getGoldDetail(@RequestBody Page page){ |
||||
|
|
||||
|
if(ObjectUtils.isEmpty(page.getPageNum())){ |
||||
|
return Result.error("页码数为空!"); |
||||
|
} |
||||
|
if(ObjectUtils.isEmpty(page.getPageSize())){ |
||||
|
return Result.error("页大小为空!"); |
||||
|
} |
||||
|
else{ |
||||
|
return Result.success(goldDetailService.getGoldDetail(page.getPageNum(), page.getPageSize(), page.getGoldDetail())); |
||||
|
} |
||||
|
} |
||||
|
@PostMapping("/getTotal") |
||||
|
public Result getTotal(@RequestBody GoldDetail goldDetail) { |
||||
|
return Result.success(goldDetailService.getTotal(goldDetail)); |
||||
|
} |
||||
|
@PostMapping("/goldTotal") |
||||
|
public Result GoldTotal(@RequestBody User user) { |
||||
|
return Result.success(goldDetailService.GoldTotal(user)); |
||||
|
} |
||||
|
@PostMapping("/getGold") |
||||
|
public Result getGold(@RequestBody Page page) { |
||||
|
System.out.println( page); |
||||
|
if(ObjectUtils.isEmpty(page.getPageNum())){ |
||||
|
return Result.error("页码数为空!"); |
||||
|
} |
||||
|
if(ObjectUtils.isEmpty(page.getPageSize())){ |
||||
|
return Result.error("页大小为空!"); |
||||
|
} |
||||
|
return Result.success(goldDetailService.getGold(page.getPageNum(), page.getPageSize(), page.getUser())); |
||||
|
} |
||||
|
@PostMapping("/export") |
||||
|
public Result export(@Valid @RequestBody GoldDetailDTO dto) { |
||||
|
String lockKey = "export:lock:" + dto.getToken(); // 锁的 Key(可按用户/业务区分) |
||||
|
String requestId = UUID.randomUUID().toString(); // 请求 ID(防止误删锁) |
||||
|
long expireTime = 5000; // 锁过期时间(5秒)s |
||||
|
try { |
||||
|
// 尝试获取锁 |
||||
|
if (!redisLockUtil.tryLock(lockKey, requestId, expireTime)) { |
||||
|
throw new BusinessException("操作太频繁,请稍后重试"); |
||||
|
} |
||||
|
// 执行业务逻辑 |
||||
|
return goldDetailService.addExportRecord(dto); |
||||
|
} finally { |
||||
|
// 释放锁 |
||||
|
redisLockUtil.unlock(lockKey, requestId); |
||||
|
} |
||||
|
} |
||||
|
@PostMapping("/exportGold") |
||||
|
public Result export(@Valid @RequestBody GoldUserDTO dto) { |
||||
|
String lockKey = "export:lock:" + dto.getToken(); // 锁的 Key(可按用户/业务区分) |
||||
|
String requestId = UUID.randomUUID().toString(); // 请求 ID(防止误删锁) |
||||
|
long expireTime = 5000; // 锁过期时间(5秒)s |
||||
|
try { |
||||
|
// 尝试获取锁 |
||||
|
if (!redisLockUtil.tryLock(lockKey, requestId, expireTime)) { |
||||
|
throw new BusinessException("操作太频繁,请稍后重试"); |
||||
|
} |
||||
|
// 执行业务逻辑 |
||||
|
return goldDetailService.addExportRecordGold(dto); |
||||
|
} finally { |
||||
|
// 释放锁 |
||||
|
redisLockUtil.unlock(lockKey, requestId); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,70 @@ |
|||||
|
package com.example.demo.controller; |
||||
|
|
||||
|
import com.example.demo.domain.entity.Admin; |
||||
|
import com.example.demo.domain.entity.AdminRole; |
||||
|
import com.example.demo.domain.vo.Page; |
||||
|
import com.example.demo.domain.vo.Permission; |
||||
|
import com.example.demo.domain.vo.Result; |
||||
|
import com.example.demo.service.PermissionService; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.web.bind.annotation.*; |
||||
|
|
||||
|
import java.util.Arrays; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName PermissionController |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−06-26 13:22 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
@RestController |
||||
|
@RequestMapping("/permission") |
||||
|
@RequiredArgsConstructor |
||||
|
@Slf4j |
||||
|
@CrossOrigin |
||||
|
public class PermissionController { |
||||
|
private final PermissionService permissionService; |
||||
|
@PostMapping("/getposition") |
||||
|
public Result getposition(@RequestBody String token){ |
||||
|
return Result.success(permissionService.getposition(token)); |
||||
|
} |
||||
|
@PostMapping("/getmarket") |
||||
|
public Result getmarket(@RequestBody String token){ |
||||
|
return Result.success(permissionService.getmarket(token)); |
||||
|
} |
||||
|
@PostMapping("/getPermission") |
||||
|
public Result getPermission(@RequestBody Page page){ |
||||
|
return Result.success(permissionService.getpermission(page.getPageNum(), page.getPageSize(), page.getPermission())); |
||||
|
} |
||||
|
@PostMapping("/addPermission") |
||||
|
public Result addPermission(@RequestBody Admin admin) throws Exception { |
||||
|
System.out.println( admin); |
||||
|
try { |
||||
|
return Result.success(permissionService.addpermission(admin)); |
||||
|
} |
||||
|
catch (Exception e) { |
||||
|
log.error(Arrays.toString(e.getStackTrace())); |
||||
|
return Result.error(e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
@PostMapping("/getRole") |
||||
|
public Result getRole(@RequestBody String token){ |
||||
|
return Result.success(permissionService.getRole(token)); |
||||
|
} |
||||
|
@PostMapping("/deleteAdmin") |
||||
|
public Result deleteAdmin(@RequestBody Admin admin){ |
||||
|
return Result.success(permissionService.deleteAdmin(admin.getId())); |
||||
|
} |
||||
|
@PostMapping("/updateAdminRole") |
||||
|
public Result updateAdminRole(@RequestBody AdminRole adminrole){ |
||||
|
return Result.success(permissionService.updateAdminRole(adminrole)); |
||||
|
} |
||||
|
@PostMapping("/upadatePermission") |
||||
|
public Result upadatePermission(@RequestBody Admin admin) throws Exception { |
||||
|
return Result.success(permissionService.upadatePermission(admin)); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,69 @@ |
|||||
|
package com.example.demo.controller; |
||||
|
|
||||
|
|
||||
|
import com.example.demo.domain.entity.Rate; |
||||
|
import com.example.demo.domain.vo.Page; |
||||
|
import com.example.demo.domain.vo.Result; |
||||
|
import com.example.demo.mapper.RateMapper; |
||||
|
import com.example.demo.service.RateService; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.util.ObjectUtils; |
||||
|
import org.springframework.validation.BindingResult; |
||||
|
import org.springframework.web.bind.annotation.*; |
||||
|
|
||||
|
import java.util.Map; |
||||
|
|
||||
|
|
||||
|
@RestController |
||||
|
@RequestMapping("/rate") |
||||
|
@RequiredArgsConstructor |
||||
|
@Slf4j |
||||
|
@CrossOrigin |
||||
|
public class RateController { |
||||
|
|
||||
|
@Autowired |
||||
|
private RateService rateService; |
||||
|
|
||||
|
//货币汇率列表 |
||||
|
@PostMapping("/selectAll") |
||||
|
public Result selectAll(@RequestBody Page page){ |
||||
|
if (ObjectUtils.isEmpty(page.getPageNum())) { |
||||
|
return Result.error("页码数为空!"); |
||||
|
} |
||||
|
if (ObjectUtils.isEmpty(page.getPageSize())) { |
||||
|
return Result.error("页大小为空!"); |
||||
|
} else { |
||||
|
return Result.success(rateService.selectAll(page.getPageNum(), page.getPageSize())); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
//查询货币 |
||||
|
@PostMapping("/selectById") |
||||
|
public Result selectById(@RequestBody Map<String, Object> requestBody) { |
||||
|
Integer id = (Integer) requestBody.get("id"); |
||||
|
if (ObjectUtils.isEmpty(id)) { |
||||
|
return Result.error("id 为空!"); |
||||
|
} |
||||
|
Rate rate = rateService.selectById(id); |
||||
|
return Result.success(rate); |
||||
|
} |
||||
|
|
||||
|
// 编辑 |
||||
|
@PostMapping("/update") |
||||
|
public Result update(@RequestBody Rate rate) { |
||||
|
if (ObjectUtils.isEmpty(rate.getId())) { |
||||
|
return Result.error("id不能为空"); |
||||
|
} |
||||
|
if (ObjectUtils.isEmpty(rate.getRateName())) { |
||||
|
return Result.error("汇率名称不能为空"); |
||||
|
} |
||||
|
if (rate.getNum() == null) { |
||||
|
return Result.error("汇率数值不能为空"); |
||||
|
} |
||||
|
rateService.update(rate); |
||||
|
return Result.success("编辑成功"); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,93 @@ |
|||||
|
package com.example.demo.controller; |
||||
|
|
||||
|
import com.example.demo.domain.vo.*; |
||||
|
import com.example.demo.service.ConsumeService; |
||||
|
import com.example.demo.service.RechargeService; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.util.ObjectUtils; |
||||
|
import org.springframework.web.bind.annotation.*; |
||||
|
|
||||
|
/** |
||||
|
* @program: gold-java |
||||
|
* @ClassName RechargeController |
||||
|
* @description: |
||||
|
* @author: Double |
||||
|
* @create: 2025−06-29 13:01 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
@RestController |
||||
|
@RequestMapping("/recharge") |
||||
|
@RequiredArgsConstructor |
||||
|
@Slf4j |
||||
|
@CrossOrigin |
||||
|
public class RechargeController { |
||||
|
|
||||
|
|
||||
|
@Autowired |
||||
|
private RechargeService rechargeService; |
||||
|
|
||||
|
//消耗明细 |
||||
|
@PostMapping("/selectAll") |
||||
|
public Result selcetAll(@RequestBody Page page) { |
||||
|
try { |
||||
|
if (ObjectUtils.isEmpty(page.getPageNum())) { |
||||
|
return Result.error("页码数为空!"); |
||||
|
} |
||||
|
if (ObjectUtils.isEmpty(page.getPageSize())) { |
||||
|
return Result.error("页大小为空!"); |
||||
|
} else { |
||||
|
return Result.success(rechargeService.selectAll(page.getPageNum(), page.getPageSize(),page.getRechargeUser())); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
return Result.error("接口调用失败"); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
//消耗明细筛选 |
||||
|
@PostMapping("/selectBy") |
||||
|
public Result selcetBy(@RequestBody Page page) { |
||||
|
try { |
||||
|
if (ObjectUtils.isEmpty(page.getPageNum())) { |
||||
|
return Result.error("页码数为空!"); |
||||
|
} |
||||
|
if (ObjectUtils.isEmpty(page.getPageSize())) { |
||||
|
return Result.error("页大小为空!"); |
||||
|
} else { |
||||
|
return Result.success(rechargeService.selectBy(page.getPageNum(), page.getPageSize(), page.getRechargeUser())); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
return Result.error("接口调用失败"); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
//消耗金币统计 |
||||
|
@PostMapping("/statsGold") |
||||
|
public Result statsGold(@RequestBody RechargeUser rechargeUser) { |
||||
|
try { |
||||
|
Gold gold = rechargeService.statsGold(rechargeUser); |
||||
|
return Result.success(gold); |
||||
|
} catch (Exception e) { |
||||
|
return Result.error("接口调用失败"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
//充值金币增加 |
||||
|
@PostMapping("/add") |
||||
|
public Result add(@RequestBody RechargeUser rechargeUser) { |
||||
|
try { |
||||
|
return rechargeService.add(rechargeUser); |
||||
|
} catch (Exception e) { |
||||
|
return Result.error("接口调用失败"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
} |
@ -0,0 +1,101 @@ |
|||||
|
package com.example.demo.controller; |
||||
|
|
||||
|
import com.example.demo.domain.vo.*; |
||||
|
import com.example.demo.service.ConsumeService; |
||||
|
import com.example.demo.service.RefundService; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.util.ObjectUtils; |
||||
|
import org.springframework.web.bind.annotation.*; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* @program: gold-java |
||||
|
* @ClassName RefundMapper.xml |
||||
|
* @description: |
||||
|
* @author: Double |
||||
|
* @create: 2025−06-26 11:28 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
@RestController |
||||
|
@RequestMapping("/refund") |
||||
|
@RequiredArgsConstructor |
||||
|
@Slf4j |
||||
|
@CrossOrigin |
||||
|
public class RefundController { |
||||
|
|
||||
|
@Autowired |
||||
|
private RefundService refundService; |
||||
|
|
||||
|
//退款明细 |
||||
|
@PostMapping("/selectAll") |
||||
|
public Result selcetAll(@RequestBody Page page) { |
||||
|
try { |
||||
|
if (ObjectUtils.isEmpty(page.getPageNum())) { |
||||
|
return Result.error("页码数为空!"); |
||||
|
} |
||||
|
if (ObjectUtils.isEmpty(page.getPageSize())) { |
||||
|
return Result.error("页大小为空!"); |
||||
|
} else { |
||||
|
return Result.success(refundService.selectAll(page.getPageNum(), page.getPageSize(), page.getRefundUser())); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
return Result.error("接口调用失败"); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
@PostMapping("/selectBy") |
||||
|
public Result selcetBy(@RequestBody Page page) { |
||||
|
try { |
||||
|
if (ObjectUtils.isEmpty(page.getPageNum())) { |
||||
|
return Result.error("页码数为空!"); |
||||
|
} |
||||
|
if (ObjectUtils.isEmpty(page.getPageSize())) { |
||||
|
return Result.error("页大小为空!"); |
||||
|
} else { |
||||
|
return Result.success(refundService.selectBy(page.getPageNum(), page.getPageSize(), page.getRefundUser())); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
return Result.error("接口调用失败"); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
@PostMapping("/statsGold") |
||||
|
public Result statsGold(@RequestBody RefundUser refundUser) { |
||||
|
try { |
||||
|
Gold gold = refundService.statsGold(refundUser); |
||||
|
return Result.success(gold); |
||||
|
} catch (Exception e) { |
||||
|
return Result.error("接口调用失败"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@PostMapping("/refundType") |
||||
|
public Result getRefundType() |
||||
|
{ |
||||
|
List<String> list = refundService.getRefundType(); |
||||
|
return Result.success(list); |
||||
|
} |
||||
|
|
||||
|
@PostMapping("/selectGoods") |
||||
|
public Result getSelectGoods(@RequestBody RefundUser refundUser) |
||||
|
{ |
||||
|
List<RefundUser> list = refundService.selectGoods(refundUser.getJwcode()); |
||||
|
return Result.success(list); |
||||
|
} |
||||
|
|
||||
|
//消耗金币增加 |
||||
|
@PostMapping("/add") |
||||
|
public Result add(@RequestBody RefundUser refundUser) { |
||||
|
try { |
||||
|
return refundService.add(refundUser); |
||||
|
} catch (Exception e) { |
||||
|
return Result.error("接口调用失败"); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,41 @@ |
|||||
|
package com.example.demo.controller; |
||||
|
|
||||
|
import com.example.demo.domain.vo.Gold; |
||||
|
import com.example.demo.domain.vo.GoldUser; |
||||
|
import com.example.demo.domain.vo.Result; |
||||
|
import com.example.demo.service.ConsumeService; |
||||
|
import com.example.demo.service.UserService; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.web.bind.annotation.*; |
||||
|
|
||||
|
/** |
||||
|
* @program: gold-java |
||||
|
* @ClassName UserController |
||||
|
* @description: |
||||
|
* @author: Double |
||||
|
* @create: 2025−06-25 10:25 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
@RestController |
||||
|
@RequestMapping("/user") |
||||
|
@RequiredArgsConstructor |
||||
|
@Slf4j |
||||
|
@CrossOrigin |
||||
|
public class UserController { |
||||
|
|
||||
|
@Autowired |
||||
|
private UserService userService; |
||||
|
|
||||
|
@PostMapping("/selectUser") |
||||
|
public Result selectUser(@RequestBody GoldUser user) { |
||||
|
try { |
||||
|
user = userService.selectUser(user.getJwcode().toString()); |
||||
|
return Result.success(user); |
||||
|
} catch (Exception e) { |
||||
|
return Result.error("接口调用失败"); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,42 @@ |
|||||
|
package com.example.demo.domain.DTO; |
||||
|
|
||||
|
import jakarta.validation.constraints.NotNull; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName ConsumeDTO |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−07-01 16:17 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
public class ConsumeDTO { |
||||
|
private String token; |
||||
|
private String url = ""; |
||||
|
private String fileName = ""; |
||||
|
private Integer sort = 0; |
||||
|
private String field = ""; |
||||
|
private Integer account; |
||||
|
private Integer type = 4; //类型 |
||||
|
private Integer state = 0; //状态 |
||||
|
private String text = ""; //关键词搜索 |
||||
|
private Integer dataNum = 0; |
||||
|
private String deptid = ""; |
||||
|
|
||||
|
@NotNull(message = "page不能为空") |
||||
|
private Integer page = 1; |
||||
|
@NotNull(message = "pageSize不能为空") |
||||
|
private Integer pageSize = 20; |
||||
|
|
||||
|
@Override |
||||
|
public String toString() { |
||||
|
return String.format( |
||||
|
"AiEmotionExport(account=%d, type=%d, state=%d, dataNum=%d)", |
||||
|
account, type, state, dataNum |
||||
|
); |
||||
|
} |
||||
|
} |
@ -0,0 +1,44 @@ |
|||||
|
package com.example.demo.domain.DTO; |
||||
|
|
||||
|
import jakarta.validation.constraints.NotNull; |
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName AiEmotionExportDTO |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−06-30 15:06 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
@AllArgsConstructor |
||||
|
public class GoldDetailDTO { |
||||
|
private String token; |
||||
|
private String url = ""; |
||||
|
private String fileName = ""; |
||||
|
private Integer sort = 0; |
||||
|
private String field = ""; |
||||
|
private Integer account; |
||||
|
private Integer type = 0; //类型 |
||||
|
private Integer state = 0; //状态 |
||||
|
private String text = ""; //关键词搜索 |
||||
|
private Integer dataNum = 0; |
||||
|
private String deptid = ""; |
||||
|
|
||||
|
@NotNull(message = "page不能为空") |
||||
|
private Integer page = 1; |
||||
|
@NotNull(message = "pageSize不能为空") |
||||
|
private Integer pageSize = 20; |
||||
|
|
||||
|
@Override |
||||
|
public String toString() { |
||||
|
return String.format( |
||||
|
"AiEmotionExport(account=%d, type=%d, state=%d, dataNum=%d)", |
||||
|
account, type, state, dataNum |
||||
|
); |
||||
|
} |
||||
|
} |
@ -0,0 +1,42 @@ |
|||||
|
package com.example.demo.domain.DTO; |
||||
|
|
||||
|
import jakarta.validation.constraints.NotNull; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName GoldDTO |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−06-30 23:40 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
public class GoldUserDTO { |
||||
|
private String token; |
||||
|
private String url = ""; |
||||
|
private String fileName = ""; |
||||
|
private Integer sort = 0; |
||||
|
private String field = ""; |
||||
|
private Integer account; |
||||
|
private Integer type = 1; //类型 |
||||
|
private Integer state = 0; //状态 |
||||
|
private String text = ""; //关键词搜索 |
||||
|
private Integer dataNum = 0; |
||||
|
private String deptid = ""; |
||||
|
|
||||
|
@NotNull(message = "page不能为空") |
||||
|
private Integer page = 1; |
||||
|
@NotNull(message = "pageSize不能为空") |
||||
|
private Integer pageSize = 20; |
||||
|
|
||||
|
@Override |
||||
|
public String toString() { |
||||
|
return String.format( |
||||
|
"AiEmotionExport(account=%d, type=%d, state=%d, dataNum=%d)", |
||||
|
account, type, state, dataNum |
||||
|
); |
||||
|
} |
||||
|
} |
@ -0,0 +1,43 @@ |
|||||
|
package com.example.demo.domain.DTO; |
||||
|
|
||||
|
import jakarta.validation.constraints.NotNull; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName RechargeDTO |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−07-01 16:15 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
public class RechargeDTO { |
||||
|
private String token; |
||||
|
private String url = ""; |
||||
|
private String fileName = ""; |
||||
|
private Integer sort = 0; |
||||
|
private String field = ""; |
||||
|
private Integer account; |
||||
|
private Integer type = 2; //类型 |
||||
|
private Integer state = 0; //状态 |
||||
|
private String text = ""; //关键词搜索 |
||||
|
private Integer dataNum = 0; |
||||
|
private String deptid = ""; |
||||
|
|
||||
|
@NotNull(message = "page不能为空") |
||||
|
private Integer page = 1; |
||||
|
@NotNull(message = "pageSize不能为空") |
||||
|
private Integer pageSize = 20; |
||||
|
|
||||
|
@Override |
||||
|
public String toString() { |
||||
|
return String.format( |
||||
|
"AiEmotionExport(account=%d, type=%d, state=%d, dataNum=%d)", |
||||
|
account, type, state, dataNum |
||||
|
); |
||||
|
} |
||||
|
} |
@ -0,0 +1,42 @@ |
|||||
|
package com.example.demo.domain.DTO; |
||||
|
|
||||
|
import jakarta.validation.constraints.NotNull; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName RefundDTO |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−07-01 16:16 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
public class RefundDTO { |
||||
|
private String token; |
||||
|
private String url = ""; |
||||
|
private String fileName = ""; |
||||
|
private Integer sort = 0; |
||||
|
private String field = ""; |
||||
|
private Integer account; |
||||
|
private Integer type = 3; //类型 |
||||
|
private Integer state = 0; //状态 |
||||
|
private String text = ""; //关键词搜索 |
||||
|
private Integer dataNum = 0; |
||||
|
private String deptid = ""; |
||||
|
|
||||
|
@NotNull(message = "page不能为空") |
||||
|
private Integer page = 1; |
||||
|
@NotNull(message = "pageSize不能为空") |
||||
|
private Integer pageSize = 20; |
||||
|
|
||||
|
@Override |
||||
|
public String toString() { |
||||
|
return String.format( |
||||
|
"AiEmotionExport(account=%d, type=%d, state=%d, dataNum=%d)", |
||||
|
account, type, state, dataNum |
||||
|
); |
||||
|
} |
||||
|
} |
@ -0,0 +1,33 @@ |
|||||
|
package com.example.demo.domain.entity; |
||||
|
|
||||
|
import com.fasterxml.jackson.annotation.JsonFormat; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
import org.springframework.format.annotation.DateTimeFormat; |
||||
|
|
||||
|
import java.util.Date; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName Export |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−06-24 16:17 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
public class Export { |
||||
|
private String token; |
||||
|
private Integer account; // 账号 |
||||
|
private String url; // 文件路径 |
||||
|
private String fileName; // 文件名 |
||||
|
private Byte type; // 类型 |
||||
|
private Byte state; // 状态 |
||||
|
private Integer dataNum; // 数据量 |
||||
|
private String reason; // 失败原因 |
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") |
||||
|
private Date createTime; // 创建时间 |
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") |
||||
|
private Date updateTime; // 更新时间 |
||||
|
} |
@ -0,0 +1,28 @@ |
|||||
|
package com.example.demo.domain.export; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName goldmingxi |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−06-29 17:37 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
public class Goldmingxi { |
||||
|
private String name; // 名称 |
||||
|
private Integer jwcode; // 精网号 |
||||
|
private String market; // 所属地区 |
||||
|
private String payPlatform; // 支付平台 |
||||
|
private Integer type; // 类型 |
||||
|
private Integer sumGold; // 总金币 |
||||
|
private Integer permentGold; //永久金币 |
||||
|
private Integer freeJune; // 免费金币六月到期 |
||||
|
private Integer freeDecember; // 免费金币七月到期 |
||||
|
private Integer taskGold; // 任务金币 |
||||
|
private String adminName; //提交人 |
||||
|
} |
@ -0,0 +1,28 @@ |
|||||
|
package com.example.demo.domain.vo; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
import java.util.Date; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName AiEmotionExportRecordVO |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−06-29 14:59 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
public class AiEmotionExportRecordVO { |
||||
|
private static final long serialVersionUID = 1L; |
||||
|
private String token; |
||||
|
private Long id; |
||||
|
private Long jwcode; |
||||
|
private String fileName; |
||||
|
private String url; |
||||
|
private Integer state; |
||||
|
private Date createTime; |
||||
|
private Date updateTime; |
||||
|
} |
@ -0,0 +1,18 @@ |
|||||
|
package com.example.demo.domain.vo; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
@AllArgsConstructor |
||||
|
public class AuditRequest { |
||||
|
private String token; |
||||
|
private String orderCode; //订单号 |
||||
|
private Integer auditId; //审核人id |
||||
|
private Integer action; //操作 |
||||
|
private String rejectReason; //驳回理由 |
||||
|
|
||||
|
|
||||
|
} |
@ -0,0 +1,50 @@ |
|||||
|
package com.example.demo.domain.vo; |
||||
|
|
||||
|
import com.fasterxml.jackson.annotation.JsonFormat; |
||||
|
import jakarta.validation.constraints.PositiveOrZero; |
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
import java.io.Serializable; |
||||
|
import java.util.Date; |
||||
|
|
||||
|
/** |
||||
|
* @program: gold-java |
||||
|
* @ClassName Consume |
||||
|
* @description: 消费明细 |
||||
|
* @author: Double |
||||
|
* @create: 2025−06-23 11:53 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
@AllArgsConstructor |
||||
|
public class ConsumeUser implements Serializable { |
||||
|
|
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
private String name; // 客户姓名 |
||||
|
private Integer jwcode; // 精网号 |
||||
|
private String market; // 所属地区 |
||||
|
private String goodsName; // 商品名称 |
||||
|
private String payPlatform; // 消费平台 |
||||
|
private Integer sumGold; // 金币总数 |
||||
|
private Integer permanentGold; // 永久金币 |
||||
|
private Integer freeGold; // 免费金币 |
||||
|
private Integer taskGold; // 任务金币 |
||||
|
private String remark; // 备注 |
||||
|
private Integer adminId; //提交人Id |
||||
|
private String adminName; //提交人姓名 |
||||
|
|
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") |
||||
|
private Date createTime; // 消费时间 |
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") |
||||
|
private Date startTime; // 开始时间 |
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") |
||||
|
private Date endTime; // 结束时间 |
||||
|
|
||||
|
private String sortField; //排序字段 |
||||
|
private String sortOrder; //排序顺序 |
||||
|
} |
@ -0,0 +1,25 @@ |
|||||
|
package com.example.demo.domain.vo; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Data; |
||||
|
|
||||
|
import java.util.Date; |
||||
|
|
||||
|
@Data |
||||
|
@AllArgsConstructor |
||||
|
public class ExecutionContext { |
||||
|
// getters 和 setters |
||||
|
private String executionType; // "API" 或 "SCRIPT" |
||||
|
private String apiUrl; |
||||
|
private String requestParams; |
||||
|
private String token; |
||||
|
private String scriptFile; |
||||
|
private Date executionTime; |
||||
|
private String method; |
||||
|
|
||||
|
// 构造方法 |
||||
|
public ExecutionContext() { |
||||
|
this.executionTime = new Date(); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,26 @@ |
|||||
|
package com.example.demo.domain.vo; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
import java.util.Date; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName ExportVo |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−06-29 17:24 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
|
||||
|
public class ExportVo { |
||||
|
private String token; |
||||
|
private Long id; |
||||
|
private String fileName; |
||||
|
private String url; |
||||
|
private Integer state; |
||||
|
|
||||
|
} |
@ -0,0 +1,27 @@ |
|||||
|
package com.example.demo.domain.vo; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
import java.io.Serializable; |
||||
|
|
||||
|
/** |
||||
|
* @program: gold-java |
||||
|
* @ClassName Gold |
||||
|
* @description: 金币信息 |
||||
|
* @author: Double |
||||
|
* @create: 2025−06-23 15:53 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
@AllArgsConstructor |
||||
|
public class Gold implements Serializable { |
||||
|
private static final long serialVersionUID = 1L; |
||||
|
private Integer totalNum; //总条数 |
||||
|
private Integer permanentGolds; // 永久金币总数 |
||||
|
private Integer freeGolds; // 免费金币总数 |
||||
|
private Integer taskGolds; // 任务金币总数 |
||||
|
} |
@ -0,0 +1,42 @@ |
|||||
|
package com.example.demo.domain.vo; |
||||
|
|
||||
|
import com.fasterxml.jackson.annotation.JsonFormat; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
import org.springframework.format.annotation.DateTimeFormat; |
||||
|
|
||||
|
import java.util.Date; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName GoldDetail |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−06-23 13:03 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
public class GoldDetail { |
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
private String token; |
||||
|
private String name; // 名称 |
||||
|
private Integer jwcode; // 精网号 |
||||
|
private String market; // 所属地区 |
||||
|
private String payPlatform; // 支付平台 |
||||
|
private Integer type; // 类型 |
||||
|
private Integer sumGold; // 总金币 |
||||
|
private Integer permentGold; //永久金币 |
||||
|
private Integer freeJune; // 免费金币六月到期 |
||||
|
private Integer freeDecember; // 免费金币七月到期 |
||||
|
private Integer taskGold; // 任务金币 |
||||
|
private String adminName; //提交人 |
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") |
||||
|
private Date startTime; // 开始时间 |
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") |
||||
|
private Date endTime; // 结束时间 |
||||
|
private String sortField; //排序字段 |
||||
|
private String sortOrder; //排序顺序 |
||||
|
|
||||
|
} |
@ -0,0 +1,41 @@ |
|||||
|
package com.example.demo.domain.vo; |
||||
|
|
||||
|
import com.fasterxml.jackson.annotation.JsonFormat; |
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
import java.util.Date; |
||||
|
|
||||
|
/** |
||||
|
* @program: gold-java |
||||
|
* @ClassName ConsumeUser |
||||
|
* @description: |
||||
|
* @author: Double |
||||
|
* @create: 2025−06-24 18:30 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
@AllArgsConstructor |
||||
|
public class GoldUser { |
||||
|
private String name; // 客户姓名 |
||||
|
private Integer jwcode; // 精网号 |
||||
|
private String market; // 所属地区 |
||||
|
private Integer NowSumGold; // 当前金币总数 |
||||
|
private Integer NowPermanentGold; // 当前永久金币 |
||||
|
private Integer NowFreeGold; // 当前免费金币 |
||||
|
private Integer NowFreeJune; // 免费金币6月 |
||||
|
private Integer NowFreeDecember; // 免费金币12月 |
||||
|
private Integer NowTaskGold; // 当前任务金币 |
||||
|
private Integer historySumGold; // 历史金币总数 |
||||
|
private Integer historyPermanentGold; // 历史永久金币 |
||||
|
private Integer historyFreeGold; // 历史免费金币 |
||||
|
private Integer historyTaskGold; // 历史任务金币 |
||||
|
private Integer rechargeNum; // 充值次数 |
||||
|
private Integer consumeNum; // 消费次数 |
||||
|
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "Asia/Shanghai") |
||||
|
private Date firstRecharge; // 首充日期 |
||||
|
|
||||
|
} |
@ -0,0 +1,30 @@ |
|||||
|
package com.example.demo.domain.vo; |
||||
|
|
||||
|
import com.example.demo.domain.entity.User; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName Page |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−06-23 16:23 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
public class Page { |
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
private Integer pageNum; |
||||
|
private Integer pageSize; |
||||
|
private GoldDetail goldDetail; |
||||
|
private ConsumeUser consumeUser; |
||||
|
private User user; |
||||
|
private RefundUser refundUser; |
||||
|
private Permission permission; |
||||
|
private RechargeAudit rechargeAudit; |
||||
|
private RefundAudit refundAudit; |
||||
|
private RechargeUser rechargeUser; |
||||
|
} |
@ -0,0 +1,27 @@ |
|||||
|
package com.example.demo.domain.vo; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName Permission |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−06-26 10:54 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
public class Permission { |
||||
|
private String token; |
||||
|
private String id; |
||||
|
private String name; //姓名 |
||||
|
private String account; //账号 |
||||
|
private String market; //地区 |
||||
|
private String postiton; //职位 |
||||
|
private String roleName; //角色 |
||||
|
private String remark; //备注 |
||||
|
private Integer adminStatus; //状态 |
||||
|
private Integer roleId; //角色id |
||||
|
} |
@ -0,0 +1,30 @@ |
|||||
|
package com.example.demo.domain.vo; |
||||
|
|
||||
|
import com.fasterxml.jackson.annotation.JsonFormat; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
import java.math.BigDecimal; |
||||
|
import java.util.Date; |
||||
|
|
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
public class RateDetail { |
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
|
||||
|
private Integer id; |
||||
|
private String rateName; |
||||
|
private BigDecimal num = BigDecimal.ZERO; |
||||
|
private Integer adminId;//提交人 |
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") |
||||
|
private Date createTime; // 创建时间 |
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") |
||||
|
private Date updateTime; // 更新时间 |
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") |
||||
|
private Date lastTime; // 最晚时间 |
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
@ -0,0 +1,57 @@ |
|||||
|
package com.example.demo.domain.vo; |
||||
|
|
||||
|
import com.fasterxml.jackson.annotation.JsonFormat; |
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
import java.util.Date; |
||||
|
|
||||
|
/** |
||||
|
* @program: gold-java |
||||
|
* @ClassName RechargeAudit |
||||
|
* @description: 充值审核 |
||||
|
* @author: Ethan |
||||
|
* @create: 2025−06-30 10:29 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
@AllArgsConstructor |
||||
|
public class RechargeAudit { |
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
private String name; // 客户姓名 |
||||
|
private Integer jwcode; // 精网号 |
||||
|
private String orderCode; // 订单号 |
||||
|
private String activity; // 活动名称 |
||||
|
private String market; // 所属地区 |
||||
|
private Byte refundType; // 退款类型 |
||||
|
private Integer sumGold; //充值金额 |
||||
|
private Integer permanentGold; // 永久金币 |
||||
|
private Integer freeGold; // 免费金币 |
||||
|
private Integer freeJune; // 6月免费金币 |
||||
|
private Integer freeDecember; // 12月免费金币 |
||||
|
private String remark; // 备注 |
||||
|
private String payModel; //支付方式 |
||||
|
private String voucher; //支付凭证 |
||||
|
private Integer adminId; //提交人Id |
||||
|
private String adminName; //提交人姓名 |
||||
|
private String auditStatus; //审核状态 |
||||
|
private Integer auditId; //审核人Id |
||||
|
private String auditName; //审核人姓名 |
||||
|
private Byte type; //类型 |
||||
|
private String rejectReason; //驳回理由 |
||||
|
|
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") |
||||
|
private String payTime; //支付时间 |
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") |
||||
|
private Date createTime; // 创建时间 |
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") |
||||
|
private Date startTime; // 开始时间 |
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") |
||||
|
private Date endTime; // 结束时间 |
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") |
||||
|
private Date auditTime; // 审核时间 |
||||
|
} |
@ -0,0 +1,51 @@ |
|||||
|
package com.example.demo.domain.vo; |
||||
|
|
||||
|
import com.fasterxml.jackson.annotation.JsonFormat; |
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
import java.util.Date; |
||||
|
|
||||
|
/** |
||||
|
* @program: gold-java |
||||
|
* @ClassName Recharge |
||||
|
* @description: |
||||
|
* @author: Double |
||||
|
* @create: 2025−06-29 13:18 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
@AllArgsConstructor |
||||
|
public class RechargeUser { |
||||
|
|
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
private String name; // 客户姓名 |
||||
|
private Integer jwcode; // 精网号 |
||||
|
private String market; // 所属地区 |
||||
|
private String activity; // 活动名称 |
||||
|
private Integer rateId; // 汇率ID |
||||
|
private String rateName; // 汇率名称 |
||||
|
private Integer money; // 金额[分] |
||||
|
private Integer permanentGold; // 永久金币 |
||||
|
private Integer freeGold; // 免费金币 |
||||
|
private String payModel; // 支付方式 |
||||
|
private String payPlatform; // 支付平台 |
||||
|
private String voucher; // 支付凭证 |
||||
|
private String remark; // 备注 |
||||
|
private Integer adminId; //提交人Id |
||||
|
private String adminName; //提交人姓名 |
||||
|
|
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") |
||||
|
private Date payTime; // 创建时间 |
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") |
||||
|
private Date startTime; // 开始时间 |
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") |
||||
|
private Date endTime; // 结束时间 |
||||
|
|
||||
|
private String sortField; //排序字段 |
||||
|
private String sortOrder; //排序顺序 |
||||
|
} |
@ -0,0 +1,54 @@ |
|||||
|
package com.example.demo.domain.vo; |
||||
|
|
||||
|
import com.fasterxml.jackson.annotation.JsonFormat; |
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
import java.util.Date; |
||||
|
|
||||
|
/** |
||||
|
* @program: gold-java |
||||
|
* @ClassName RechargeAudit |
||||
|
* @description: 退款审核 |
||||
|
* @author: Ethan |
||||
|
* @create: 2025−06-30 13:29 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
@AllArgsConstructor |
||||
|
public class RefundAudit { |
||||
|
private static final long serialVersionUID = 1L; |
||||
|
private String name; // 客户姓名 |
||||
|
private Integer jwcode; // 精网号 |
||||
|
private String orderCode; // 订单号 |
||||
|
private String market; // 所属地区 |
||||
|
private Integer refundModel; // 退款方式-全额 部分 |
||||
|
private String goodsName; // 商品名称 |
||||
|
private Integer sumGold; // 退款金额 |
||||
|
private Integer permanentGold; // 永久金币 |
||||
|
private Integer freeGold; // 免费金币 |
||||
|
private Integer freeJune; // 6月免费金币 |
||||
|
private Integer freeDecember; // 12月免费金币 |
||||
|
private Integer taskGold; // 任务金币 |
||||
|
private String remark; // 备注 |
||||
|
private Integer adminId; //提交人Id |
||||
|
private String adminName; //提交人姓名 |
||||
|
private String auditStatus; //审核状态 |
||||
|
private Integer auditId; //审核人Id |
||||
|
private String auditName; //审核人姓名 |
||||
|
private String rejectReason; //驳回理由 |
||||
|
private Byte type; //类型 |
||||
|
|
||||
|
|
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") |
||||
|
private Date createTime; // 创建时间 |
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") |
||||
|
private Date startTime; // 开始时间 |
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") |
||||
|
private Date endTime; // 结束时间 |
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") |
||||
|
private Date auditTime; // 审核时间 |
||||
|
} |
@ -0,0 +1,50 @@ |
|||||
|
package com.example.demo.domain.vo; |
||||
|
|
||||
|
import com.fasterxml.jackson.annotation.JsonFormat; |
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
import java.util.Date; |
||||
|
|
||||
|
/** |
||||
|
* @program: gold-java |
||||
|
* @ClassName RefundUser |
||||
|
* @description: |
||||
|
* @author: Double |
||||
|
* @create: 2025−06-26 11:29 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
@AllArgsConstructor |
||||
|
public class RefundUser { |
||||
|
|
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
private String orderCode; // 订单号 |
||||
|
private String name; // 客户姓名 |
||||
|
private Integer jwcode; // 精网号 |
||||
|
private String market; // 所属地区 |
||||
|
private String goodsName; // 商品名称 |
||||
|
private String refundType; // 退款类型 |
||||
|
private Byte refundModel; // 退款方式(0全部/1部分退款) |
||||
|
private Integer sumGold; // 金币总数 |
||||
|
private Integer permanentGold; // 永久金币 |
||||
|
private Integer freeGold; // 免费金币 |
||||
|
private Integer taskGold; // 任务金币 |
||||
|
private String remark; // 退款原因 |
||||
|
private Integer adminId; //提交人Id |
||||
|
private String adminName; //提交人姓名 |
||||
|
|
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") |
||||
|
private Date createTime; // 创建时间 |
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") |
||||
|
private Date startTime; // 开始时间 |
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") |
||||
|
private Date endTime; // 结束时间 |
||||
|
|
||||
|
private String sortField; //排序字段 |
||||
|
private String sortOrder; //排序顺序 |
||||
|
} |
@ -0,0 +1,17 @@ |
|||||
|
package com.example.demo.domain.vo; |
||||
|
|
||||
|
import com.fasterxml.jackson.annotation.JsonFormat; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
import java.util.Date; |
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
public class TestRequest { |
||||
|
private String market; |
||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") |
||||
|
private Date date; |
||||
|
|
||||
|
|
||||
|
|
||||
|
} |
@ -0,0 +1,25 @@ |
|||||
|
package com.example.demo.domain.vo; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName Total |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−06-23 16:53 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
public class Total { |
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
private String token; |
||||
|
private Integer Goldtotal; |
||||
|
private Integer permanentGold; |
||||
|
private Integer freeGold; |
||||
|
private Integer taskGold; |
||||
|
|
||||
|
} |
@ -0,0 +1,65 @@ |
|||||
|
package com.example.demo.domain.vo; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
import java.io.Serializable; |
||||
|
|
||||
|
/** |
||||
|
* @program: gold-java |
||||
|
* @ClassName WorkbenchMarketCard |
||||
|
* @description: |
||||
|
* @author: Ethan |
||||
|
* @create: 2025−06-25 16:20 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
@AllArgsConstructor |
||||
|
public class WorkbenchMarketCard implements Serializable { |
||||
|
|
||||
|
private String market;//地区 |
||||
|
// 卡片一:当前金币相关 |
||||
|
private Integer currentGold; // 当前金币余量 |
||||
|
private Integer dailyChange; // 余量较前一天的变化 |
||||
|
private Integer currentPermanent; // 永久金币余量 |
||||
|
private Integer currentFreeJune; // 六月到期免费金币余量 |
||||
|
private Integer currentFreeDecember; // 十二月到期免费金币余量 |
||||
|
private Integer currentTask; // 任务金币余量 |
||||
|
private Integer currentFree; // 免费金币余量(currentFreeJune + currentFreeDecember) |
||||
|
|
||||
|
// 卡片二:充值相关 |
||||
|
private Integer recharge; // 当日充值金币数 |
||||
|
private Integer money; // 当日金额(永久金币) |
||||
|
private Integer yearlyRecharge; // 全年累计充值金币数 |
||||
|
private Integer yearlyMoney; // 全年累计金额 |
||||
|
|
||||
|
// 卡片三:当日消费/退款/消耗相关 |
||||
|
private Integer consumePermanent; // 当日新增消费(永久) |
||||
|
private Integer consumeFreeJune; // 当日新增消费(六月免费) |
||||
|
private Integer consumeFreeDecember; // 当日新增消费(十二月免费) |
||||
|
private Integer consumeTask; // 当日新增消费(任务) |
||||
|
private Integer refundPermanent; // 当日新增退款(永久) |
||||
|
private Integer refundFreeJune; // 当日新增退款(六月免费) |
||||
|
private Integer refundFreeDecember; // 当日新增退款(十二月免费) |
||||
|
private Integer refundTask; // 当日新增退款(任务) |
||||
|
private Integer dailyReduce; // 当日总消耗 = consumePermanent + consumeFreeJune + consumeFreeDecember + consumeTask - (refundPermanent + refundFreeJune + refundFreeDecember + refundTask) |
||||
|
private Integer yearlyConsume; // 全年累计消费 |
||||
|
private Integer yearlyRefund; // 全年累计退款金币数 |
||||
|
private Integer yearlyReduce; // 全年累计消耗金币数 = yearlyConsume - yearlyRefund |
||||
|
|
||||
|
// 卡片四:人头数相关 |
||||
|
private Integer rechargeNum; // 当日充值人数 |
||||
|
private Integer firstRecharge; // 当日首充人数 |
||||
|
private Integer wow; // 周同比(%) |
||||
|
private Integer daily; // 日环比(%) |
||||
|
private Integer yearlyRechargeNum; // 全年累计充值人头数 |
||||
|
//图表 |
||||
|
private Integer SumRechargePermanent; //合计充值永久金币 |
||||
|
private Integer SumRechargeFree; //合计充值免费金币 |
||||
|
private Integer SumConsumePermanent; //合计消费永久金币 |
||||
|
private Integer SumConsumeFree; //合计消费免费金币 |
||||
|
private Integer SumConsumeTask; //合计消费任务金币 |
||||
|
} |
@ -0,0 +1,13 @@ |
|||||
|
package com.example.demo.exception; |
||||
|
|
||||
|
public class SystemException extends RuntimeException { |
||||
|
public SystemException(String message) { |
||||
|
super(message); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
public SystemException(String message, Throwable cause) { |
||||
|
super(message, cause); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,18 @@ |
|||||
|
package com.example.demo.mapper; |
||||
|
|
||||
|
import com.example.demo.domain.entity.Admin; |
||||
|
import org.apache.ibatis.annotations.Mapper; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName AdminMapper |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−06-27 17:21 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
@Mapper |
||||
|
public interface AdminMapper { |
||||
|
Admin getAdmin(String account); |
||||
|
Admin selectByName(String account); |
||||
|
} |
@ -0,0 +1,25 @@ |
|||||
|
package com.example.demo.mapper; |
||||
|
|
||||
|
import com.example.demo.domain.vo.AiEmotionExportRecordVO; |
||||
|
import org.apache.ibatis.annotations.Mapper; |
||||
|
import org.apache.ibatis.annotations.Param; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName AiEmotionMapper |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−06-29 16:48 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
@Mapper |
||||
|
public interface AiEmotionMapper { |
||||
|
void updateStatus( |
||||
|
@Param("recordId") Long recordId, |
||||
|
@Param("state") Integer state, |
||||
|
@Param("url") String url, |
||||
|
@Param("reason") String reason, |
||||
|
@Param("dataNum") Integer dataNum |
||||
|
); |
||||
|
AiEmotionExportRecordVO getRecordById(Long recordId); |
||||
|
} |
@ -0,0 +1,28 @@ |
|||||
|
package com.example.demo.mapper; |
||||
|
|
||||
|
import com.example.demo.domain.entity.UserGoldRecord; |
||||
|
import com.example.demo.domain.vo.ConsumeUser; |
||||
|
import org.apache.ibatis.annotations.Mapper; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* @program: gold-java |
||||
|
* @ClassName ConsumeMapper |
||||
|
* @description: |
||||
|
* @author: Double |
||||
|
* @create: 2025−06-23 13:45 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
@Mapper |
||||
|
public interface ConsumeMapper { |
||||
|
|
||||
|
List<ConsumeUser> selectAll(ConsumeUser consumeUser); |
||||
|
|
||||
|
List<ConsumeUser> selectBy(ConsumeUser consumeUser); |
||||
|
|
||||
|
void add(UserGoldRecord userGoldRecord); |
||||
|
|
||||
|
void updateIsRefund(String orderCode); |
||||
|
} |
@ -0,0 +1,23 @@ |
|||||
|
package com.example.demo.mapper; |
||||
|
|
||||
|
import com.example.demo.domain.entity.Export; |
||||
|
import com.example.demo.domain.vo.ExportVo; |
||||
|
import org.apache.ibatis.annotations.Mapper; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName ExportMapper |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−06-29 17:28 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
@Mapper |
||||
|
public interface ExportMapper { |
||||
|
ExportVo getExportData(Integer id); |
||||
|
int updateExportData(Long recordId, Integer state, String url, String reason, Integer dataNum); |
||||
|
List<Export> getExportRecord(Integer account); |
||||
|
|
||||
|
} |
@ -0,0 +1,39 @@ |
|||||
|
package com.example.demo.mapper; |
||||
|
|
||||
|
import com.example.demo.domain.entity.User; |
||||
|
import com.example.demo.domain.vo.GoldDetail; |
||||
|
import com.example.demo.domain.vo.Total; |
||||
|
import lombok.Data; |
||||
|
import org.apache.ibatis.annotations.Mapper; |
||||
|
import org.apache.ibatis.annotations.Param; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName GoldDetailMapper |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−06-23 13:47 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
@Mapper |
||||
|
public interface GoldDetailMapper { |
||||
|
List<GoldDetail> getGoldDetail(GoldDetail goldDetail); |
||||
|
Total getTotal(GoldDetail goldDetail); |
||||
|
List<User> getGold(User user); |
||||
|
Total GoldTotal(User user); |
||||
|
@Data |
||||
|
public static class ExportRecordIdHolder{ |
||||
|
private Long id; |
||||
|
} |
||||
|
void insertExportRecord( |
||||
|
@Param("recordId") ExportRecordIdHolder recordId, // 用于接收主键 |
||||
|
@Param("account") Integer account, |
||||
|
@Param("type") Integer type, |
||||
|
@Param("state") Integer state, |
||||
|
@Param("url") String url, |
||||
|
@Param("fileName") String fileName, |
||||
|
@Param("dataNum") Integer dataNum |
||||
|
); |
||||
|
} |
@ -0,0 +1,31 @@ |
|||||
|
package com.example.demo.mapper; |
||||
|
|
||||
|
import com.example.demo.domain.entity.Admin; |
||||
|
import com.example.demo.domain.entity.AdminRole; |
||||
|
import com.example.demo.domain.entity.Role; |
||||
|
import com.example.demo.domain.vo.Permission; |
||||
|
import org.apache.ibatis.annotations.Mapper; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName PermissionMapper |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−06-26 11:25 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
@Mapper |
||||
|
public interface PermissionMapper { |
||||
|
List<String> getposition(String token); |
||||
|
List<String> getmarket(String token); |
||||
|
List<Permission> getPermission(Permission permission); |
||||
|
Integer updatePermission(Admin admin); |
||||
|
Integer addPermission(Admin admin); |
||||
|
List<Role> getRole(String token); |
||||
|
Integer addadminRole(AdminRole adminRole); |
||||
|
Integer deleteAdmin(Integer id); |
||||
|
Integer deleteAdminRole(Integer id); |
||||
|
Integer updateAdminRole(AdminRole adminRole); |
||||
|
} |
@ -0,0 +1,18 @@ |
|||||
|
package com.example.demo.mapper; |
||||
|
|
||||
|
import com.example.demo.domain.entity.Rate; |
||||
|
import com.example.demo.domain.vo.RateDetail; |
||||
|
import org.apache.ibatis.annotations.Mapper; |
||||
|
|
||||
|
import java.util.List; |
||||
|
@Mapper |
||||
|
public interface RateMapper { |
||||
|
|
||||
|
List<Rate> selectAll(); |
||||
|
|
||||
|
Rate selectById(Integer id); |
||||
|
|
||||
|
void update(Rate rate); |
||||
|
|
||||
|
void add(Rate rate); |
||||
|
} |
@ -0,0 +1,27 @@ |
|||||
|
package com.example.demo.mapper; |
||||
|
|
||||
|
|
||||
|
import com.example.demo.domain.entity.UserGoldRecord; |
||||
|
import com.example.demo.domain.vo.RechargeUser; |
||||
|
import com.example.demo.domain.vo.RefundUser; |
||||
|
import org.apache.ibatis.annotations.Mapper; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* @program: gold-java |
||||
|
* @ClassName RechargeMapper |
||||
|
* @description: |
||||
|
* @author: Double |
||||
|
* @create: 2025−06-29 13:41 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
@Mapper |
||||
|
public interface RechargeMapper { |
||||
|
List<RechargeUser> selectAll(RechargeUser rechargeUser); |
||||
|
|
||||
|
List<RechargeUser> selectBy(RechargeUser rechargeUser); |
||||
|
|
||||
|
void add(UserGoldRecord userGoldRecord); |
||||
|
} |
@ -0,0 +1,32 @@ |
|||||
|
package com.example.demo.mapper; |
||||
|
|
||||
|
import com.example.demo.domain.entity.UserGoldRecord; |
||||
|
import com.example.demo.domain.vo.ConsumeUser; |
||||
|
import com.example.demo.domain.vo.RefundUser; |
||||
|
import org.apache.ibatis.annotations.Mapper; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* @program: gold-java |
||||
|
* @ClassName RefundMapper |
||||
|
* @description: |
||||
|
* @author: Double |
||||
|
* @create: 2025−06-27 11:31 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
@Mapper |
||||
|
public interface RefundMapper { |
||||
|
|
||||
|
List<RefundUser> selectAll(RefundUser refundUser); |
||||
|
|
||||
|
List<RefundUser> selectBy(RefundUser refundUser); |
||||
|
|
||||
|
void add(UserGoldRecord userGoldRecord); |
||||
|
|
||||
|
List<String> getRefundType(); |
||||
|
|
||||
|
List<RefundUser> selectGoods(Integer jwcode); |
||||
|
|
||||
|
} |
@ -0,0 +1,62 @@ |
|||||
|
package com.example.demo.mapper; |
||||
|
|
||||
|
import com.example.demo.domain.entity.Statistics; |
||||
|
import com.example.demo.domain.entity.UserGoldRecord; |
||||
|
import org.apache.ibatis.annotations.Mapper; |
||||
|
import org.apache.ibatis.annotations.Param; |
||||
|
|
||||
|
import java.time.LocalDate; |
||||
|
import java.util.Date; |
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* @program: gold-java |
||||
|
* @ClassName StatisticsMapper |
||||
|
* @description: |
||||
|
* @author: Ethan |
||||
|
* @create: 2025−06-23 14:08 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
@Mapper |
||||
|
public interface StatisticsMapper { |
||||
|
//根据地区、审核状态、起止时间查询订单表数据 |
||||
|
List<UserGoldRecord> findByMarketAndAuditStatus(@Param("market") String market, |
||||
|
@Param("auditStatusList") List<Integer> auditStatusList, |
||||
|
@Param("startTime") Date startTime, |
||||
|
@Param("endTime") Date endTime); |
||||
|
//获取某地区当前永久金币余量 |
||||
|
Integer sumCurrentPermanentGold(@Param("market") String market); |
||||
|
//获取某地区当前六月免费金币余量 |
||||
|
Integer sumCurrentFreeJune(@Param("market") String market); |
||||
|
//获取某地区当前永久金币余量 |
||||
|
Integer sumCurrentFreeDecember(@Param("market") String market); |
||||
|
//获取某地区当前永久金币余量 |
||||
|
Integer sumCurrentTaskGold(@Param("market") String market); |
||||
|
//计算该天充值人数 |
||||
|
Integer countRechargeNum( |
||||
|
@Param("market") String market, |
||||
|
@Param("startTime") Date startTime, |
||||
|
@Param("endTime") Date endTime); |
||||
|
//计算该天首充人数 |
||||
|
Integer countFirstRecharge( |
||||
|
@Param("market") String market, |
||||
|
@Param("startTime") Date startTime, |
||||
|
@Param("endTime") Date endTime); |
||||
|
//新增part1统计数据 |
||||
|
void insertPart1(Statistics statistics); |
||||
|
//更新part1统计数据 |
||||
|
void updatePart1(Statistics statistics); |
||||
|
//新增part2统计数据 |
||||
|
void insertPart2(Statistics statistics); |
||||
|
//更新part2统计数据 |
||||
|
void updatePart2(Statistics statistics); |
||||
|
//获取某地区某时间所在日期的数据(仅一条) |
||||
|
Statistics selectByMarketAndDate(@Param("market") String market, |
||||
|
@Param("startDate") Date startDate, |
||||
|
@Param("endDate") Date endDate); |
||||
|
//获取某地区某时间段的统计数据(仅一条) |
||||
|
Statistics selectSumByMarketAndDate(@Param("market") String market, |
||||
|
@Param("startDate") Date startDate, |
||||
|
@Param("endDate") Date endDate); |
||||
|
} |
@ -0,0 +1,25 @@ |
|||||
|
package com.example.demo.mapper; |
||||
|
|
||||
|
import com.example.demo.domain.entity.User; |
||||
|
import com.example.demo.domain.vo.Gold; |
||||
|
import com.example.demo.domain.vo.GoldUser; |
||||
|
import org.apache.ibatis.annotations.Mapper; |
||||
|
|
||||
|
/** |
||||
|
* @program: gold-java |
||||
|
* @ClassName UserMapper |
||||
|
* @description: |
||||
|
* @author: Double |
||||
|
* @create: 2025−06-25 10:40 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
@Mapper |
||||
|
public interface UserMapper { |
||||
|
|
||||
|
GoldUser selectUser(String jwcode); |
||||
|
|
||||
|
GoldUser selectGold(String jwcode); |
||||
|
|
||||
|
void updateGold(User user); |
||||
|
} |
@ -1,43 +0,0 @@ |
|||||
package com.example.demo.security; |
|
||||
|
|
||||
import jakarta.servlet.FilterChain; |
|
||||
import jakarta.servlet.ServletException; |
|
||||
import jakarta.servlet.http.HttpServletRequest; |
|
||||
import jakarta.servlet.http.HttpServletResponse; |
|
||||
import org.springframework.stereotype.Component; |
|
||||
import org.springframework.web.filter.OncePerRequestFilter; |
|
||||
import org.springframework.web.multipart.MultipartResolver; |
|
||||
|
|
||||
import java.io.IOException; |
|
||||
|
|
||||
|
|
||||
@Component |
|
||||
public class UploadFilter extends OncePerRequestFilter { |
|
||||
|
|
||||
private final MultipartResolver multipartResolver; |
|
||||
|
|
||||
public UploadFilter(MultipartResolver multipartResolver) { |
|
||||
this.multipartResolver = multipartResolver; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) |
|
||||
throws ServletException, IOException { |
|
||||
|
|
||||
// 检查请求是否为上传请求,这里假设上传请求的路径以 "/upload" 开头 |
|
||||
boolean isUploadRequest = request.getRequestURI().startsWith("/upload"); |
|
||||
System.out.println(isUploadRequest); |
|
||||
System.out.println("MultipartResolver: " + multipartResolver); |
|
||||
if (isUploadRequest ) { |
|
||||
System.out.println("执行upload-------------------------------"); |
|
||||
// 如果是上传请求且Content-Type为multipart/form-data,直接将请求传递给下一个过滤器或目标资源 |
|
||||
filterChain.doFilter(request, response); |
|
||||
} else { |
|
||||
// 如果不是上传请求,执行一些自定义逻辑 |
|
||||
// 例如,可以在这里添加令牌验证或其他安全检查 |
|
||||
|
|
||||
// 继续执行过滤器链 |
|
||||
filterChain.doFilter(request, response); |
|
||||
} |
|
||||
} |
|
||||
} |
|
@ -0,0 +1,15 @@ |
|||||
|
package com.example.demo.service; |
||||
|
|
||||
|
import com.example.demo.domain.entity.Admin; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName adminService |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−07-01 10:40 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
public interface AdminService { |
||||
|
Admin login(Admin admin)throws Exception; |
||||
|
} |
@ -0,0 +1,19 @@ |
|||||
|
package com.example.demo.service; |
||||
|
|
||||
|
import com.example.demo.domain.vo.AiEmotionExportRecordVO; |
||||
|
import com.example.demo.domain.vo.ExportVo; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName AiEmotionService |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−06-29 14:27 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
public interface AiEmotionService { |
||||
|
|
||||
|
int updateStatus(Long recordId, int i, String s, String s1, int i1); |
||||
|
AiEmotionExportRecordVO getRecordById(Long id) throws Exception; |
||||
|
|
||||
|
} |
@ -0,0 +1,28 @@ |
|||||
|
package com.example.demo.service; |
||||
|
|
||||
|
|
||||
|
import com.example.demo.domain.entity.UserGoldRecord; |
||||
|
import com.example.demo.domain.vo.ConsumeUser; |
||||
|
import com.example.demo.domain.vo.Gold; |
||||
|
import com.example.demo.domain.vo.Result; |
||||
|
import com.github.pagehelper.PageInfo; |
||||
|
|
||||
|
/** |
||||
|
* @program: gold-java |
||||
|
* @ClassName ConsumeService |
||||
|
* @description: 消费模块 |
||||
|
* @author: Double |
||||
|
* @create: 2025−06-23 13:58 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
public interface ConsumeService { |
||||
|
|
||||
|
PageInfo<ConsumeUser> selectAll(Integer pageNum, Integer pageSize, ConsumeUser consumeUser); |
||||
|
|
||||
|
Gold statsGold(ConsumeUser consumeUser); |
||||
|
|
||||
|
PageInfo<ConsumeUser> selectBy(Integer pageNum, Integer pageSize, ConsumeUser consumeUser); |
||||
|
|
||||
|
Result add(ConsumeUser consumeUser); |
||||
|
} |
@ -0,0 +1,22 @@ |
|||||
|
package com.example.demo.service; |
||||
|
|
||||
|
import com.example.demo.domain.entity.Export; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName exportService |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−06-28 15:39 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
public interface ExportExcelService { |
||||
|
Exception handleExcelExportData(String message) throws Exception; |
||||
|
Exception handleExcel(String message) throws Exception; |
||||
|
Exception rechargeExcel(String message) throws Exception; |
||||
|
Exception consumeExcel(String message) throws Exception; |
||||
|
Exception refundExcel(String message) throws Exception; |
||||
|
List<Export> getExcel(Export export); |
||||
|
} |
@ -0,0 +1,31 @@ |
|||||
|
package com.example.demo.service; |
||||
|
|
||||
|
import com.example.demo.domain.DTO.GoldDetailDTO; |
||||
|
import com.example.demo.domain.DTO.GoldUserDTO; |
||||
|
import com.example.demo.domain.entity.User; |
||||
|
import com.example.demo.domain.vo.GoldDetail; |
||||
|
|
||||
|
import com.example.demo.domain.vo.Result; |
||||
|
import com.example.demo.domain.vo.Total; |
||||
|
import com.github.pagehelper.PageInfo; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName GoldDetailService |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−06-23 11:59 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
public interface GoldDetailService { |
||||
|
PageInfo<GoldDetail> getGoldDetail(Integer pageNum, Integer pageSize, GoldDetail goldDetail); |
||||
|
Total getTotal(GoldDetail goldDetail); |
||||
|
|
||||
|
PageInfo<User> getGold(Integer pageNum, Integer pageSize, User user); |
||||
|
Total GoldTotal(User user); |
||||
|
//异步导出客户明细 |
||||
|
Result addExportRecord(GoldDetailDTO dto); |
||||
|
//异步导出金币余额 |
||||
|
Result addExportRecordGold(GoldUserDTO dto); |
||||
|
} |
@ -0,0 +1,30 @@ |
|||||
|
package com.example.demo.service; |
||||
|
|
||||
|
import com.example.demo.domain.entity.Admin; |
||||
|
import com.example.demo.domain.entity.AdminRole; |
||||
|
import com.example.demo.domain.entity.Role; |
||||
|
import com.example.demo.domain.vo.Page; |
||||
|
import com.example.demo.domain.vo.Permission; |
||||
|
import com.github.pagehelper.PageInfo; |
||||
|
|
||||
|
import javax.swing.*; |
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName PermissionService |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−06-26 13:18 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
public interface PermissionService { |
||||
|
List<String> getposition(String token); |
||||
|
List<String> getmarket(String token); |
||||
|
PageInfo<Permission> getpermission(Integer pageNum, Integer pageSize, Permission permission); |
||||
|
Integer addpermission(Admin admin) throws Exception; |
||||
|
List<Role> getRole(String token); |
||||
|
Integer deleteAdmin(Integer id); |
||||
|
Integer updateAdminRole(AdminRole adminRole); |
||||
|
Integer upadatePermission(Admin admin) throws Exception; |
||||
|
} |
@ -0,0 +1,16 @@ |
|||||
|
package com.example.demo.service; |
||||
|
|
||||
|
import com.example.demo.domain.entity.Rate; |
||||
|
import com.example.demo.domain.vo.RateDetail; |
||||
|
import com.github.pagehelper.PageInfo; |
||||
|
|
||||
|
public interface RateService { |
||||
|
|
||||
|
PageInfo<Rate> selectAll(Integer pageNum, Integer pageSize); |
||||
|
|
||||
|
Rate selectById(Integer id); |
||||
|
|
||||
|
void add(Rate rate); |
||||
|
|
||||
|
void update(Rate rate); |
||||
|
} |
@ -0,0 +1,26 @@ |
|||||
|
package com.example.demo.service; |
||||
|
|
||||
|
import com.example.demo.domain.vo.ConsumeUser; |
||||
|
import com.example.demo.domain.vo.Gold; |
||||
|
import com.example.demo.domain.vo.RechargeUser; |
||||
|
import com.example.demo.domain.vo.Result; |
||||
|
import com.github.pagehelper.PageInfo; |
||||
|
|
||||
|
/** |
||||
|
* @program: gold-java |
||||
|
* @ClassName RechargeService |
||||
|
* @description: |
||||
|
* @author: Double |
||||
|
* @create: 2025−06-29 13:39 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
public interface RechargeService { |
||||
|
PageInfo<RechargeUser> selectAll(Integer pageNum, Integer pageSize, RechargeUser rechargeUser); |
||||
|
|
||||
|
Gold statsGold(RechargeUser rechargeUser); |
||||
|
|
||||
|
PageInfo<RechargeUser> selectBy(Integer pageNum, Integer pageSize, RechargeUser rechargeUser); |
||||
|
|
||||
|
Result add(RechargeUser rechargeUser); |
||||
|
} |
@ -0,0 +1,35 @@ |
|||||
|
package com.example.demo.service; |
||||
|
|
||||
|
|
||||
|
import com.example.demo.domain.vo.ConsumeUser; |
||||
|
import com.example.demo.domain.vo.Gold; |
||||
|
import com.example.demo.domain.vo.RefundUser; |
||||
|
import com.example.demo.domain.vo.Result; |
||||
|
import com.github.pagehelper.PageInfo; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* @program: gold-java |
||||
|
* @ClassName RefundService |
||||
|
* @description: |
||||
|
* @author: Double |
||||
|
* @create: 2025−06-27 11:50 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
public interface RefundService { |
||||
|
|
||||
|
PageInfo<RefundUser> selectAll(Integer pageNum, Integer pageSize, RefundUser refundUser); |
||||
|
|
||||
|
Gold statsGold(RefundUser refundUser); |
||||
|
|
||||
|
PageInfo<RefundUser> selectBy(Integer pageNum, Integer pageSize, RefundUser refundUser); |
||||
|
|
||||
|
Result add(RefundUser refundUser); |
||||
|
|
||||
|
//获取退款类型 |
||||
|
List<String> getRefundType(); |
||||
|
|
||||
|
List<RefundUser> selectGoods(Integer jwcode); |
||||
|
} |
@ -0,0 +1,19 @@ |
|||||
|
package com.example.demo.service; |
||||
|
|
||||
|
import com.example.demo.domain.vo.Gold; |
||||
|
import com.example.demo.domain.vo.GoldUser; |
||||
|
|
||||
|
/** |
||||
|
* @program: gold-java |
||||
|
* @ClassName UserService |
||||
|
* @description: |
||||
|
* @author: Double |
||||
|
* @create: 2025−06-25 10:30 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
public interface UserService { |
||||
|
|
||||
|
GoldUser selectUser(String jwcode); |
||||
|
GoldUser selectgold(String jwcode); |
||||
|
} |
@ -0,0 +1,84 @@ |
|||||
|
package com.example.demo.service.listen; |
||||
|
|
||||
|
import cn.hutool.core.util.StrUtil; |
||||
|
|
||||
|
|
||||
|
import com.example.demo.Util.ExecutionContextUtil; |
||||
|
import com.example.demo.Util.FeiShuAlertUtil; |
||||
|
import com.example.demo.Util.RedisUtil; |
||||
|
import com.example.demo.domain.vo.ExecutionContext; |
||||
|
import com.example.demo.service.ExportExcelService; |
||||
|
import com.example.demo.service.queue.AbstractMessageListener; |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
import static java.lang.Thread.sleep; |
||||
|
|
||||
|
|
||||
|
@Component |
||||
|
public class AiEmotionExportListener extends AbstractMessageListener<String> { |
||||
|
|
||||
|
|
||||
|
//注入ExportExcelService |
||||
|
@Autowired |
||||
|
private ExportExcelService exportExcelService; |
||||
|
|
||||
|
@Autowired |
||||
|
public AiEmotionExportListener( |
||||
|
RedisUtil redisQueueUtil |
||||
|
|
||||
|
) { |
||||
|
super(redisQueueUtil, "hwgold:queue:export_queue"); |
||||
|
System.out.println("监听器已启动,队列: "); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void handleMessage(String message) { |
||||
|
if (StrUtil.isBlank(message)) { |
||||
|
System.err.println("redis消息队列数据为空" + message); |
||||
|
} |
||||
|
try { |
||||
|
Thread.sleep(5000); |
||||
|
exportExcelService.handleExcelExportData(message); |
||||
|
} catch (Exception e) { |
||||
|
logError(e, message); |
||||
|
throw new RuntimeException("Failed to process HWGOLD export: " + e.getMessage(), e); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
private void logError(Exception e, String message) { |
||||
|
System.err.println("Export data listener exception: " + e.getMessage()); |
||||
|
e.printStackTrace(); |
||||
|
try { |
||||
|
ExecutionContext context = ExecutionContextUtil.getExecutionContext(); |
||||
|
String cause = ""; |
||||
|
if (e.getCause() != null) { |
||||
|
cause = e.getCause().getMessage(); |
||||
|
} |
||||
|
FeiShuAlertUtil.sendAlertMessage( |
||||
|
context, |
||||
|
e.getStackTrace()[0].getFileName(), |
||||
|
e.getStackTrace()[0].getLineNumber(), |
||||
|
"HWGOLD Export Error: " + e.getMessage() + " 底层错误: " + cause , |
||||
|
"Failed message: " + message |
||||
|
); |
||||
|
} catch (Exception alertEx) { |
||||
|
System.err.println("Failed to send Feishu alert: " + alertEx.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void handleError(Exception e, String message) { |
||||
|
System.err.println("处理消息失败: " + message); |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,81 @@ |
|||||
|
package com.example.demo.service.listen; |
||||
|
|
||||
|
import cn.hutool.core.util.StrUtil; |
||||
|
import com.example.demo.Export.ExportService; |
||||
|
import com.example.demo.Util.ExecutionContextUtil; |
||||
|
import com.example.demo.Util.FeiShuAlertUtil; |
||||
|
import com.example.demo.Util.RedisUtil; |
||||
|
import com.example.demo.domain.vo.ExecutionContext; |
||||
|
import com.example.demo.service.ExportExcelService; |
||||
|
import com.example.demo.service.queue.AbstractMessageListener; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName RechargeListener |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−07-01 15:46 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
@Component |
||||
|
public class ConsumeListener extends AbstractMessageListener<String> { |
||||
|
//注入ExportExcelService |
||||
|
@Autowired |
||||
|
private ExportExcelService exportService; |
||||
|
|
||||
|
@Autowired |
||||
|
public ConsumeListener( |
||||
|
RedisUtil redisQueueUtil |
||||
|
|
||||
|
) { |
||||
|
super(redisQueueUtil, "consume:queue:export_queue"); |
||||
|
System.out.println("监听器已启动,队列: "); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void handleMessage(String message) { |
||||
|
if (StrUtil.isBlank(message)) { |
||||
|
System.err.println("redis消息队列数据为空" + message); |
||||
|
} |
||||
|
try { |
||||
|
Thread.sleep(5000); |
||||
|
exportService.consumeExcel(message); |
||||
|
} catch (Exception e) { |
||||
|
logError(e, message); |
||||
|
throw new RuntimeException("Failed to process HWGOLD export: " + e.getMessage(), e); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
private void logError(Exception e, String message) { |
||||
|
System.err.println("Export data listener exception: " + e.getMessage()); |
||||
|
e.printStackTrace(); |
||||
|
try { |
||||
|
ExecutionContext context = ExecutionContextUtil.getExecutionContext(); |
||||
|
String cause = ""; |
||||
|
if (e.getCause() != null) { |
||||
|
cause = e.getCause().getMessage(); |
||||
|
} |
||||
|
FeiShuAlertUtil.sendAlertMessage( |
||||
|
context, |
||||
|
e.getStackTrace()[0].getFileName(), |
||||
|
e.getStackTrace()[0].getLineNumber(), |
||||
|
"HWGOLD Export Error: " + e.getMessage() + " 底层错误: " + cause , |
||||
|
"Failed message: " + message |
||||
|
); |
||||
|
} catch (Exception alertEx) { |
||||
|
System.err.println("Failed to send Feishu alert: " + alertEx.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void handleError(Exception e, String message) { |
||||
|
System.err.println("处理消息失败: " + message); |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
@ -0,0 +1,82 @@ |
|||||
|
package com.example.demo.service.listen; |
||||
|
|
||||
|
import cn.hutool.core.util.StrUtil; |
||||
|
|
||||
|
import com.example.demo.Util.ExecutionContextUtil; |
||||
|
import com.example.demo.Util.FeiShuAlertUtil; |
||||
|
import com.example.demo.Util.RedisUtil; |
||||
|
import com.example.demo.domain.vo.ExecutionContext; |
||||
|
import com.example.demo.service.ExportExcelService; |
||||
|
import com.example.demo.service.GoldDetailService; |
||||
|
import com.example.demo.service.queue.AbstractMessageListener; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName GoldListener |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−07-01 15:43 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
@Component |
||||
|
public class GoldListener extends AbstractMessageListener<String> { |
||||
|
//注入ExportExcelService |
||||
|
@Autowired |
||||
|
private ExportExcelService exportExcelService; |
||||
|
|
||||
|
@Autowired |
||||
|
public GoldListener( |
||||
|
RedisUtil redisQueueUtil |
||||
|
|
||||
|
) { |
||||
|
super(redisQueueUtil, "gold:queue:export_queue"); |
||||
|
System.out.println("监听器已启动,队列: "); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void handleMessage(String message) { |
||||
|
if (StrUtil.isBlank(message)) { |
||||
|
System.err.println("redis消息队列数据为空" + message); |
||||
|
} |
||||
|
try { |
||||
|
Thread.sleep(5000); |
||||
|
exportExcelService.handleExcel(message); |
||||
|
} catch (Exception e) { |
||||
|
logError(e, message); |
||||
|
throw new RuntimeException("Failed to process HWGOLD export: " + e.getMessage(), e); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
private void logError(Exception e, String message) { |
||||
|
System.err.println("Export data listener exception: " + e.getMessage()); |
||||
|
e.printStackTrace(); |
||||
|
try { |
||||
|
ExecutionContext context = ExecutionContextUtil.getExecutionContext(); |
||||
|
String cause = ""; |
||||
|
if (e.getCause() != null) { |
||||
|
cause = e.getCause().getMessage(); |
||||
|
} |
||||
|
FeiShuAlertUtil.sendAlertMessage( |
||||
|
context, |
||||
|
e.getStackTrace()[0].getFileName(), |
||||
|
e.getStackTrace()[0].getLineNumber(), |
||||
|
"HWGOLD Export Error: " + e.getMessage() + " 底层错误: " + cause , |
||||
|
"Failed message: " + message |
||||
|
); |
||||
|
} catch (Exception alertEx) { |
||||
|
System.err.println("Failed to send Feishu alert: " + alertEx.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void handleError(Exception e, String message) { |
||||
|
System.err.println("处理消息失败: " + message); |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
@ -0,0 +1,81 @@ |
|||||
|
package com.example.demo.service.listen; |
||||
|
|
||||
|
import cn.hutool.core.util.StrUtil; |
||||
|
import com.example.demo.Export.ExportService; |
||||
|
import com.example.demo.Util.ExecutionContextUtil; |
||||
|
import com.example.demo.Util.FeiShuAlertUtil; |
||||
|
import com.example.demo.Util.RedisUtil; |
||||
|
import com.example.demo.domain.vo.ExecutionContext; |
||||
|
import com.example.demo.service.ExportExcelService; |
||||
|
import com.example.demo.service.queue.AbstractMessageListener; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName RechargeListener |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−07-01 15:46 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
@Component |
||||
|
public class RechargeListener extends AbstractMessageListener<String> { |
||||
|
//注入ExportExcelService |
||||
|
@Autowired |
||||
|
private ExportExcelService exportService; |
||||
|
|
||||
|
@Autowired |
||||
|
public RechargeListener( |
||||
|
RedisUtil redisQueueUtil |
||||
|
|
||||
|
) { |
||||
|
super(redisQueueUtil, "recharge:queue:export_queue"); |
||||
|
System.out.println("监听器已启动,队列: "); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void handleMessage(String message) { |
||||
|
if (StrUtil.isBlank(message)) { |
||||
|
System.err.println("redis消息队列数据为空" + message); |
||||
|
} |
||||
|
try { |
||||
|
Thread.sleep(5000); |
||||
|
exportService.rechargeExcel(message); |
||||
|
} catch (Exception e) { |
||||
|
logError(e, message); |
||||
|
throw new RuntimeException("Failed to process HWGOLD export: " + e.getMessage(), e); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
private void logError(Exception e, String message) { |
||||
|
System.err.println("Export data listener exception: " + e.getMessage()); |
||||
|
e.printStackTrace(); |
||||
|
try { |
||||
|
ExecutionContext context = ExecutionContextUtil.getExecutionContext(); |
||||
|
String cause = ""; |
||||
|
if (e.getCause() != null) { |
||||
|
cause = e.getCause().getMessage(); |
||||
|
} |
||||
|
FeiShuAlertUtil.sendAlertMessage( |
||||
|
context, |
||||
|
e.getStackTrace()[0].getFileName(), |
||||
|
e.getStackTrace()[0].getLineNumber(), |
||||
|
"HWGOLD Export Error: " + e.getMessage() + " 底层错误: " + cause , |
||||
|
"Failed message: " + message |
||||
|
); |
||||
|
} catch (Exception alertEx) { |
||||
|
System.err.println("Failed to send Feishu alert: " + alertEx.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void handleError(Exception e, String message) { |
||||
|
System.err.println("处理消息失败: " + message); |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
@ -0,0 +1,81 @@ |
|||||
|
package com.example.demo.service.listen; |
||||
|
|
||||
|
import cn.hutool.core.util.StrUtil; |
||||
|
import com.example.demo.Export.ExportService; |
||||
|
import com.example.demo.Util.ExecutionContextUtil; |
||||
|
import com.example.demo.Util.FeiShuAlertUtil; |
||||
|
import com.example.demo.Util.RedisUtil; |
||||
|
import com.example.demo.domain.vo.ExecutionContext; |
||||
|
import com.example.demo.service.ExportExcelService; |
||||
|
import com.example.demo.service.queue.AbstractMessageListener; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName RechargeListener |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−07-01 15:46 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
@Component |
||||
|
public class RefundListener extends AbstractMessageListener<String> { |
||||
|
//注入ExportExcelService |
||||
|
@Autowired |
||||
|
private ExportExcelService exportExcelService; |
||||
|
|
||||
|
@Autowired |
||||
|
public RefundListener( |
||||
|
RedisUtil redisQueueUtil |
||||
|
|
||||
|
) { |
||||
|
super(redisQueueUtil, "refund:queue:export_queue"); |
||||
|
System.out.println("监听器已启动,队列: "); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void handleMessage(String message) { |
||||
|
if (StrUtil.isBlank(message)) { |
||||
|
System.err.println("redis消息队列数据为空" + message); |
||||
|
} |
||||
|
try { |
||||
|
Thread.sleep(5000); |
||||
|
exportExcelService.refundExcel(message); |
||||
|
} catch (Exception e) { |
||||
|
logError(e, message); |
||||
|
throw new RuntimeException("Failed to process HWGOLD export: " + e.getMessage(), e); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
private void logError(Exception e, String message) { |
||||
|
System.err.println("Export data listener exception: " + e.getMessage()); |
||||
|
e.printStackTrace(); |
||||
|
try { |
||||
|
ExecutionContext context = ExecutionContextUtil.getExecutionContext(); |
||||
|
String cause = ""; |
||||
|
if (e.getCause() != null) { |
||||
|
cause = e.getCause().getMessage(); |
||||
|
} |
||||
|
FeiShuAlertUtil.sendAlertMessage( |
||||
|
context, |
||||
|
e.getStackTrace()[0].getFileName(), |
||||
|
e.getStackTrace()[0].getLineNumber(), |
||||
|
"HWGOLD Export Error: " + e.getMessage() + " 底层错误: " + cause , |
||||
|
"Failed message: " + message |
||||
|
); |
||||
|
} catch (Exception alertEx) { |
||||
|
System.err.println("Failed to send Feishu alert: " + alertEx.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void handleError(Exception e, String message) { |
||||
|
System.err.println("处理消息失败: " + message); |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
@ -0,0 +1,69 @@ |
|||||
|
package com.example.demo.service.queue; |
||||
|
|
||||
|
|
||||
|
|
||||
|
import com.example.demo.Util.RedisUtil; |
||||
|
import jakarta.annotation.PostConstruct; |
||||
|
|
||||
|
|
||||
|
import java.util.concurrent.ExecutorService; |
||||
|
import java.util.concurrent.Executors; |
||||
|
|
||||
|
/** |
||||
|
* 抽象消息监听器 |
||||
|
*/ |
||||
|
public abstract class AbstractMessageListener<T> { |
||||
|
|
||||
|
private final ExecutorService executorService = Executors.newSingleThreadExecutor(); |
||||
|
protected final RedisUtil redisQueueUtil; |
||||
|
protected final String queueName; |
||||
|
|
||||
|
public AbstractMessageListener(RedisUtil redisQueueUtil, String queueName) { |
||||
|
this.redisQueueUtil = redisQueueUtil; |
||||
|
this.queueName = queueName; |
||||
|
} |
||||
|
|
||||
|
@PostConstruct |
||||
|
public void init() { |
||||
|
executorService.submit(this::listen); |
||||
|
} |
||||
|
|
||||
|
private void listen() { |
||||
|
System.out.println("消费者消费数据" + queueName + "<UNK>"); |
||||
|
while (!Thread.currentThread().isInterrupted()) { |
||||
|
try { |
||||
|
Object message = redisQueueUtil.blockingGetMessage(queueName, 1); |
||||
|
if (message != null) { |
||||
|
try { |
||||
|
handleMessage((T) message); |
||||
|
} catch (Exception e) { |
||||
|
handleError(e, (T) message); |
||||
|
} |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("监听队列异常: " + e.getMessage()); |
||||
|
try { |
||||
|
Thread.sleep(5000); |
||||
|
} catch (InterruptedException ex) { |
||||
|
Thread.currentThread().interrupt(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 处理消息 |
||||
|
* @param message 消息内容 |
||||
|
*/ |
||||
|
protected abstract void handleMessage(T message); |
||||
|
|
||||
|
/** |
||||
|
* 处理错误 |
||||
|
* @param e 异常 |
||||
|
* @param message 消息内容 |
||||
|
*/ |
||||
|
protected void handleError(Exception e, T message) { |
||||
|
System.err.println("处理消息异常: " + e.getMessage()); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,70 @@ |
|||||
|
package com.example.demo.serviceImpl; |
||||
|
|
||||
|
import com.example.demo.domain.entity.Admin; |
||||
|
import com.example.demo.mapper.AdminMapper; |
||||
|
import com.example.demo.service.AdminService; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.security.authentication.AuthenticationManager; |
||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; |
||||
|
import org.springframework.security.core.Authentication; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.apache.commons.lang3.StringUtils; |
||||
|
import org.slf4j.Logger; |
||||
|
import org.slf4j.LoggerFactory; |
||||
|
|
||||
|
@Service |
||||
|
@RequiredArgsConstructor |
||||
|
public class AdminServiceImpl implements AdminService { |
||||
|
|
||||
|
@Autowired |
||||
|
private AuthenticationManager authenticationManager; |
||||
|
private final AdminMapper adminMapper; |
||||
|
|
||||
|
@Override |
||||
|
public Admin login(Admin admin) throws Exception { |
||||
|
String account = admin.getAccount(); |
||||
|
String inputMachineId = admin.getMachineId(); |
||||
|
|
||||
|
if (StringUtils.isBlank(account)) { |
||||
|
throw new IllegalArgumentException("账号不能为空"); |
||||
|
} |
||||
|
|
||||
|
Admin adminInDB = adminMapper.getAdmin(account); |
||||
|
System.out.println("adminInDB:" + adminInDB); |
||||
|
if (adminInDB == null) { |
||||
|
throw new RuntimeException("无此精网号"); |
||||
|
} |
||||
|
|
||||
|
// 校验机器权限 |
||||
|
if (!hasPermissionToMachine(adminInDB, inputMachineId)) { |
||||
|
throw new RuntimeException("你没有使用该机器的权限!"); |
||||
|
} |
||||
|
|
||||
|
try { |
||||
|
System.out.println("admin:" + account); |
||||
|
System.out.println("admin:" + admin.getPassword()); |
||||
|
UsernamePasswordAuthenticationToken token = |
||||
|
new UsernamePasswordAuthenticationToken(account,admin.getPassword()); |
||||
|
Authentication authentication = authenticationManager.authenticate(token); |
||||
|
return (Admin) authentication.getPrincipal(); |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
System.out.println("密码错误"+e.getMessage()); |
||||
|
throw new RuntimeException("登录失败,请稍后再试", e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private boolean hasPermissionToMachine(Admin admin, String targetMachineId) { |
||||
|
if (targetMachineId == null || admin.getMachineId() == null) { |
||||
|
return false; |
||||
|
} |
||||
|
String[] machineIds = admin.getMachineId().split(","); |
||||
|
for (String id : machineIds) { |
||||
|
if (targetMachineId.equals(id)) { |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
} |
@ -0,0 +1,35 @@ |
|||||
|
package com.example.demo.serviceImpl; |
||||
|
|
||||
|
import com.example.demo.domain.vo.AiEmotionExportRecordVO; |
||||
|
import com.example.demo.domain.vo.ExportVo; |
||||
|
import com.example.demo.mapper.AiEmotionMapper; |
||||
|
import com.example.demo.mapper.ExportMapper; |
||||
|
import com.example.demo.service.AiEmotionService; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
|
||||
|
/** |
||||
|
* @program: GOLD |
||||
|
* @ClassName AiEmotionServiceImpl |
||||
|
* @description: |
||||
|
* @author: huangqizhen |
||||
|
* @create: 2025−06-29 14:46 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
@Service |
||||
|
public class AiEmotionServiceImpl implements AiEmotionService { |
||||
|
@Autowired |
||||
|
private ExportMapper exportMapper; |
||||
|
@Autowired |
||||
|
private AiEmotionMapper aiEmotionMapper; |
||||
|
|
||||
|
@Override |
||||
|
public int updateStatus(Long recordId, int i, String s, String s1, int i1) { |
||||
|
return exportMapper.updateExportData(recordId, i, s, s1, i1); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public AiEmotionExportRecordVO getRecordById(Long id) throws Exception { |
||||
|
return aiEmotionMapper.getRecordById(id); |
||||
|
} |
||||
|
} |
@ -0,0 +1,169 @@ |
|||||
|
package com.example.demo.serviceImpl; |
||||
|
|
||||
|
import com.example.demo.Util.GoldTistV2; |
||||
|
import com.example.demo.domain.entity.User; |
||||
|
import com.example.demo.domain.entity.UserGoldRecord; |
||||
|
import com.example.demo.domain.vo.ConsumeUser; |
||||
|
import com.example.demo.domain.vo.Gold; |
||||
|
import com.example.demo.domain.vo.GoldUser; |
||||
|
import com.example.demo.domain.vo.Result; |
||||
|
import com.example.demo.mapper.ConsumeMapper; |
||||
|
import com.example.demo.mapper.UserMapper; |
||||
|
import com.example.demo.service.ConsumeService; |
||||
|
import com.github.pagehelper.PageHelper; |
||||
|
import com.github.pagehelper.PageInfo; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
|
||||
|
import java.math.BigDecimal; |
||||
|
import java.time.LocalDate; |
||||
|
import java.time.LocalDateTime; |
||||
|
import java.time.format.DateTimeFormatter; |
||||
|
import java.util.Date; |
||||
|
import java.util.List; |
||||
|
import java.util.Random; |
||||
|
import java.util.concurrent.atomic.AtomicInteger; |
||||
|
|
||||
|
/** |
||||
|
* @program: gold-java |
||||
|
* @ClassName ConsumeServiceImpl |
||||
|
* @description: 消费模块 |
||||
|
* @author: Double |
||||
|
* @create: 2025−06-23 13:58 |
||||
|
* @Version 1.0 |
||||
|
**/ |
||||
|
|
||||
|
@Service |
||||
|
public class ConsumeServiceImpl implements ConsumeService { |
||||
|
|
||||
|
@Autowired |
||||
|
private ConsumeMapper consumeMapper; |
||||
|
|
||||
|
@Autowired |
||||
|
private UserMapper userMapper; |
||||
|
|
||||
|
//消耗明细 |
||||
|
@Override |
||||
|
public PageInfo<ConsumeUser> selectAll(Integer pageNum, Integer pageSize, ConsumeUser consumeUser) { |
||||
|
PageHelper.startPage(pageNum, pageSize); |
||||
|
List<ConsumeUser> consumeUsers = consumeMapper.selectAll(consumeUser); |
||||
|
return new PageInfo<>(consumeUsers); |
||||
|
} |
||||
|
|
||||
|
//消耗金币统计 |
||||
|
@Override |
||||
|
public Gold statsGold(ConsumeUser consumeUser) { |
||||
|
Gold gold = new Gold(); |
||||
|
List<ConsumeUser> consumeUsers = consumeMapper.selectBy(consumeUser); |
||||
|
|
||||
|
// 初始化累加器 |
||||
|
int permanentGoldSum = 0; |
||||
|
int freeGoldSum = 0; |
||||
|
int taskGoldSum = 0; |
||||
|
|
||||
|
// 遍历消费记录并累加金币 |
||||
|
for (ConsumeUser user : consumeUsers) { |
||||
|
// 累加永久金币 |
||||
|
if (user.getPermanentGold() != null) { |
||||
|
permanentGoldSum += user.getPermanentGold(); |
||||
|
} |
||||
|
// 累加免费金币 |
||||
|
if (user.getFreeGold() != null) { |
||||
|
freeGoldSum += user.getFreeGold(); |
||||
|
} |
||||
|
// 累加任务金币 |
||||
|
if (user.getTaskGold() != null) { |
||||
|
taskGoldSum += user.getTaskGold(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 将累加结果设置到Gold对象 |
||||
|
gold.setPermanentGolds(permanentGoldSum); |
||||
|
gold.setFreeGolds(freeGoldSum); |
||||
|
gold.setTaskGolds(taskGoldSum); |
||||
|
|
||||
|
return gold; |
||||
|
} |
||||
|
|
||||
|
//消耗明细筛选 |
||||
|
@Override |
||||
|
public PageInfo<ConsumeUser> selectBy(Integer pageNum, Integer pageSize, ConsumeUser consumeUser) { |
||||
|
PageHelper.startPage(pageNum, pageSize); |
||||
|
List<ConsumeUser> consumeUsers = consumeMapper.selectBy(consumeUser); |
||||
|
return new PageInfo<>(consumeUsers); |
||||
|
} |
||||
|
|
||||
|
//新增消耗 |
||||
|
@Override |
||||
|
public Result add(ConsumeUser consumeUser) { |
||||
|
UserGoldRecord userGoldRecord = new UserGoldRecord(); |
||||
|
|
||||
|
// 获取当前时间戳部分 |
||||
|
String timestampPart = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS")); |
||||
|
|
||||
|
// 获取自增计数器部分(三位数,不足补零) |
||||
|
AtomicInteger atomicInteger = new AtomicInteger(0); |
||||
|
|
||||
|
int count = atomicInteger.getAndUpdate(c -> (c >= 999) ? 0 : c + 1); |
||||
|
String counterPart = String.format("%03d", count); |
||||
|
|
||||
|
|
||||
|
//订单号生成 |
||||
|
userGoldRecord.setOrderCode("XF" + timestampPart + counterPart); |
||||
|
userGoldRecord.setJwcode(consumeUser.getJwcode()); |
||||
|
userGoldRecord.setGoodsName(consumeUser.getGoodsName()); |
||||
|
userGoldRecord.setSumGold(consumeUser.getSumGold()); |
||||
|
userGoldRecord.setPermanentGold(consumeUser.getPermanentGold()); |
||||
|
// 获取当前月份(1-12) |
||||
|
int currentMonth = LocalDate.now().getMonthValue(); |
||||
|
GoldUser gold = userMapper.selectGold(consumeUser.getJwcode().toString()); |
||||
|
if (consumeUser.getFreeGold() > (gold.getNowFreeDecember() + gold.getNowFreeJune()) || consumeUser.getPermanentGold() > gold.getNowPermanentGold() |
||||
|
|| consumeUser.getTaskGold() > gold.getNowTaskGold()) { |
||||
|
return Result.error("金币数量不足"); |
||||
|
} |
||||
|
// 根据当前月份设置对应字段 |
||||
|
if (currentMonth >= 1 && currentMonth <= 6) { |
||||
|
// 1-6月:设置6月额度,12月保持默认值 |
||||
|
if (consumeUser.getFreeGold() > gold.getNowFreeJune()) { |
||||
|
userGoldRecord.setFreeJune(gold.getNowFreeJune()); |
||||
|
userGoldRecord.setFreeDecember(consumeUser.getFreeGold() - gold.getNowFreeJune()); |
||||
|
} else { |
||||
|
userGoldRecord.setFreeJune(consumeUser.getFreeGold()); |
||||
|
userGoldRecord.setFreeDecember(0); |
||||
|
} |
||||
|
} else { |
||||
|
// 7-12月:设置12月额度,6月保持默认值 |
||||
|
if (consumeUser.getFreeGold() > gold.getNowFreeDecember()) { |
||||
|
userGoldRecord.setFreeDecember(gold.getNowFreeDecember()); |
||||
|
userGoldRecord.setFreeJune(consumeUser.getFreeGold() - gold.getNowFreeDecember()); |
||||
|
} else { |
||||
|
userGoldRecord.setFreeDecember(consumeUser.getFreeGold()); |
||||
|
userGoldRecord.setFreeJune(0); |
||||
|
} |
||||
|
} |
||||
|
userGoldRecord.setTaskGold(consumeUser.getTaskGold()); |
||||
|
userGoldRecord.setRemark(consumeUser.getRemark()); |
||||
|
userGoldRecord.setType((byte) 1); |
||||
|
userGoldRecord.setIsRefund((byte) 0); |
||||
|
userGoldRecord.setPayPlatform("金币系统"); |
||||
|
userGoldRecord.setAdminId(consumeUser.getAdminId()); |
||||
|
userGoldRecord.setAuditStatus(1); |
||||
|
userGoldRecord.setCreateTime(new Date()); |
||||
|
userGoldRecord.setPayTime(new Date()); |
||||
|
consumeMapper.add(userGoldRecord); |
||||
|
User user = new User(); |
||||
|
user.setJwcode(userGoldRecord.getJwcode()); |
||||
|
user.setCurrentPermanentGold(gold.getNowPermanentGold() - consumeUser.getPermanentGold()); |
||||
|
user.setCurrentFreeJune(gold.getNowFreeJune() - userGoldRecord.getFreeJune()); |
||||
|
user.setCurrentFreeDecember(gold.getNowFreeDecember() - userGoldRecord.getFreeDecember()); |
||||
|
user.setCurrentTaskGold(gold.getNowTaskGold() - consumeUser.getTaskGold()); |
||||
|
user.setConsumeNum(gold.getConsumeNum() + 1); |
||||
|
user.setSumConsume(consumeUser.getPermanentGold() + consumeUser.getFreeGold() + consumeUser.getTaskGold()); |
||||
|
userMapper.updateGold(user); |
||||
|
//对接接口 |
||||
|
// GoldTistV2.addCoinNew(userGoldRecord.getJwcode().toString(), 65, |
||||
|
// (double) (userGoldRecord.getPermanentGold() + userGoldRecord.getFreeDecember() + userGoldRecord.getFreeJune() + userGoldRecord.getTaskGold()) /100, |
||||
|
// userGoldRecord.getRemark(),((double) userGoldRecord.getPermanentGold() /100), userGoldRecord.getPayPlatform(), userGoldRecord.getGoodsName()); |
||||
|
return Result.success(); |
||||
|
} |
||||
|
} |
1102
src/main/java/com/example/demo/serviceImpl/ExportExcelServiceImpl.java
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
Some files were not shown because too many files changed in this diff
Write
Preview
Loading…
Cancel
Save
Reference in new issue