|
@@ -15,6 +15,7 @@ import com.yingpai.stock.domain.vo.StockPoolHistoryVo;
|
|
|
import com.yingpai.stock.mapper.StockPoolHistoryMapper;
|
|
import com.yingpai.stock.mapper.StockPoolHistoryMapper;
|
|
|
import com.yingpai.stock.mapper.StockPoolMapper;
|
|
import com.yingpai.stock.mapper.StockPoolMapper;
|
|
|
import com.yingpai.stock.service.IStockPoolHistoryService;
|
|
import com.yingpai.stock.service.IStockPoolHistoryService;
|
|
|
|
|
+import com.yingpai.stock.service.IStockPoolService;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
import lombok.RequiredArgsConstructor;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.dromara.common.core.utils.StringUtils;
|
|
import org.dromara.common.core.utils.StringUtils;
|
|
@@ -46,6 +47,7 @@ public class StockPoolHistoryServiceImpl implements IStockPoolHistoryService {
|
|
|
|
|
|
|
|
private final StockPoolHistoryMapper baseMapper;
|
|
private final StockPoolHistoryMapper baseMapper;
|
|
|
private final StockPoolMapper stockPoolMapper;
|
|
private final StockPoolMapper stockPoolMapper;
|
|
|
|
|
+ private final IStockPoolService stockPoolService;
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
public TableDataInfo<StockPoolHistoryVo> queryPageList(StockPoolHistoryBo bo, PageQuery pageQuery) {
|
|
public TableDataInfo<StockPoolHistoryVo> queryPageList(StockPoolHistoryBo bo, PageQuery pageQuery) {
|
|
@@ -101,18 +103,18 @@ public class StockPoolHistoryServiceImpl implements IStockPoolHistoryService {
|
|
|
// 读取 Excel 数据
|
|
// 读取 Excel 数据
|
|
|
String originalFilename = file.getOriginalFilename();
|
|
String originalFilename = file.getOriginalFilename();
|
|
|
log.info("导入文件名: {}, 文件大小: {} bytes", originalFilename, file.getSize());
|
|
log.info("导入文件名: {}, 文件大小: {} bytes", originalFilename, file.getSize());
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 判断文件类型
|
|
// 判断文件类型
|
|
|
- boolean isXls = originalFilename != null && originalFilename.toLowerCase().endsWith(".xls")
|
|
|
|
|
|
|
+ boolean isXls = originalFilename != null && originalFilename.toLowerCase().endsWith(".xls")
|
|
|
&& !originalFilename.toLowerCase().endsWith(".xlsx");
|
|
&& !originalFilename.toLowerCase().endsWith(".xlsx");
|
|
|
log.info("文件类型: {}", isXls ? "xls (Excel 97-2003)" : "xlsx (Excel 2007+)");
|
|
log.info("文件类型: {}", isXls ? "xls (Excel 97-2003)" : "xlsx (Excel 2007+)");
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 使用 Map 方式读取原始数据,避免类型转换问题
|
|
// 使用 Map 方式读取原始数据,避免类型转换问题
|
|
|
List<Map<Integer, String>> rawDataList = new ArrayList<>();
|
|
List<Map<Integer, String>> rawDataList = new ArrayList<>();
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 使用 BufferedInputStream 支持 mark/reset
|
|
// 使用 BufferedInputStream 支持 mark/reset
|
|
|
InputStream inputStream = new BufferedInputStream(file.getInputStream());
|
|
InputStream inputStream = new BufferedInputStream(file.getInputStream());
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
try {
|
|
try {
|
|
|
if (isXls) {
|
|
if (isXls) {
|
|
|
// .xls 文件使用 GBK 编码读取(解决中文乱码问题)
|
|
// .xls 文件使用 GBK 编码读取(解决中文乱码问题)
|
|
@@ -151,19 +153,19 @@ public class StockPoolHistoryServiceImpl implements IStockPoolHistoryService {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
log.info("读取到 {} 条原始数据", rawDataList.size());
|
|
log.info("读取到 {} 条原始数据", rawDataList.size());
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 输出前5条原始数据用于调试
|
|
// 输出前5条原始数据用于调试
|
|
|
for (int i = 0; i < Math.min(5, rawDataList.size()); i++) {
|
|
for (int i = 0; i < Math.min(5, rawDataList.size()); i++) {
|
|
|
Map<Integer, String> row = rawDataList.get(i);
|
|
Map<Integer, String> row = rawDataList.get(i);
|
|
|
log.info("=== 调试 - 第{}条原始数据(共{}列)===", i + 1, row.size());
|
|
log.info("=== 调试 - 第{}条原始数据(共{}列)===", i + 1, row.size());
|
|
|
for (Map.Entry<Integer, String> entry : row.entrySet()) {
|
|
for (Map.Entry<Integer, String> entry : row.entrySet()) {
|
|
|
String value = entry.getValue();
|
|
String value = entry.getValue();
|
|
|
- log.info(" 列{}: [{}] (长度:{})", entry.getKey(),
|
|
|
|
|
|
|
+ log.info(" 列{}: [{}] (长度:{})", entry.getKey(),
|
|
|
value != null && value.length() > 50 ? value.substring(0, 50) + "..." : value,
|
|
value != null && value.length() > 50 ? value.substring(0, 50) + "..." : value,
|
|
|
value != null ? value.length() : 0);
|
|
value != null ? value.length() : 0);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 检查是否所有数据都在一列中(可能是制表符分隔的文本)
|
|
// 检查是否所有数据都在一列中(可能是制表符分隔的文本)
|
|
|
if (!rawDataList.isEmpty()) {
|
|
if (!rawDataList.isEmpty()) {
|
|
|
Map<Integer, String> firstRow = rawDataList.get(0);
|
|
Map<Integer, String> firstRow = rawDataList.get(0);
|
|
@@ -186,17 +188,17 @@ public class StockPoolHistoryServiceImpl implements IStockPoolHistoryService {
|
|
|
log.info("制表符分割成功,每行 {} 列", splitDataList.get(0).size());
|
|
log.info("制表符分割成功,每行 {} 列", splitDataList.get(0).size());
|
|
|
rawDataList.clear();
|
|
rawDataList.clear();
|
|
|
rawDataList.addAll(splitDataList);
|
|
rawDataList.addAll(splitDataList);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 再次输出调试信息
|
|
// 再次输出调试信息
|
|
|
for (int i = 0; i < Math.min(3, rawDataList.size()); i++) {
|
|
for (int i = 0; i < Math.min(3, rawDataList.size()); i++) {
|
|
|
Map<Integer, String> row = rawDataList.get(i);
|
|
Map<Integer, String> row = rawDataList.get(i);
|
|
|
- log.info("分割后第{}条: 列0=[{}], 列1=[{}], 列2=[{}]",
|
|
|
|
|
|
|
+ log.info("分割后第{}条: 列0=[{}], 列1=[{}], 列2=[{}]",
|
|
|
i + 1, row.get(0), row.get(1), row.get(2));
|
|
i + 1, row.get(0), row.get(1), row.get(2));
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 将原始数据转换为 StockPoolHistoryVo
|
|
// 将原始数据转换为 StockPoolHistoryVo
|
|
|
List<StockPoolHistoryVo> dataList = new ArrayList<>();
|
|
List<StockPoolHistoryVo> dataList = new ArrayList<>();
|
|
|
for (Map<Integer, String> row : rawDataList) {
|
|
for (Map<Integer, String> row : rawDataList) {
|
|
@@ -219,15 +221,23 @@ public class StockPoolHistoryServiceImpl implements IStockPoolHistoryService {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
log.info("转换后数据 {} 条", dataList.size());
|
|
log.info("转换后数据 {} 条", dataList.size());
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 输出前5条转换后的数据用于调试
|
|
// 输出前5条转换后的数据用于调试
|
|
|
for (int i = 0; i < Math.min(5, dataList.size()); i++) {
|
|
for (int i = 0; i < Math.min(5, dataList.size()); i++) {
|
|
|
StockPoolHistoryVo debugVo = dataList.get(i);
|
|
StockPoolHistoryVo debugVo = dataList.get(i);
|
|
|
- log.info("转换后第{}条: 代码=[{}], 名称=[{}], 涨幅=[{}], 收盘=[{}]",
|
|
|
|
|
- i + 1, debugVo.getStockCode(), debugVo.getStockName(),
|
|
|
|
|
|
|
+ log.info("转换后第{}条: 代码=[{}], 名称=[{}], 涨幅=[{}], 收盘=[{}]",
|
|
|
|
|
+ i + 1, debugVo.getStockCode(), debugVo.getStockName(),
|
|
|
debugVo.getChangePercent(), debugVo.getClosePrice());
|
|
debugVo.getChangePercent(), debugVo.getClosePrice());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // 如果是重复导入同一天的数据,先删除该日期的所有历史记录
|
|
|
|
|
+ LambdaQueryWrapper<StockPoolHistory> deleteLqw = Wrappers.lambdaQuery();
|
|
|
|
|
+ deleteLqw.eq(StockPoolHistory::getRecordDate, parsedRecordDate);
|
|
|
|
|
+ int deletedCount = baseMapper.delete(deleteLqw);
|
|
|
|
|
+ if (deletedCount > 0) {
|
|
|
|
|
+ log.info("删除同一天的旧历史记录: {} 条", deletedCount);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
int successNum = 0;
|
|
int successNum = 0;
|
|
|
int updateNum = 0;
|
|
int updateNum = 0;
|
|
|
int failureNum = 0;
|
|
int failureNum = 0;
|
|
@@ -261,22 +271,22 @@ public class StockPoolHistoryServiceImpl implements IStockPoolHistoryService {
|
|
|
// 处理股票代码(去除可能的引号和公式格式)
|
|
// 处理股票代码(去除可能的引号和公式格式)
|
|
|
String stockCode = vo.getStockCode();
|
|
String stockCode = vo.getStockCode();
|
|
|
String stockName = vo.getStockName();
|
|
String stockName = vo.getStockName();
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (stockCode != null) {
|
|
if (stockCode != null) {
|
|
|
// 去除前后空格
|
|
// 去除前后空格
|
|
|
stockCode = stockCode.trim();
|
|
stockCode = stockCode.trim();
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 调试日志:记录前几条数据的原始值
|
|
// 调试日志:记录前几条数据的原始值
|
|
|
if (i < 5) {
|
|
if (i < 5) {
|
|
|
- log.info("第{}条数据 - 处理前代码: [{}], 长度: {}, 名称: [{}]",
|
|
|
|
|
|
|
+ log.info("第{}条数据 - 处理前代码: [{}], 长度: {}, 名称: [{}]",
|
|
|
i + 1, stockCode, stockCode.length(), stockName);
|
|
i + 1, stockCode, stockCode.length(), stockName);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 处理公式格式 ="000547"
|
|
// 处理公式格式 ="000547"
|
|
|
if (stockCode.startsWith("=")) {
|
|
if (stockCode.startsWith("=")) {
|
|
|
stockCode = stockCode.substring(1);
|
|
stockCode = stockCode.substring(1);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 去除所有类型的引号(使用 Unicode 转义避免编码问题)
|
|
// 去除所有类型的引号(使用 Unicode 转义避免编码问题)
|
|
|
stockCode = stockCode.replace("\"", ""); // 双引号
|
|
stockCode = stockCode.replace("\"", ""); // 双引号
|
|
|
stockCode = stockCode.replace("'", ""); // 单引号
|
|
stockCode = stockCode.replace("'", ""); // 单引号
|
|
@@ -284,28 +294,28 @@ public class StockPoolHistoryServiceImpl implements IStockPoolHistoryService {
|
|
|
stockCode = stockCode.replace("\u201D", ""); // 中文右双引号
|
|
stockCode = stockCode.replace("\u201D", ""); // 中文右双引号
|
|
|
stockCode = stockCode.replace("\u2018", ""); // 中文左单引号
|
|
stockCode = stockCode.replace("\u2018", ""); // 中文左单引号
|
|
|
stockCode = stockCode.replace("\u2019", ""); // 中文右单引号
|
|
stockCode = stockCode.replace("\u2019", ""); // 中文右单引号
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 去除所有空白字符(包括空格、制表符、换行符等)
|
|
// 去除所有空白字符(包括空格、制表符、换行符等)
|
|
|
stockCode = stockCode.replaceAll("\\s+", "");
|
|
stockCode = stockCode.replaceAll("\\s+", "");
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 只保留数字和字母(股票代码只应该包含这些字符)
|
|
// 只保留数字和字母(股票代码只应该包含这些字符)
|
|
|
stockCode = stockCode.replaceAll("[^0-9A-Za-z]", "");
|
|
stockCode = stockCode.replaceAll("[^0-9A-Za-z]", "");
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 确保长度不超过20个字符(数据库限制)
|
|
// 确保长度不超过20个字符(数据库限制)
|
|
|
if (stockCode.length() > 20) {
|
|
if (stockCode.length() > 20) {
|
|
|
- log.warn("第{}条数据 - 股票代码过长,截取前20位: [{}] -> [{}]",
|
|
|
|
|
|
|
+ log.warn("第{}条数据 - 股票代码过长,截取前20位: [{}] -> [{}]",
|
|
|
i + 1, stockCode, stockCode.substring(0, 20));
|
|
i + 1, stockCode, stockCode.substring(0, 20));
|
|
|
stockCode = stockCode.substring(0, 20);
|
|
stockCode = stockCode.substring(0, 20);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 调试日志:记录处理后的值
|
|
// 调试日志:记录处理后的值
|
|
|
if (i < 5) {
|
|
if (i < 5) {
|
|
|
log.info("第{}条数据 - 处理后代码: [{}], 长度: {}", i + 1, stockCode, stockCode.length());
|
|
log.info("第{}条数据 - 处理后代码: [{}], 长度: {}", i + 1, stockCode, stockCode.length());
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
vo.setStockCode(stockCode);
|
|
vo.setStockCode(stockCode);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 处理股票名称(去除可能的特殊字符)
|
|
// 处理股票名称(去除可能的特殊字符)
|
|
|
if (stockName != null) {
|
|
if (stockName != null) {
|
|
|
stockName = stockName.trim();
|
|
stockName = stockName.trim();
|
|
@@ -331,10 +341,10 @@ public class StockPoolHistoryServiceImpl implements IStockPoolHistoryService {
|
|
|
}
|
|
}
|
|
|
continue;
|
|
continue;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 验证股票代码格式(正常股票代码应该是6位数字)
|
|
// 验证股票代码格式(正常股票代码应该是6位数字)
|
|
|
String code = vo.getStockCode();
|
|
String code = vo.getStockCode();
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 如果代码超过6位,可能是多列数据被拼接了,尝试提取前6位
|
|
// 如果代码超过6位,可能是多列数据被拼接了,尝试提取前6位
|
|
|
if (code.length() > 6) {
|
|
if (code.length() > 6) {
|
|
|
String originalCode = code;
|
|
String originalCode = code;
|
|
@@ -343,7 +353,7 @@ public class StockPoolHistoryServiceImpl implements IStockPoolHistoryService {
|
|
|
log.info("第{}条数据 - 股票代码过长,尝试提取前6位: [{}] -> [{}]", i + 1, originalCode, code);
|
|
log.info("第{}条数据 - 股票代码过长,尝试提取前6位: [{}] -> [{}]", i + 1, originalCode, code);
|
|
|
vo.setStockCode(code);
|
|
vo.setStockCode(code);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 验证股票代码是否为纯6位数字
|
|
// 验证股票代码是否为纯6位数字
|
|
|
if (!code.matches("^\\d{6}$")) {
|
|
if (!code.matches("^\\d{6}$")) {
|
|
|
log.warn("第{}条数据 - 股票代码不是6位数字,跳过: [{}]", i + 1, code);
|
|
log.warn("第{}条数据 - 股票代码不是6位数字,跳过: [{}]", i + 1, code);
|
|
@@ -353,7 +363,7 @@ public class StockPoolHistoryServiceImpl implements IStockPoolHistoryService {
|
|
|
.append("(股票代码应为6位数字)");
|
|
.append("(股票代码应为6位数字)");
|
|
|
continue;
|
|
continue;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 检查必填字段 - 股票名称
|
|
// 检查必填字段 - 股票名称
|
|
|
if (StringUtils.isBlank(vo.getStockName())) {
|
|
if (StringUtils.isBlank(vo.getStockName())) {
|
|
|
failureNum++;
|
|
failureNum++;
|
|
@@ -432,10 +442,17 @@ public class StockPoolHistoryServiceImpl implements IStockPoolHistoryService {
|
|
|
log.info("批量更新完成: {} 条", toUpdateList.size());
|
|
log.info("批量更新完成: {} 条", toUpdateList.size());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 如果导入日期是当天,将排名前十的股票加入强势池
|
|
|
|
|
- if (parsedRecordDate.equals(LocalDate.now())) {
|
|
|
|
|
- log.info("[强势池] 检测到导入日期为当天,开始将排名前十的股票加入强势池");
|
|
|
|
|
- addTopTenToStrongPool(parsedRecordDate);
|
|
|
|
|
|
|
+ // 将排名前十的股票加入强势池
|
|
|
|
|
+ log.info("[强势池] 开始将排名前十的股票加入强势池,导入日期: {}", parsedRecordDate);
|
|
|
|
|
+ addTopTenToStrongPool(parsedRecordDate);
|
|
|
|
|
+
|
|
|
|
|
+ // 调用数据补全功能,将历史数据补全到stock_pool表
|
|
|
|
|
+ try {
|
|
|
|
|
+ log.info("[数据补全] 开始补全历史数据到stock_pool表,导入日期: {}", parsedRecordDate);
|
|
|
|
|
+ String completeResult = stockPoolService.completeHistoryData(parsedRecordDate);
|
|
|
|
|
+ log.info("[数据补全] 补全结果: {}", completeResult);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("[数据补全] 补全历史数据失败: {}", e.getMessage(), e);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (failureNum > 0) {
|
|
if (failureNum > 0) {
|
|
@@ -450,7 +467,7 @@ public class StockPoolHistoryServiceImpl implements IStockPoolHistoryService {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 将排名前十的股票加入强势池(覆盖原有数据)
|
|
|
|
|
|
|
+ * 将排名前十的股票加入强势池(将之前的设为历史有效)
|
|
|
*/
|
|
*/
|
|
|
private void addTopTenToStrongPool(LocalDate recordDate) {
|
|
private void addTopTenToStrongPool(LocalDate recordDate) {
|
|
|
try {
|
|
try {
|
|
@@ -470,15 +487,43 @@ public class StockPoolHistoryServiceImpl implements IStockPoolHistoryService {
|
|
|
.map(h -> h.getStockCode() + "-" + h.getStockName())
|
|
.map(h -> h.getStockCode() + "-" + h.getStockName())
|
|
|
.collect(java.util.stream.Collectors.joining(", ")));
|
|
.collect(java.util.stream.Collectors.joining(", ")));
|
|
|
|
|
|
|
|
- // 2. 清空原有的强势池数据(poolType=2)
|
|
|
|
|
- LambdaQueryWrapper<StockPool> deleteLqw = Wrappers.lambdaQuery();
|
|
|
|
|
- deleteLqw.eq(StockPool::getPoolType, 2);
|
|
|
|
|
- int deletedCount = stockPoolMapper.delete(deleteLqw);
|
|
|
|
|
- log.info("[强势池] 清空原有强势池数据,删除 {} 条", deletedCount);
|
|
|
|
|
|
|
+ // 2. 查询当天已存在的强势池数据
|
|
|
|
|
+ LambdaQueryWrapper<StockPool> todayLqw = Wrappers.lambdaQuery();
|
|
|
|
|
+ todayLqw.eq(StockPool::getPoolType, 2)
|
|
|
|
|
+ .eq(StockPool::getAddDate, recordDate)
|
|
|
|
|
+ .eq(StockPool::getStatus, 2);
|
|
|
|
|
+ List<StockPool> todayPools = stockPoolMapper.selectList(todayLqw);
|
|
|
|
|
+ Map<String, StockPool> todayPoolMap = todayPools.stream()
|
|
|
|
|
+ .collect(java.util.stream.Collectors.toMap(StockPool::getStockCode, p -> p));
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 收集前十名的股票代码
|
|
|
|
|
+ java.util.Set<String> topTenCodes = topTen.stream()
|
|
|
|
|
+ .map(StockPoolHistory::getStockCode)
|
|
|
|
|
+ .collect(java.util.stream.Collectors.toSet());
|
|
|
|
|
+
|
|
|
|
|
+ // 4. 将当天存在但不在前十名中的股票状态改为1
|
|
|
|
|
+ for (StockPool pool : todayPools) {
|
|
|
|
|
+ if (!topTenCodes.contains(pool.getStockCode())) {
|
|
|
|
|
+ pool.setStatus(1);
|
|
|
|
|
+ stockPoolMapper.updateById(pool);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 5. 将其他日期的强势池数据状态改为1
|
|
|
|
|
+ LambdaQueryWrapper<StockPool> otherDaysLqw = Wrappers.lambdaQuery();
|
|
|
|
|
+ otherDaysLqw.eq(StockPool::getPoolType, 2)
|
|
|
|
|
+ .eq(StockPool::getStatus, 2)
|
|
|
|
|
+ .ne(StockPool::getAddDate, recordDate);
|
|
|
|
|
+ List<StockPool> otherDaysPools = stockPoolMapper.selectList(otherDaysLqw);
|
|
|
|
|
+ for (StockPool pool : otherDaysPools) {
|
|
|
|
|
+ pool.setStatus(1);
|
|
|
|
|
+ stockPoolMapper.updateById(pool);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // 3. 将前十名加入强势池
|
|
|
|
|
|
|
+ // 6. 处理前十名:更新或插入
|
|
|
Long adminId = LoginHelper.getUserId();
|
|
Long adminId = LoginHelper.getUserId();
|
|
|
List<StockPool> toInsert = new ArrayList<>();
|
|
List<StockPool> toInsert = new ArrayList<>();
|
|
|
|
|
+ int updateCount = 0;
|
|
|
|
|
|
|
|
for (StockPoolHistory history : topTen) {
|
|
for (StockPoolHistory history : topTen) {
|
|
|
// 优先使用 closePrice,如果为空则使用 dayClosePrice
|
|
// 优先使用 closePrice,如果为空则使用 dayClosePrice
|
|
@@ -493,20 +538,39 @@ public class StockPoolHistoryServiceImpl implements IStockPoolHistoryService {
|
|
|
continue;
|
|
continue;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- StockPool pool = new StockPool();
|
|
|
|
|
- pool.setStockCode(history.getStockCode());
|
|
|
|
|
- pool.setStockName(history.getStockName());
|
|
|
|
|
- pool.setPoolType(2); // 强势池
|
|
|
|
|
- pool.setAddPrice(addPrice);
|
|
|
|
|
- pool.setAddDate(recordDate);
|
|
|
|
|
- pool.setStatus(1); // 有效
|
|
|
|
|
- pool.setAdminId(adminId);
|
|
|
|
|
- toInsert.add(pool);
|
|
|
|
|
|
|
+ String stockCode = history.getStockCode();
|
|
|
|
|
+ StockPool existingPool = todayPoolMap.get(stockCode);
|
|
|
|
|
+
|
|
|
|
|
+ if (existingPool != null) {
|
|
|
|
|
+ // 当天已存在该股票,更新数据
|
|
|
|
|
+ existingPool.setStockName(history.getStockName());
|
|
|
|
|
+ existingPool.setAddPrice(addPrice);
|
|
|
|
|
+ existingPool.setNextDayGain(history.getHighTrend());
|
|
|
|
|
+ existingPool.setStatus(2);
|
|
|
|
|
+ existingPool.setAdminId(adminId);
|
|
|
|
|
+ stockPoolMapper.updateById(existingPool);
|
|
|
|
|
+ updateCount++;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 当天不存在该股票,插入新记录
|
|
|
|
|
+ StockPool pool = new StockPool();
|
|
|
|
|
+ pool.setStockCode(stockCode);
|
|
|
|
|
+ pool.setStockName(history.getStockName());
|
|
|
|
|
+ pool.setPoolType(2); // 强势池
|
|
|
|
|
+ pool.setAddPrice(addPrice);
|
|
|
|
|
+ pool.setAddDate(recordDate);
|
|
|
|
|
+ pool.setNextDayGain(history.getHighTrend()); // 设置最高涨幅
|
|
|
|
|
+ pool.setStatus(2); // 当前有效
|
|
|
|
|
+ pool.setAdminId(adminId);
|
|
|
|
|
+ toInsert.add(pool);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (!toInsert.isEmpty()) {
|
|
if (!toInsert.isEmpty()) {
|
|
|
stockPoolMapper.insertBatch(toInsert);
|
|
stockPoolMapper.insertBatch(toInsert);
|
|
|
- log.info("[强势池] 成功加入 {} 只股票到强势池", toInsert.size());
|
|
|
|
|
|
|
+ log.info("[强势池] 成功插入 {} 只股票到强势池", toInsert.size());
|
|
|
|
|
+ }
|
|
|
|
|
+ if (updateCount > 0) {
|
|
|
|
|
+ log.info("[强势池] 成功更新 {} 只股票到强势池", updateCount);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
@@ -514,6 +578,7 @@ public class StockPoolHistoryServiceImpl implements IStockPoolHistoryService {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 从 Map 中获取字符串值
|
|
* 从 Map 中获取字符串值
|
|
|
*/
|
|
*/
|
|
@@ -531,15 +596,15 @@ public class StockPoolHistoryServiceImpl implements IStockPoolHistoryService {
|
|
|
value = value.substring(1);
|
|
value = value.substring(1);
|
|
|
value = value.replace("\"", "").replace("'", "");
|
|
value = value.replace("\"", "").replace("'", "");
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 尝试修复编码问题(如果检测到乱码)
|
|
// 尝试修复编码问题(如果检测到乱码)
|
|
|
if (containsGarbledText(value)) {
|
|
if (containsGarbledText(value)) {
|
|
|
value = tryFixEncoding(value);
|
|
value = tryFixEncoding(value);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
return value.isEmpty() ? null : value;
|
|
return value.isEmpty() ? null : value;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 检测是否包含乱码(简单检测)
|
|
* 检测是否包含乱码(简单检测)
|
|
|
*/
|
|
*/
|
|
@@ -560,7 +625,7 @@ public class StockPoolHistoryServiceImpl implements IStockPoolHistoryService {
|
|
|
// 如果超过30%的字符是特殊字符,可能是乱码
|
|
// 如果超过30%的字符是特殊字符,可能是乱码
|
|
|
return specialCharCount > text.length() * 0.3;
|
|
return specialCharCount > text.length() * 0.3;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 尝试修复编码问题
|
|
* 尝试修复编码问题
|
|
|
*/
|
|
*/
|
|
@@ -576,7 +641,7 @@ public class StockPoolHistoryServiceImpl implements IStockPoolHistoryService {
|
|
|
log.debug("编码修复成功: [{}] -> [{}]", text, gbkText);
|
|
log.debug("编码修复成功: [{}] -> [{}]", text, gbkText);
|
|
|
return gbkText;
|
|
return gbkText;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 尝试将 UTF-8 编码的字符串转换为 GBK
|
|
// 尝试将 UTF-8 编码的字符串转换为 GBK
|
|
|
bytes = text.getBytes(java.nio.charset.StandardCharsets.UTF_8);
|
|
bytes = text.getBytes(java.nio.charset.StandardCharsets.UTF_8);
|
|
|
gbkText = new String(bytes, java.nio.charset.Charset.forName("GBK"));
|
|
gbkText = new String(bytes, java.nio.charset.Charset.forName("GBK"));
|
|
@@ -589,7 +654,7 @@ public class StockPoolHistoryServiceImpl implements IStockPoolHistoryService {
|
|
|
}
|
|
}
|
|
|
return text;
|
|
return text;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 从 Map 中获取 BigDecimal 值
|
|
* 从 Map 中获取 BigDecimal 值
|
|
|
*/
|
|
*/
|