Browse Source

权限

暂用(不合并)
huangqizhen 2 days ago
parent
commit
6bb3f5a45d
  1. 35
      pom.xml
  2. 200
      src/main/java/com/example/demo/Util/ExcelUploadUtil.java
  3. 227
      src/main/java/com/example/demo/Util/ExecutionContextUtil.java
  4. 173
      src/main/java/com/example/demo/Util/FeiShuAlertUtil.java
  5. 37
      src/main/java/com/example/demo/Util/RedisLockUtil.java
  6. 31
      src/main/java/com/example/demo/Util/RedisUtil.java
  7. 18
      src/main/java/com/example/demo/config/EnvConfig.java
  8. 4
      src/main/java/com/example/demo/config/RedisConfig.java
  9. 28
      src/main/java/com/example/demo/controller/ExportController.java
  10. 31
      src/main/java/com/example/demo/controller/GoldDetailController.java
  11. 4
      src/main/java/com/example/demo/controller/PermissionController.java
  12. 44
      src/main/java/com/example/demo/domain/DTO/GoldDetailDTO.java
  13. 28
      src/main/java/com/example/demo/domain/export/Goldmingxi.java
  14. 28
      src/main/java/com/example/demo/domain/vo/AiEmotionExportRecordVO.java
  15. 25
      src/main/java/com/example/demo/domain/vo/ExecutionContext.java
  16. 26
      src/main/java/com/example/demo/domain/vo/ExportVo.java
  17. 25
      src/main/java/com/example/demo/mapper/AiEmotionMapper.java
  18. 19
      src/main/java/com/example/demo/mapper/ExportMapper.java
  19. 15
      src/main/java/com/example/demo/mapper/GoldDetailMapper.java
  20. 19
      src/main/java/com/example/demo/service/AiEmotionService.java
  21. 16
      src/main/java/com/example/demo/service/ExportExcelService.java
  22. 7
      src/main/java/com/example/demo/service/GoldDetailService.java
  23. 1
      src/main/java/com/example/demo/service/PermissionService.java
  24. 35
      src/main/java/com/example/demo/serviceImpl/AiEmotionServiceImpl.java
  25. 253
      src/main/java/com/example/demo/serviceImpl/ExportExcelServiceImpl.java
  26. 69
      src/main/java/com/example/demo/serviceImpl/GoldDetailServiceImpl.java
  27. 5
      src/main/java/com/example/demo/serviceImpl/PermissionServiceImpl.java
  28. 14
      src/main/resources/application.yml
  29. 17
      src/main/resources/mapper/AiEmotionMapper.xml
  30. 18
      src/main/resources/mapper/ExportMapper.xml
  31. 15
      src/main/resources/mapper/GoldDetailMapper.xml
  32. 19
      src/main/resources/mapper/PermissionMapper.xml
  33. 8
      src/main/resources/mapper/UrlMapper.xml

35
pom.xml

@ -31,15 +31,48 @@
</properties>
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.14</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.24</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.4</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.1.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>

200
src/main/java/com/example/demo/Util/ExcelUploadUtil.java

@ -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);
}
}
}

227
src/main/java/com/example/demo/Util/ExecutionContextUtil.java

@ -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";
}
}

173
src/main/java/com/example/demo/Util/FeiShuAlertUtil.java

@ -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);
}
}

37
src/main/java/com/example/demo/Util/RedisLockUtil.java

@ -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);
}
}
}

31
src/main/java/com/example/demo/Util/RedisUtil.java

@ -1,4 +1,3 @@
/*
package com.example.demo.Util;
import jakarta.annotation.PostConstruct;
@ -35,24 +34,24 @@ public class RedisUtil {
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) {
// 分段获取避免长时间阻塞
@ -66,35 +65,35 @@ public class RedisUtil {
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);
@ -116,10 +115,10 @@ public class RedisUtil {
});
}
*/
/**
* 启动延迟消息处理任务
*//*
*/
@Scheduled(fixedRate = DELAY_QUEUE_POLL_INTERVAL)
public void processDelayMessages() {
@ -134,10 +133,10 @@ public class RedisUtil {
}
}
*/
/**
* 处理单个延迟队列
*//*
*/
private void processSingleDelayQueue(String queueName) {
String delayQueueKey = getDelayQueueKey(queueName);
@ -187,4 +186,4 @@ public class RedisUtil {
}
return serialized;
}
}*/
}

18
src/main/java/com/example/demo/config/EnvConfig.java

@ -0,0 +1,18 @@
package com.example.demo.config;
import org.springframework.context.annotation.Configuration;
/**
* @program: GOLD
* @ClassName EnvConfig
* @description:
* @author: huangqizhen
* @create: 202506-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";
}

4
src/main/java/com/example/demo/config/RedisConfig.java

@ -1,4 +1,4 @@
/*
package com.example.demo.config;
import org.springframework.beans.factory.annotation.Autowired;
@ -45,4 +45,4 @@ public class RedisConfig {
}
*/

28
src/main/java/com/example/demo/controller/ExportController.java

@ -0,0 +1,28 @@
package com.example.demo.controller;
import com.example.demo.domain.entity.Export;
import com.example.demo.domain.vo.Result;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* @program: GOLD
* @ClassName ExportController
* @description:
* @author: huangqizhen
* @create: 202506-28 15:22
* @Version 1.0
**/
@RestController
@RequestMapping("/export")
@RequiredArgsConstructor
@Slf4j
@CrossOrigin
public class ExportController {
@PostMapping("/export")
public Result export(@RequestBody Export export){
return null;
}
}

31
src/main/java/com/example/demo/controller/GoldDetailController.java

@ -1,15 +1,23 @@
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.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
@ -26,6 +34,12 @@ import org.springframework.web.bind.annotation.*;
@CrossOrigin
public class GoldDetailController {
private final GoldDetailService goldDetailService;
@Autowired
private RedisLockUtil redisLockUtil;
@Autowired
private AiEmotionServiceImpl aiEmotionServiceImpl;
@PostMapping("/getGoldDetail")
public Result getGoldDetail(@RequestBody Page page){
@ -58,4 +72,21 @@ public class GoldDetailController {
}
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);
}
}
}

4
src/main/java/com/example/demo/controller/PermissionController.java

@ -62,5 +62,9 @@ public class PermissionController {
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));
}
}

44
src/main/java/com/example/demo/domain/DTO/GoldDetailDTO.java

@ -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: 202506-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 jwcode;
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(jwcode=%d, type=%d, state=%d, dataNum=%d)",
jwcode, type, state, dataNum
);
}
}

28
src/main/java/com/example/demo/domain/export/Goldmingxi.java

@ -0,0 +1,28 @@
package com.example.demo.domain.export;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @program: GOLD
* @ClassName goldmingxi
* @description:
* @author: huangqizhen
* @create: 202506-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; //提交人
}

28
src/main/java/com/example/demo/domain/vo/AiEmotionExportRecordVO.java

@ -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: 202506-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;
}

25
src/main/java/com/example/demo/domain/vo/ExecutionContext.java

@ -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();
}
}

26
src/main/java/com/example/demo/domain/vo/ExportVo.java

@ -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: 202506-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;
}

25
src/main/java/com/example/demo/mapper/AiEmotionMapper.java

@ -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: 202506-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);
}

19
src/main/java/com/example/demo/mapper/ExportMapper.java

@ -0,0 +1,19 @@
package com.example.demo.mapper;
import com.example.demo.domain.vo.ExportVo;
import org.apache.ibatis.annotations.Mapper;
/**
* @program: GOLD
* @ClassName ExportMapper
* @description:
* @author: huangqizhen
* @create: 202506-29 17:28
* @Version 1.0
**/
@Mapper
public interface ExportMapper {
ExportVo getExportData(Integer id);
ExportVo updateExportData(Long recordId, Integer state, String url, String reason, Integer dataNum);
}

15
src/main/java/com/example/demo/mapper/GoldDetailMapper.java

@ -4,6 +4,7 @@ import com.example.demo.domain.entity.User;
import com.example.demo.domain.vo.GoldDetail;
import com.example.demo.domain.vo.Total;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@ -19,7 +20,19 @@ import java.util.List;
public interface GoldDetailMapper {
List<GoldDetail> getGoldDetail(GoldDetail goldDetail);
Total getTotal(GoldDetail goldDetail);
List<User> getGold(User user);
Total GoldTotal(User user);
public static class ExportRecordIdHolder{
private Long id;
}
void insertExportRecord(
@Param("recordId") ExportRecordIdHolder recordId, // 用于接收主键
@Param("jwcode") Integer jwcode,
@Param("type") Integer type,
@Param("state") Integer state,
@Param("url") String url,
@Param("fileName") String fileName,
@Param("dataNum") Integer dataNum
);
);
}

19
src/main/java/com/example/demo/service/AiEmotionService.java

@ -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: 202506-29 14:27
* @Version 1.0
**/
public interface AiEmotionService {
ExportVo updateStatus(Long recordId, int i, String s, String s1, int i1);
AiEmotionExportRecordVO getRecordById(Long id) throws Exception;
}

16
src/main/java/com/example/demo/service/ExportExcelService.java

@ -0,0 +1,16 @@
package com.example.demo.service;
import com.example.demo.domain.vo.AiEmotionExportRecordVO;
/**
* @program: GOLD
* @ClassName exportService
* @description:
* @author: huangqizhen
* @create: 202506-28 15:39
* @Version 1.0
**/
public interface ExportExcelService {
Exception handleExcelExportData(String message) throws Exception;
}

7
src/main/java/com/example/demo/service/GoldDetailService.java

@ -1,9 +1,14 @@
package com.example.demo.service;
import com.example.demo.domain.DTO.GoldDetailDTO;
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;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @program: GOLD
@ -19,4 +24,6 @@ public interface GoldDetailService {
PageInfo<User> getGold(Integer pageNum, Integer pageSize, User user);
Total GoldTotal(User user);
//异步导出客户明细
Result addExportRecord(GoldDetailDTO dto);
}

1
src/main/java/com/example/demo/service/PermissionService.java

@ -26,4 +26,5 @@ public interface PermissionService {
List<Role> getRole(String token);
Integer deleteAdmin(Integer id);
Integer updateAdminRole(AdminRole adminRole);
Integer upadatePermission(Admin admin) throws Exception;
}

35
src/main/java/com/example/demo/serviceImpl/AiEmotionServiceImpl.java

@ -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: 202506-29 14:46
* @Version 1.0
**/
@Service
public class AiEmotionServiceImpl implements AiEmotionService {
@Autowired
private ExportMapper exportMapper;
@Autowired
private AiEmotionMapper aiEmotionMapper;
@Override
public ExportVo 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);
}
}

253
src/main/java/com/example/demo/serviceImpl/ExportExcelServiceImpl.java

@ -0,0 +1,253 @@
package com.example.demo.serviceImpl;
import cn.hutool.log.AbstractLog;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.example.demo.Util.ExcelUploadUtil;
import com.example.demo.controller.GoldDetailController;
import com.example.demo.domain.export.Goldmingxi;
import com.example.demo.domain.vo.*;
import com.example.demo.service.ExportExcelService;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.example.demo.service.AiEmotionService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.*;
import java.util.List;
import java.util.Map;
@Service
@Slf4j
public class ExportExcelServiceImpl implements ExportExcelService {
private static final ObjectMapper objectMapper = new ObjectMapper();
//注入AiEmotionService
@Autowired
private AiEmotionService aiEmotionService;
//注入GoldDetailController
@Autowired
private GoldDetailController goldDetailController;
// 每页查询的数据量
private static final int PAGE_SIZE = 1000;
@Transactional
@Override
public Exception handleExcelExportData(String message) throws Exception {
System.out.println("明细导出excel数据开始执行:" + message);
long startTime = System.currentTimeMillis();
Long recordId = null;
String fileName = null;
File tempFile = null;
OutputStream outputStream = null;
ExcelWriter excelWriter = null;
try {
// 1. 解析JSON任务
JsonNode rootNode = objectMapper.readTree(message);
// 2. 获取基本参数
recordId = rootNode.path("recordId").asLong();
JsonNode requestDataNode = rootNode.path("requestData");
// 3. 验证导出记录
AiEmotionExportRecordVO record = validateExportRecord(recordId);
if (record == null) return null;
//4. 更新状态为处理中
aiEmotionService.updateStatus(recordId, 1, "", "", 0);
// 5. 准备Excel文件
fileName = record.getFileName();
// 初始化临时文件保存到本地临时目录
tempFile = File.createTempFile("export_", ".xlsx");
outputStream = new FileOutputStream(tempFile); // 使用文件输出流
// 从JSON中提取单个值
String text = requestDataNode.has("text") ? requestDataNode.get("text").asText() : null;
Integer sort = requestDataNode.has("sort") ? requestDataNode.get("sort").asInt() : null;
String field = requestDataNode.has("field") ? requestDataNode.get("field").asText() : null;
String deptId = requestDataNode.has("deptId") ? requestDataNode.get("deptId").asText() : null;
try {
// 6. 初始化Excel写入器指向本地文件流
excelWriter = initExcelWriter(outputStream, "user");
WriteSheet writeSheet = EasyExcel.writerSheet("Sheet1").build();
// 7. 分页查询并写入数据
Page page = new Page();
page.setPageNum(1);
page.setPageSize(1000);
Integer totalCount = 0;
boolean hasMore = true;
while (hasMore) {
Result pageResult = goldDetailController.getGoldDetail(page);
Integer code = pageResult.getCode();
Object data = pageResult.getData();
if (code == 200) {
Map<String, Object> rawData = (Map<String, Object>) data;
Long total = (Long) rawData.get("total");
List<Map<String, Object>> list = (List<Map<String, Object>>) rawData.get("list");
// 检查是否还有数据
if (list == null || list.isEmpty()) {
hasMore = false;
} else {
// 写入数据注意finish()应在所有数据写入后调用
excelWriter.write(list, writeSheet);
page.setPageNum(page.getPageNum() + 1);
totalCount += list.size();
log.info("导出进度 recordId: {}, 已处理: {}条", recordId, totalCount);
// 检查是否还有更多数据
hasMore = totalCount < total;
}
} else {
hasMore = false;
log.error("获取数据失败,状态码: {}", code);
}
}
// 7. 完成Excel写入所有数据写入后关闭写入器
if (excelWriter != null) {
excelWriter.finish();
}
if (outputStream != null) {
outputStream.flush(); // 确保所有数据写入
outputStream.close(); // 关闭文件流
}
// 检查文件是否存在且不为空
if (tempFile != null && tempFile.exists() && tempFile.length() > 0) {
// 8. 上传到OSS读取本地临时文件
// 获取接口的基础 URL
String uploadUrl = "http://39.101.133.168:8828/hljw/api/aws/upload";
try {
// 1. 创建上传工具实例
ExcelUploadUtil uploadUtil = new ExcelUploadUtil(uploadUrl);
// 2. 准备要上传的文件
File excelFile = new File(tempFile.toURI());
try {
// 3. 执行上传
String result = uploadUtil.uploadExcel(excelFile, "export/excel/");
// 1. 解析JSON任务
JsonNode uploadResult = objectMapper.readTree(result);
long code = uploadResult.path("code").asLong();
String url = String.valueOf(uploadResult.path("data"));
url = url.replace("\"", "");
if (code == 1) {
// 3. 验证导出记录decodecode
aiEmotionService.updateStatus(recordId, 2, url, "", totalCount);
} else {
//更新失败
aiEmotionService.updateStatus(recordId, 3, "", url, 0);
}
} catch (Exception e) {
//更新失败
aiEmotionService.updateStatus(recordId, 3, "", StringUtils.substring(e.getMessage(), 0, 500), 0);
throw new Exception("文件上传云端失败1", e);
}
} catch (Exception e) {
log.error("上传文件失败 recordId: {}, 文件名: {}", recordId, fileName, e);
//更新状态为失败
if (recordId != null) {
aiEmotionService.updateStatus(recordId, 3, "", StringUtils.substring(e.getMessage(), 0, 500), 0);
}
throw new Exception("文件上传云端失败2", e);
}
} else {
throw new Exception("导出的Excel文件不存在或为空");
}
} catch (Exception e) {
System.out.println("导出异常" + e.getMessage());
log.error("导出任务处理失败 recordId: {}", recordId, e);
// 更新状态为失败
if (recordId != null) {
aiEmotionService.updateStatus(recordId, 3, "", StringUtils.substring(e.getMessage(), 0, 500), 0);
}
throw new Exception("导出异常", e);
} finally {
// 确保资源被关闭
try {
if (excelWriter != null) {
excelWriter.finish();
}
if (outputStream != null) {
outputStream.close();
}
} catch (Exception e) {
log.error("关闭资源失败", e);
throw new Exception("excel文件关闭资源失败", e);
}
}
} catch (Exception e) {
log.error("导出任务处理失败 recordId: {}", recordId, e);
// 更新状态为失败
if (recordId != null) {
aiEmotionService.updateStatus(recordId, 3, "", StringUtils.substring(e.getMessage(), 0, 500), 0);
}
System.out.println("<导出失败>" + e.getMessage());
throw new Exception("导出任务处理失败", e);
} finally {
// 清理临时文件
if (tempFile != null && tempFile.exists()) {
try {
if (tempFile.delete()) {
log.info("临时文件已删除: {}", tempFile.getAbsolutePath());
} else {
log.warn("无法删除临时文件: {}", tempFile.getAbsolutePath());
}
} catch (Exception e) {
log.error("删除临时文件失败", e.getMessage());
throw new Exception("删除临时文件失败", e);
}
}
long endTime = System.currentTimeMillis();
log.info("导出任务完成,耗时: {}毫秒", (endTime - startTime));
}
return null;
}
/**
* 验证导出记录
*/
private AiEmotionExportRecordVO validateExportRecord(Long recordId) throws Exception {
AiEmotionExportRecordVO record = aiEmotionService.getRecordById(recordId);
AbstractLog log = null;
if (record == null) {
log.error("导出记录不存在 recordId: {}", recordId);
return null;
}
// 检查是否已经处理过
if (record.getState() != 0) {
log.warn("导出记录已处理 recordId: {}, status: {}", recordId, record.getState());
return null;
}
return record;
}
/**
* 初始化excel文件
* @param os
* @param exportType
* @return
*/
private ExcelWriter initExcelWriter(OutputStream os, String exportType) {
switch (exportType) {
case "user":
return EasyExcel.write(os, Goldmingxi.class)
.inMemory(Boolean.TRUE)
.build();
default:
throw new IllegalArgumentException("不支持的导出类型: " + exportType);
}
}
}

69
src/main/java/com/example/demo/serviceImpl/GoldDetailServiceImpl.java

@ -1,16 +1,24 @@
package com.example.demo.serviceImpl;
import com.example.demo.domain.DTO.GoldDetailDTO;
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.example.demo.mapper.GoldDetailMapper;
import com.example.demo.service.GoldDetailService;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @program: GOLD
@ -25,24 +33,25 @@ public class GoldDetailServiceImpl implements GoldDetailService {
@Autowired
private GoldDetailMapper goldDetailMapper;
@Override
public PageInfo<GoldDetail> getGoldDetail(Integer pageNum, Integer pageSize, GoldDetail goldDetail) {
PageHelper.startPage(pageNum, pageSize);
List<GoldDetail> list= goldDetailMapper.getGoldDetail(goldDetail);
List<GoldDetail> list = goldDetailMapper.getGoldDetail(goldDetail);
return new PageInfo<>(list);
}
@Override
public Total getTotal(GoldDetail goldDetail) {
return goldDetailMapper.getTotal(goldDetail);
return goldDetailMapper.getTotal(goldDetail);
}
@Override
public PageInfo<User> getGold(Integer pageNum, Integer pageSize, User user) {
PageHelper.startPage(pageNum, pageSize);
List<User> list= goldDetailMapper.getGold(user);
List<User> list = goldDetailMapper.getGold(user);
return new PageInfo<>(list);
}
@ -50,4 +59,58 @@ public class GoldDetailServiceImpl implements GoldDetailService {
public Total GoldTotal(User user) {
return goldDetailMapper.GoldTotal(user);
}
@Override
public Result addExportRecord(GoldDetailDTO dto) {
// 获取操作者 jwcode
// 生成文件名
String fileName = String.format("%s_%s_%s.xlsx",
"客户金币明细",
"操作人",
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
System.out.println(fileName);
dto.setJwcode(123456);
dto.setUrl("");
dto.setFileName(fileName);
dto.setDataNum(0);
try{
// 调用方式
GoldDetailMapper.ExportRecordIdHolder idHolder = new AiEmotionMapper.ExportRecordIdHolder();
goldDetailMapper.insertExportRecord(
idHolder, // 用于接收主键
dto.getJwcode(),
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("hwgold:queue:export_queue", jsonData);
}catch (Exception e){
e.printStackTrace();
throw new SystemException("导出数据异常,请稍后重试", e);
}
return Result.success();
}
}
}
}

5
src/main/java/com/example/demo/serviceImpl/PermissionServiceImpl.java

@ -111,5 +111,10 @@ public class PermissionServiceImpl implements PermissionService {
return permissionMapper.updateAdminRole(adminRole);
}
@Override
public Integer upadatePermission(Admin admin) throws Exception {
return permissionMapper.updatePermission(admin);
}
}

14
src/main/resources/application.yml

@ -4,9 +4,9 @@ spring:
fail-on-unknown-properties: false
datasource:
mysql1:
jdbc-url: jdbc:mysql://192.168.8.220:3306/hwgold?serverTimezone=Asia/Shanghai
username: hwgold
password: 123456
jdbc-url: jdbc:mysql://18.143.76.3:3306/hwgoldc?serverTimezone=Asia/Shanghai
username: hwgoldc
password: zB48T55wCsHC8KPz
driver-class-name: com.mysql.cj.jdbc.Driver
hikari:
pool-name: mysql1HikariCP
@ -62,10 +62,10 @@ spring:
data:
redis:
database: 0
host: 192.168.8.94
port: 6379
password:
timeout: 1000
host: 18.143.76.3
port: 10703
password: Ngc0FYUTA6h3wC5J
lettuce:
pool:
max-active: 20

17
src/main/resources/mapper/AiEmotionMapper.xml

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.AiEmotionMapper">
<update id="updateStatus">
UPDATE admin_export_record
<set>
<if test="state != null">state = #{state},</if>
<if test="url != null and url != ''">url = #{url},</if>
<if test="reason != null and reason != ''">reason = #{reason},</if>
<if test="dataNum != null and dataNum != ''">data_num = #{dataNum},</if>
</set>
WHERE id = #{recordId}
</update>
<select id="getRecordById" resultType="com.example.demo.domain.vo.AiEmotionExportRecordVO">
SELECT id, file_name, state, url FROM admin_export_record WHERE id = #{recordId}
</select>
</mapper>

18
src/main/resources/mapper/ExportMapper.xml

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.ExportMapper">
<update id="updateExportData">
UPDATE export
<set>
<if test="state != null">state = #{state},</if>
<if test="url != null and url != ''">url = #{url},</if>
<if test="reason != null and reason != ''">reason = #{reason},</if>
<if test="dataNum != null and dataNum != ''">data_num = #{dataNum},</if>
</set>
WHERE id = #{recordId}
</update>
<select id="getExportData" resultType="com.example.demo.domain.vo.ExportVo">
select id,file_name,url,state from export where id=#{recordId}
</select>
</mapper>

15
src/main/resources/mapper/GoldDetailMapper.xml

@ -1,6 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.GoldDetailMapper">
<insert id="insertExportRecord">
insert into
</insert>
<select id="getGoldDetail" resultType="com.example.demo.domain.vo.GoldDetail">
select `user`.name, `user`.jwcode, `user`.market, `ugr`.pay_platform, `ugr`.type, `ugr`.sum_gold, `ugr`.permanent_gold, `ugr`.free_june, `ugr`.free_december, `ugr`.task_gold, `admin`.admin_name, `ugr`.audit_time
@ -8,13 +11,13 @@
left join `user` on `user`.jwcode = `ugr`.jwcode
left join `admin` on `admin`.id = `ugr`.admin_id
<where>
<if test="jwcode != null and jwcode.length > 0">
<if test="jwcode != null">
and `ugr`.jwcode = #{jwcode}
</if>
<if test="payPlatform != null and payPlatform.length > 0">
and `ugr`.pay_platform = #{payPlatform}
</if>
<if test="type != null and type.length > 0">
<if test="type != null">
and `ugr`.type = #{type}
</if>
<if test="market != null and market.length > 0">
@ -38,13 +41,13 @@
select sum(sum_gold) as Goldtotal, sum(permanent_gold) as permanentGold, sum(free_june+free_december) as freeGold, sum(task_gold) as taskGold
from user_gold_record
<where>
<if test="jwcode != null and jwcode.length > 0">
<if test="jwcode != null">
and `ugr`.jwcode = #{jwcode}
</if>
<if test="payPlatform != null and payPlatform.length > 0">
and `ugr`.pay_platform = #{payPlatform}
</if>
<if test="type != null and type.length > 0">
<if test="type != null">
and `ugr`.type = #{type}
</if>
<if test="market != null and market.length > 0">
@ -59,7 +62,7 @@
<select id="getGold" resultType="com.example.demo.domain.entity.User">
select * from user
<where>
<if test="jwcode != null and jwcode.length > 0">
<if test="jwcode != null">
and jwcode = #{jwcode}
</if>
<if test="market != null and market.length > 0">
@ -83,7 +86,7 @@
sum(current_permanent_gold) + sum(current_free_june + current_free_december) + sum(current_task_gold) as Goldtotal
from `user`
<where>
<if test="jwcode != null and jwcode.length > 0">
<if test="jwcode != null ">
and jwcode = #{jwcode}
</if>
<if test="market != null and market.length > 0">

19
src/main/resources/mapper/PermissionMapper.xml

@ -12,20 +12,11 @@
<update id="updatePermission">
update admin
<set>
<if test="name!=null">
admin_name=#{name},
</if>
<if test="market!=null">
market=#{market},
</if>
<if test="postiton!=null">
postiton=#{postiton},
</if>
<if test="role!=null">
roleId=#{role},
<if test="adminStatus!=null">
admin_status= #{adminStatus},
</if>
</set>
where id= #{id}
where id=#{id}
</update>
<update id="updateAdminRole">
update admin_role
@ -49,7 +40,7 @@
select distinct market from admin
</select>
<select id="getPermission" resultType="com.example.demo.domain.vo.Permission">
select admin.id,admin.admin_name,admin.account,admin.market,admin.postiton,admin.remark,admin.admin_status,role.role_name
select admin.id as id,admin.admin_name as name,admin.account,admin.market,admin.postiton,admin.remark,admin.admin_status,role.role_name,role.id as roleId
from admin
left join admin_role on admin.id=admin_role.admin_id
left join role on admin_role.role_id=role.id
@ -70,4 +61,4 @@
select * from role
</select>
</mapper>
</mapper>

8
src/main/resources/mapper/UrlMapper.xml

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UrlMapper">
<select id="selectBaseUrl" resultType="java.lang.String">
select value from env where `key` = #{key}
</select>
</mapper>
Loading…
Cancel
Save