From d5404feec8225ed6bb280d919ad18bbbcccace87 Mon Sep 17 00:00:00 2001 From: aike <17730485278@139.com> Date: Fri, 23 May 2025 14:41:19 +0800 Subject: [PATCH] =?UTF-8?q?demand:=20=20=E8=88=AA=E7=BA=BF=E5=BC=80?= =?UTF-8?q?=E7=A5=A8=E8=AE=B0=E5=BD=95=E6=9F=A5=E8=AF=A2=E3=80=81=E5=AF=BC?= =?UTF-8?q?=E5=87=BA=E3=80=81=E5=AE=9A=E5=88=B6=E5=AF=BC=E5=87=BA=E6=80=A7?= =?UTF-8?q?=E8=83=BD=E4=BC=98=E5=8C=96=20committer:=20heyu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EmisSettleInvoiceChRecordController.java | 42 +- .../IEmisSettleInvoiceChRecordService.java | 11 + .../InvoicePoiExportUtil.java | 55 ++- .../EmisSettleInvoiceChRecordServiceImpl.java | 142 +++++- .../main/resources/mapper/EmisBaseMapper.xml | 13 + .../EmisSettleInvoiceChRecordMapper.xml | 449 ++++++++++-------- 6 files changed, 446 insertions(+), 266 deletions(-) diff --git a/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisSettleInvoiceChRecordController.java b/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisSettleInvoiceChRecordController.java index 48a669247..0d1073385 100644 --- a/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisSettleInvoiceChRecordController.java +++ b/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisSettleInvoiceChRecordController.java @@ -99,47 +99,7 @@ public class EmisSettleInvoiceChRecordController extends BaseController @Log(title = "渠道开票记录表", businessType = BusinessType.EXPORT) @PostMapping("/export") public void export(HttpServletResponse response, EmisSettleInvoiceChRecord emisSettleInvoiceChRecord) { - List list = emisSettleInvoiceChRecordService - .selectEmisSettleInvoiceChRecordList(emisSettleInvoiceChRecord); - List exportList = new ArrayList<>(); - for (EmisSettleInvoiceChRecord record : list) { - EmisSettleInvoiceChRecordExportVO vo = new EmisSettleInvoiceChRecordExportVO(); - // 开票日期 - if (record.getCreateTime() != null) { - vo.setInvoiceDate(new SimpleDateFormat("M月d日").format(record.getCreateTime())); - } - // 公司抬头 - vo.setCompanyTitle(InvoiceExportHelper.cleanCompanyTitle(record.getCompanyName())); - // 发票号 - vo.setInvoiceNo(record.getInvoiceNo()); - // 时间 - vo.setSendMonth(record.getSendMonth()); - // 开票金额 - vo.setOpenMoney(record.getOpenMoney().stripTrailingZeros().toPlainString()); - // 开票公司 - vo.setInvoiceCompany(InvoiceExportHelper.mapInvoiceCompany(record.getSalerCompanyName())); - // 备注 - vo.setRemark(InvoiceExportHelper.processRemark(record)); - vo.setCustomRemark(InvoiceExportHelper.processCustomRemark(record)); - // 付款日期 - vo.setPayDate(InvoiceExportHelper.processPayDate(record.getExportPayDays())); - // 业务员 - vo.setSalesmen(record.getSalesmen()); - // 快递公司 - vo.setExpressCompany(record.getSalesmen()); - // 面单单号 - vo.setBillCode("1".equals(record.getSettleType()) ? record.getBillCode() : ""); - // 结算类型 - vo.setSettleType(record.getSettleType()); - // 申请备注 - vo.setApplyRemark(record.getApplyRemark()); - exportList.add(vo); - } - try { - InvoicePoiExportUtil.export(response, exportList); - } catch (Exception e) { - e.printStackTrace(); - } + emisSettleInvoiceChRecordService.export(response, emisSettleInvoiceChRecord); } /** diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/service/IEmisSettleInvoiceChRecordService.java b/emis-biz/src/main/java/com/xdadan/erp/emis/service/IEmisSettleInvoiceChRecordService.java index f7a42f1a7..69e7ea8cc 100644 --- a/emis-biz/src/main/java/com/xdadan/erp/emis/service/IEmisSettleInvoiceChRecordService.java +++ b/emis-biz/src/main/java/com/xdadan/erp/emis/service/IEmisSettleInvoiceChRecordService.java @@ -13,6 +13,8 @@ import java.util.List; import com.xdadan.erp.emis.domain.EmisSettleInvoiceChRecord; import com.xdadan.erp.emis.domain.exception.EmisBizError; +import javax.servlet.http.HttpServletResponse; + /** * @ClassName EmisSettleInvoiceChRecordService * @Description 渠道开票记录表 @@ -92,4 +94,13 @@ public interface IEmisSettleInvoiceChRecordService public void autoDoQueryOpenBillStatus(); public void doQueryAndUpdateChOpenBillStatus(String reqNo); + + /** + * 渠道开票定制导出 + * + * @param response + * @param emisSettleInvoiceChRecord + */ + void export(HttpServletResponse response, EmisSettleInvoiceChRecord emisSettleInvoiceChRecord); + } diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/service/excelCellStrategy/InvoicePoiExportUtil.java b/emis-biz/src/main/java/com/xdadan/erp/emis/service/excelCellStrategy/InvoicePoiExportUtil.java index 27758b000..d23d7ff1c 100644 --- a/emis-biz/src/main/java/com/xdadan/erp/emis/service/excelCellStrategy/InvoicePoiExportUtil.java +++ b/emis-biz/src/main/java/com/xdadan/erp/emis/service/excelCellStrategy/InvoicePoiExportUtil.java @@ -2,21 +2,26 @@ package com.xdadan.erp.emis.service.excelCellStrategy; import com.xdadan.erp.emis.domain.EmisSettleInvoiceChRecordExportVO; import org.apache.poi.ss.usermodel.*; -import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; -import javax.servlet.http.HttpServletResponse; import java.io.OutputStream; import java.util.List; public class InvoicePoiExportUtil { + private static SXSSFWorkbook wb; + private static Sheet sheet; + private static CellStyle style; + private static int rowIndex = 1; + private static OutputStream outputStream; - public static void export(HttpServletResponse response, List data) - throws Exception { - Workbook wb = new XSSFWorkbook(); - Sheet sheet = wb.createSheet("渠道开票记录表"); + public static void createExcelWriter(OutputStream os) throws Exception { + outputStream = os; + // 创建工作簿 + wb = new SXSSFWorkbook(100); // 使用SXSSFWorkbook,每100行刷新一次 + sheet = wb.createSheet("渠道开票记录表"); // 设置行高、字体、边框 - CellStyle style = wb.createCellStyle(); + style = wb.createCellStyle(); Font font = wb.createFont(); font.setFontName("宋体"); font.setFontHeightInPoints((short) 10); @@ -27,7 +32,8 @@ public class InvoicePoiExportUtil { style.setBorderRight(BorderStyle.THIN); // 表头 - String[] headers = { "开票日期", "公司抬头", "发票号", "时间", "开票金额", "开票公司", "备注", "定制备注", "付款日期", "业务员", "快递公司", "面单单号" }; + String[] headers = { "开票日期", "公司抬头", "发票号", "时间", "开票金额", "开票公司", "备注", "定制备注", "付款日期", "业务员", "快递公司", + "面单单号" }; Row headRow = sheet.createRow(0); headRow.setHeightInPoints(30); for (int i = 0; i < headers.length; i++) { @@ -41,11 +47,15 @@ public class InvoicePoiExportUtil { for (int i = 0; i < columnWidths.length; i++) { sheet.setColumnWidth(i, (int) (columnWidths[i] * 256)); } + } + + public static void writeBatch(List data) throws Exception { + if (data == null || data.isEmpty()) { + return; + } - // 数据 - int rowIdx = 1; for (EmisSettleInvoiceChRecordExportVO vo : data) { - Row row = sheet.createRow(rowIdx++); + Row row = sheet.createRow(rowIndex++); row.setHeightInPoints(30); int col = 0; row.createCell(col++).setCellValue(vo.getInvoiceDate()); @@ -61,17 +71,22 @@ public class InvoicePoiExportUtil { row.createCell(col++).setCellValue(vo.getExpressCompany()); row.createCell(col++).setCellValue(vo.getBillCode()); - for (int i = 0; i < headers.length; i++) { + for (int i = 0; i < 12; i++) { row.getCell(i).setCellStyle(style); } } - - // 输出 - response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); - response.setHeader("Content-Disposition", "attachment;filename=invoice_export.xlsx"); - OutputStream os = response.getOutputStream(); - wb.write(os); - os.flush(); - wb.close(); } + + public static void finish() throws Exception { + if (wb != null) { + wb.write(outputStream); + wb.close(); + wb = null; + sheet = null; + style = null; + rowIndex = 1; + outputStream = null; + } + } + } \ No newline at end of file diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisSettleInvoiceChRecordServiceImpl.java b/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisSettleInvoiceChRecordServiceImpl.java index f44caedd0..afc21add0 100644 --- a/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisSettleInvoiceChRecordServiceImpl.java +++ b/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisSettleInvoiceChRecordServiceImpl.java @@ -10,35 +10,41 @@ package com.xdadan.erp.emis.service.impl; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; +import com.github.pagehelper.PageHelper; import com.xdadan.erp.common.utils.DateUtils; import com.xdadan.erp.common.utils.SecurityUtils; import com.xdadan.erp.common.utils.StringUtils; -import com.xdadan.erp.emis.domain.EmisBaseInvoiceChInfo; -import com.xdadan.erp.emis.domain.EmisSettleBill; -import com.xdadan.erp.emis.domain.EmisSettleInvoiceRecord; +import com.xdadan.erp.emis.domain.*; import com.xdadan.erp.emis.domain.enumtype.EmisBizErrorType; import com.xdadan.erp.emis.domain.exception.EmisBizError; import com.xdadan.erp.emis.mapper.EmisBaseInvoiceChInfoMapper; import com.xdadan.erp.emis.mapper.EmisSettleInvoiceRecordMapper; import com.xdadan.erp.emis.service.EmisBaseService; import com.xdadan.erp.emis.service.IEmisSettleBillService; +import com.xdadan.erp.emis.service.excelCellStrategy.InvoiceExportHelper; +import com.xdadan.erp.emis.service.excelCellStrategy.InvoicePoiExportUtil; import com.xdadan.erp.emis.service.openbill.hx.HXOrderGoods; import com.xdadan.erp.emis.service.openbill.hx.HXOrderInfo; import com.xdadan.erp.emis.service.openbill.hx.HXSdk; import com.xdadan.erp.emis.utils.WaybillHelper; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import com.xdadan.erp.emis.domain.EmisSettleInvoiceChRecord; import com.xdadan.erp.emis.mapper.EmisSettleInvoiceChRecordMapper; import com.xdadan.erp.emis.service.IEmisSettleInvoiceChRecordService; import org.springframework.util.CollectionUtils; +import javax.servlet.http.HttpServletResponse; + /** * 渠道开票记录表Service业务层处理 * @@ -46,6 +52,7 @@ import org.springframework.util.CollectionUtils; * @date 2024-07-24 23:39:08 */ @Service +@Slf4j public class EmisSettleInvoiceChRecordServiceImpl extends EmisBaseService implements IEmisSettleInvoiceChRecordService { @Autowired @@ -60,6 +67,27 @@ public class EmisSettleInvoiceChRecordServiceImpl extends EmisBaseService implem @Autowired private IEmisSettleBillService emisSettleBillService; + // 创建线程池 + private static final int AVAILABLE_PROCESSORS = Runtime.getRuntime().availableProcessors(); + private static final ThreadPoolExecutor executor = new ThreadPoolExecutor( + AVAILABLE_PROCESSORS, // 核心线程数 - 使用CPU核心数 + AVAILABLE_PROCESSORS * 2, // 最大线程数 - CPU核心数的2倍 + 60L, // 空闲线程存活时间 + TimeUnit.SECONDS, // 时间单位 + new LinkedBlockingQueue<>(1000), // 工作队列 + new ThreadFactory() { + private final AtomicInteger threadNumber = new AtomicInteger(1); + + @Override + public Thread newThread(Runnable r) { + Thread t = new Thread(r, "export-thread-" + threadNumber.getAndIncrement()); + t.setDaemon(true); + return t; + } + }, + new ThreadPoolExecutor.CallerRunsPolicy() // Rejection policy + ); + /** * 查询渠道开票记录表 * @@ -82,7 +110,111 @@ public class EmisSettleInvoiceChRecordServiceImpl extends EmisBaseService implem @Override public List selectEmisSettleInvoiceChRecordList(EmisSettleInvoiceChRecord emisSettleInvoiceChRecord) { - return emisSettleInvoiceChRecordMapper.selectEmisSettleInvoiceChRecordList(emisSettleInvoiceChRecord); + long startTime = System.currentTimeMillis(); + List emisSettleInvoiceChRecords = emisSettleInvoiceChRecordMapper.selectEmisSettleInvoiceChRecordList(emisSettleInvoiceChRecord); + long endTime = System.currentTimeMillis(); + log.info("查询渠道开票记录列表完成, 耗时: {}ms", (endTime - startTime)); + return emisSettleInvoiceChRecords; + } + + @Override + public void export(HttpServletResponse response, EmisSettleInvoiceChRecord emisSettleInvoiceChRecord) { + long startTime = System.currentTimeMillis(); + log.info("Starting invoice record export, query parameters: {}", emisSettleInvoiceChRecord); + + try { + response.setContentType("application/vnd.ms-excel"); + response.setCharacterEncoding("utf-8"); + String fileName = "invoice_records_" + new SimpleDateFormat("yyyyMMdd").format(new Date()); + response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx"); + + InvoicePoiExportUtil.createExcelWriter(response.getOutputStream()); + + int pageSize = 1000; + int pageNum = 1; + boolean hasMore = true; + + List>> futures = new ArrayList<>(); + int totalRecords = 0; + + while (hasMore) { + final int currentPage = pageNum; + Future> future = executor.submit(() -> { + PageHelper.startPage(currentPage, pageSize); + List list = this.selectEmisSettleInvoiceChRecordList( + emisSettleInvoiceChRecord); + + if (list == null || list.isEmpty()) { + return new ArrayList<>(); + } + + List exportList = new ArrayList<>(); + for (EmisSettleInvoiceChRecord record : list) { + EmisSettleInvoiceChRecordExportVO vo = new EmisSettleInvoiceChRecordExportVO(); + // 开票日期 + if (record.getCreateTime() != null) { + vo.setInvoiceDate(new SimpleDateFormat("M月d日").format(record.getCreateTime())); + } + // 公司抬头 + vo.setCompanyTitle(InvoiceExportHelper.cleanCompanyTitle(record.getCompanyName())); + // 发票号 + vo.setInvoiceNo(record.getInvoiceNo()); + // 时间 + vo.setSendMonth(record.getSendMonth()); + // 开票金额 + vo.setOpenMoney(record.getOpenMoney().stripTrailingZeros().toPlainString()); + // 开票公司 + vo.setInvoiceCompany(InvoiceExportHelper.mapInvoiceCompany(record.getSalerCompanyName())); + // 备注 + vo.setRemark(InvoiceExportHelper.processRemark(record)); + // 定制备注 + vo.setCustomRemark(InvoiceExportHelper.processCustomRemark(record)); + // 付款日期 + vo.setPayDate(InvoiceExportHelper.processPayDate(record.getExportPayDays())); + // 业务员 + vo.setSalesmen(record.getSalesmen()); + // 快递公司 + vo.setExpressCompany(record.getSalesmen()); + // 面单单号 + vo.setBillCode("1".equals(record.getSettleType()) ? record.getBillCode() : ""); + // 结算类型 + vo.setSettleType(record.getSettleType()); + // 申请备注 + vo.setApplyRemark(record.getApplyRemark()); + exportList.add(vo); + } + + return exportList; + }); + + futures.add(future); + pageNum++; + + if (future.get().isEmpty()) { + hasMore = false; + } else { + totalRecords += future.get().size(); + } + } + + for (Future> future : futures) { + List exportList = future.get(); + if (!exportList.isEmpty()) { + InvoicePoiExportUtil.writeBatch(exportList); + exportList.clear(); + } + } + + InvoicePoiExportUtil.finish(); + + long totalTime = System.currentTimeMillis() - startTime; + log.info("Export completed, total time: {}ms, average time per record: {}ms", + totalTime, totalRecords > 0 ? totalTime / totalRecords : 0); + + } catch (Exception e) { + log.error("Failed to export Excel", e); + throw new RuntimeException("Failed to export Excel", e); + } } diff --git a/emis-biz/src/main/resources/mapper/EmisBaseMapper.xml b/emis-biz/src/main/resources/mapper/EmisBaseMapper.xml index 1da79d27f..be3e0279c 100644 --- a/emis-biz/src/main/resources/mapper/EmisBaseMapper.xml +++ b/emis-biz/src/main/resources/mapper/EmisBaseMapper.xml @@ -23,6 +23,19 @@ + + + + + + + + + + + + + + -