Browse Source

时间转换BUG

master
han\hanst 4 weeks ago
parent
commit
7c04ca65ba
  1. 114
      src/main/java/com/xujie/sys/modules/pms/service/Impl/MesTidEpcLogServiceImpl.java
  2. 4
      src/main/resources/mapper/pms/MesTidEpcLogMapper.xml

114
src/main/java/com/xujie/sys/modules/pms/service/Impl/MesTidEpcLogServiceImpl.java

@ -32,7 +32,11 @@ import java.net.URLEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.DateTimeParseException;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.zip.ZipEntry;
@ -198,41 +202,37 @@ public class MesTidEpcLogServiceImpl extends ServiceImpl<MesTidEpcLogMapper, Mes
// 列0: 序号
entity.setSeqNo(getCellValue(row.getCell(0), dataFormatter));
// 列1: EPC
entity.setEpc(getCellValue(row.getCell(1), dataFormatter));
entity.setEpc(getCellValue(row.getCell(2), dataFormatter));
// 列2: TID
entity.setTid(getCellValue(row.getCell(2), dataFormatter));
entity.setTid(getCellValue(row.getCell(3), dataFormatter));
// 列3: 用户区
entity.setUserArea(getCellValue(row.getCell(3), dataFormatter));
entity.setUserArea(getCellValue(row.getCell(4), dataFormatter));
// 列4: LockiBtis
entity.setLockBits(getCellValue(row.getCell(4), dataFormatter));
entity.setLockBits(getCellValue(row.getCell(5), dataFormatter));
// 列5: 密匙
entity.setSecretKey(getCellValue(row.getCell(5), dataFormatter));
entity.setSecretKey(getCellValue(row.getCell(6), dataFormatter));
// 列6: 写码成功
entity.setWriteSuccess(getCellValue(row.getCell(6), dataFormatter));
entity.setWriteSuccess(getCellValue(row.getCell(7), dataFormatter));
// 列7: 读码成功
entity.setReadSuccess(getCellValue(row.getCell(7), dataFormatter));
entity.setReadSuccess(getCellValue(row.getCell(8), dataFormatter));
// 列8: EPC锁定
entity.setEpcLocked(getCellValue(row.getCell(8), dataFormatter));
entity.setEpcLocked(getCellValue(row.getCell(9), dataFormatter));
// 列9: 强度/读距
entity.setSignalStrength(getCellValue(row.getCell(9), dataFormatter));
entity.setSignalStrength(getCellValue(row.getCell(10), dataFormatter));
// 列10: 时间
Cell timeCell = row.getCell(10);
Cell timeCell = row.getCell(11);
if (timeCell != null) {
if (timeCell.getCellType() == CellType.NUMERIC && DateUtil.isCellDateFormatted(timeCell)) {
entity.setScanTime(timeCell.getDateCellValue());
} else {
String timeStr = getCellValue(timeCell, dataFormatter);
if (StringUtils.hasText(timeStr)) {
try {
entity.setScanTime(sdf.parse(timeStr));
} catch (ParseException e) {
log.warn("第{}行时间格式解析失败: {} - rqrq", rowNum + 1, timeStr);
}
entity.setScanTime(parseDate(timeStr));
}
}
}
// 列11: 计数
entity.setCountInfo(getCellValue(row.getCell(11), dataFormatter));
entity.setCountInfo(getCellValue(row.getCell(12), dataFormatter));
dataList.add(entity);
}
@ -241,6 +241,26 @@ public class MesTidEpcLogServiceImpl extends ServiceImpl<MesTidEpcLogMapper, Mes
return dataList;
}
public static Date parseDate(String timeStr) {
DateTimeFormatter FORMATTER =
new DateTimeFormatterBuilder()
.appendOptional(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))
.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
.toFormatter();
try {
LocalDateTime localDateTime =
LocalDateTime.parse(timeStr, FORMATTER);
return Date.from(
localDateTime.atZone(ZoneId.systemDefault()).toInstant()
);
} catch (DateTimeParseException e) {
throw new RuntimeException("时间格式错误: " + timeStr, e);
}
}
/**
* @Description 获取单元格值 - rqrq
* @param cell 单元格
@ -297,7 +317,7 @@ public class MesTidEpcLogServiceImpl extends ServiceImpl<MesTidEpcLogMapper, Mes
/**
* @Description 导出CSV文件真正的流式导出MyBatis ResultHandler + 逐行写入- rqrq
*
*
* <p><b>V5版本真正的流式导出</b></p>
* <ul>
* <li>使用 MyBatis ResultHandler 逐行从数据库读取</li>
@ -305,14 +325,14 @@ public class MesTidEpcLogServiceImpl extends ServiceImpl<MesTidEpcLogMapper, Mes
* <li>配合 JDBC responseBuffering=adaptive FORWARD_ONLY 游标</li>
* <li>真正的 O(1) 内存占用可导出任意大小数据集</li>
* </ul>
*
*
* <p><b>导出策略</b></p>
* <ul>
* <li>数据量 100万返回单个CSV文件</li>
* <li>数据量 > 100万返回ZIP压缩包每个CSV最多100万条</li>
* <li>数据量 > 500万提示用户缩小范围分批导出</li>
* </ul>
*
*
* @param data 查询条件
* @param response HttpServletResponse
* @author rqrq
@ -364,14 +384,14 @@ public class MesTidEpcLogServiceImpl extends ServiceImpl<MesTidEpcLogMapper, Mes
/**
* @Description 真正的流式CSV导出单文件- rqrq
*
*
* <p><b>核心原理</b></p>
* <ul>
* <li>MyBatis ResultHandler 逐行回调</li>
* <li>每收到一行数据立即写入CSV</li>
* <li>内存中始终只有1行数据</li>
* </ul>
*
*
* @param data 查询条件
* @param dataTotal 数据总数
* @param response HttpServletResponse
@ -448,7 +468,7 @@ public class MesTidEpcLogServiceImpl extends ServiceImpl<MesTidEpcLogMapper, Mes
/**
* @Description 真正的流式ZIP导出多CSV文件- rqrq
*
*
* <p><b>核心原理</b></p>
* <ul>
* <li>MyBatis ResultHandler 逐行回调</li>
@ -456,7 +476,7 @@ public class MesTidEpcLogServiceImpl extends ServiceImpl<MesTidEpcLogMapper, Mes
* <li>当前CSV达到100万行自动切换到新CSV</li>
* <li>内存中始终只有1行数据</li>
* </ul>
*
*
* @param data 查询条件
* @param dataTotal 数据总数
* @param response HttpServletResponse
@ -536,10 +556,10 @@ public class MesTidEpcLogServiceImpl extends ServiceImpl<MesTidEpcLogMapper, Mes
/**
* @Description V4备份写入ZIP压缩包伪流式分批查询分批写入- rqrq
*
*
* <p><b>已被V5取代</b>保留此方法用于对比或回退</p>
* <p><b>调用方式</b>如需使用在exportCsv方法中替换exportToZipRealStreaming为此方法</p>
*
*
* @param data 查询条件
* @param dataTotal 数据总数
* @param response HttpServletResponse
@ -549,7 +569,7 @@ public class MesTidEpcLogServiceImpl extends ServiceImpl<MesTidEpcLogMapper, Mes
@SuppressWarnings("unused")
private void writeToZipWithMultipleCsv(MesTidEpcLogData data, long dataTotal, HttpServletResponse response) throws IOException {
log.info("开始生成ZIP压缩包(多CSV),数据总数: {} 条 - rqrq", dataTotal);
// 设置响应头ZIP格式- rqrq
response.setContentType("application/zip");
response.setCharacterEncoding("UTF-8");
@ -563,7 +583,7 @@ public class MesTidEpcLogServiceImpl extends ServiceImpl<MesTidEpcLogMapper, Mes
try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
int pageSize = EXPORT_BATCH_SIZE;
int totalPages = (int) Math.ceil((double) dataTotal / pageSize);
long totalWritten = 0; // 总共已写入的行数
int currentCsvIndex = 1; // 当前CSV文件编号
long currentCsvRows = 0; // 当前CSV已写入的行数
@ -593,13 +613,13 @@ public class MesTidEpcLogServiceImpl extends ServiceImpl<MesTidEpcLogMapper, Mes
log.info("CSV文件 {} 写入完成,共 {} 条 - rqrq", currentCsvIndex, currentCsvRows);
currentCsvIndex++;
}
// 创建新的CSV文件 - rqrq
String csvFileName = "TID_EPC日志_" + currentCsvIndex + ".csv";
ZipEntry zipEntry = new ZipEntry(csvFileName);
zipOut.putNextEntry(zipEntry);
currentWriter = new BufferedWriter(new OutputStreamWriter(zipOut, "GB18030"), 8192 * 16);
// 写入表头 - rqrq
currentWriter.write(csvHeader);
currentWriter.newLine();
@ -623,7 +643,7 @@ public class MesTidEpcLogServiceImpl extends ServiceImpl<MesTidEpcLogMapper, Mes
sb.append(escapeCsvAsText(row.getCountInfo()));
currentWriter.write(sb.toString());
currentWriter.newLine();
currentCsvRows++;
totalWritten++;
}
@ -656,10 +676,10 @@ public class MesTidEpcLogServiceImpl extends ServiceImpl<MesTidEpcLogMapper, Mes
/**
* @Description 写入方式1EasyExcel默认版 - rqrq
*
*
* <p><b>特点</b>使用EasyExcel默认配置支持注解样式</p>
* <p><b>预计耗时</b>50万条约35-40秒</p>
*
*
* @param dataList 数据列表
* @param response HttpServletResponse
* @author rqrq
@ -708,10 +728,10 @@ public class MesTidEpcLogServiceImpl extends ServiceImpl<MesTidEpcLogMapper, Mes
/**
* @Description 写入方式2EasyExcel优化版关闭自动列宽等- rqrq
*
*
* <p><b>特点</b>关闭自动列宽计算使用inMemory模式</p>
* <p><b>预计耗时</b>50万条约25-30秒</p>
*
*
* @param dataList 数据列表
* @param response HttpServletResponse
* @author rqrq
@ -764,11 +784,11 @@ public class MesTidEpcLogServiceImpl extends ServiceImpl<MesTidEpcLogMapper, Mes
/**
* @Description 写入方式3CSV纯文本版最快- rqrq
*
*
* <p><b>特点</b>直接写入CSV文本无Excel格式处理开销</p>
* <p><b>预计耗时</b>50万条约3-5秒</p>
* <p><b>注意</b>CSV无多Sheet支持大文件用Excel打开可能卡</p>
*
*
* @param dataList 数据列表
* @param response HttpServletResponse
* @author rqrq
@ -787,7 +807,7 @@ public class MesTidEpcLogServiceImpl extends ServiceImpl<MesTidEpcLogMapper, Mes
// 使用BufferedWriter提高写入性能 - rqrq
java.io.BufferedWriter writer = new java.io.BufferedWriter(
new java.io.OutputStreamWriter(response.getOutputStream(), "GB18030"),
new java.io.OutputStreamWriter(response.getOutputStream(), "GB18030"),
8192 * 16); // 128KB缓冲区
try {
@ -874,7 +894,7 @@ public class MesTidEpcLogServiceImpl extends ServiceImpl<MesTidEpcLogMapper, Mes
/**
* @Description 写入方式4CSV流式写入边查边写最高效- rqrq
*
*
* <p><b>特点</b></p>
* <ul>
* <li>分批查询每批查完立即写入CSV</li>
@ -882,7 +902,7 @@ public class MesTidEpcLogServiceImpl extends ServiceImpl<MesTidEpcLogMapper, Mes
* <li>边查边写总耗时最短</li>
* </ul>
* <p><b>预计耗时</b>50万条约25-30秒查询+写入并行</p>
*
*
* @param data 查询条件
* @param dataTotal 数据总数由调用方传入避免重复COUNT查询
* @param response HttpServletResponse
@ -976,17 +996,17 @@ public class MesTidEpcLogServiceImpl extends ServiceImpl<MesTidEpcLogMapper, Mes
// ==================================================================================
// ========================= 导出方法V1版本备份可随时切换=========================
// ==================================================================================
/**
* @Description 使用EasyExcel导出Excel文件V1版本分批查询分批写入- rqrq
*
*
* <p><b>V1版本特点</b></p>
* <ul>
* <li>每批查询10万条查完立即写入Excel</li>
* <li>优点内存占用小适合超大数据量</li>
* <li>缺点IO操作频繁可能较慢</li>
* </ul>
*
*
* <p><b>执行流程</b></p>
* <ol>
* <li>先查询总数计算需要查询的批次数</li>
@ -995,13 +1015,13 @@ public class MesTidEpcLogServiceImpl extends ServiceImpl<MesTidEpcLogMapper, Mes
* <li>检查当前Sheet是否已满满了则创建新Sheet</li>
* <li>循环直到所有批次处理完成</li>
* </ol>
*
*
* <p><b>切换方法</b></p>
* <ol>
* <li>将Controller中调用的 exportCsv 改为 exportCsvOld</li>
* <li>或者将本方法内容与 exportCsv 方法内容互换</li>
* </ol>
*
*
* @param data 查询条件
* @param response HttpServletResponse
* @author rqrq
@ -1056,7 +1076,7 @@ public class MesTidEpcLogServiceImpl extends ServiceImpl<MesTidEpcLogMapper, Mes
// 4.1 查询当前批次数据手动分页直接返回List- rqrq
long offset = (long) (pageNum - 1) * pageSize;
log.info("查询第 {}/{} 批,OFFSET: {} - rqrq", pageNum, totalPages, offset);
// 手动分页查询无IPage开销 - rqrq
List<MesTidEpcLogExportData> records = mesTidEpcLogMapper.searchExportListManual(data, offset, pageSize);
@ -1102,7 +1122,7 @@ public class MesTidEpcLogServiceImpl extends ServiceImpl<MesTidEpcLogMapper, Mes
totalExported += exportList.size();
}
log.info("已导出 {}/{} 条,当前Sheet {} 有 {} 条 - rqrq",
log.info("已导出 {}/{} 条,当前Sheet {} 有 {} 条 - rqrq",
totalExported, dataTotal, sheetIndex + 1, sheetRowCount);
}
@ -1111,7 +1131,7 @@ public class MesTidEpcLogServiceImpl extends ServiceImpl<MesTidEpcLogMapper, Mes
// ============ 步骤5完成导出 ============ - rqrq
long endTime = System.currentTimeMillis();
log.info("MES TID EPC日志导出完成(V1),共 {} 条,{} 个Sheet,总耗时: {} 秒 - rqrq",
log.info("MES TID EPC日志导出完成(V1),共 {} 条,{} 个Sheet,总耗时: {} 秒 - rqrq",
totalExported, sheetIndex + 1, (endTime - startTime) / 1000.0);
} catch (IOException e) {

4
src/main/resources/mapper/pms/MesTidEpcLogMapper.xml

@ -332,12 +332,12 @@
#{item.readSuccess},
#{item.epcLocked},
#{item.signalStrength},
#{item.scanTime},
#{item.scanTime,jdbcType=TIMESTAMP},
#{item.countInfo},
#{item.batchNo},
#{item.fileName},
#{item.uploadBy},
#{item.uploadTime},
#{item.uploadTime,jdbcType=TIMESTAMP},
#{item.remark}
)
</foreach>

Loading…
Cancel
Save