更新导入插件

main
HUOJIN\92525 2025-09-09 13:32:59 +08:00
parent 74d7f757f3
commit 0f1069cac3
6 changed files with 166 additions and 74 deletions

View File

@ -1,5 +1,6 @@
package com.youchain.basicdata.service.impl; package com.youchain.basicdata.service.impl;
import cn.idev.excel.read.metadata.ReadSheet;
import com.youchain.basicdata.domain.BillType; import com.youchain.basicdata.domain.BillType;
import com.youchain.basicdata.domain.Item; import com.youchain.basicdata.domain.Item;
import com.youchain.basicdata.repository.*; import com.youchain.basicdata.repository.*;
@ -21,7 +22,6 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -52,18 +52,18 @@ public class ImportAsnServiceImpl implements ImportAsnService {
// String type = FileUtil.getFileType(suffix); // String type = FileUtil.getFileType(suffix);
// FileUtil.upload(file, properties.getPath().getPath() + type + File.separator); // FileUtil.upload(file, properties.getPath().getPath() + type + File.separator);
// 验证模板类型是否正确 // 验证模板类型是否正确
isValidTemplateType(file, templateType); List<ReadSheet> readSheets = isValidTemplateType(file, templateType);
// 根据模板类型进行不同的处理 // 根据模板类型进行不同的处理
switch (templateType) { switch (templateType) {
case "template1": case "template1":
baseImportTemplate(file); baseImportTemplate(file, readSheets);
break; break;
case "template2": case "template2":
bigItemTemplate(file); bigItemTemplate(file, readSheets);
break; break;
case "template3": case "template3":
invoicePackingTemplate(file); invoicePackingTemplate(file, readSheets);
break; break;
default: default:
throw new BadRequestException("不支持的模板类型: " + templateType); throw new BadRequestException("不支持的模板类型: " + templateType);
@ -72,26 +72,25 @@ public class ImportAsnServiceImpl implements ImportAsnService {
// 处理标准模板 // 处理标准模板
@Transactional @Transactional
public void baseImportTemplate(MultipartFile file) { public void baseImportTemplate(MultipartFile file, List<ReadSheet> readSheets) {
// 读取sheet数据 // 读取sheet数据
List<BaseImport> dataList = FastExcelUtil.readExcelData(file, BaseImport.class, 0, 1); List<BaseImport> dataList = FastExcelUtil.readExcelData(file, BaseImport.class, readSheets.get(0).getSheetNo(), 1);
//批量导入 //批量导入
importAsnData(dataList); importAsnData(dataList);
} }
//处理大物模板 //处理大物模板
private void bigItemTemplate(MultipartFile file) { private void bigItemTemplate(MultipartFile file, List<ReadSheet> readSheets) {
// 获取发票号 // 获取发票号
FastExcelCellListener reader = new FastExcelCellListener() FastExcelCellListener reader = new FastExcelCellListener()
.addTargetCell(5, 55); // invoiceNo .addTargetCell(6, 55); // invoiceNo
Map<String, String> cellValues = FastExcelUtil.readExcelCellValues(file, reader); FastExcelUtil.readExcelCellValues(file, reader, readSheets.get(0).getSheetNo());
String invoiceNo = cellValues.get("5-55"); String invoiceNo = reader.getCellValue(6, 55);
// 读取两个sheet的数据 // 读取两个sheet的数据
List<BaseImport> sheet1Data = FastExcelUtil.readExcelData(file, BaseImport.class, 0, 21); List<BaseImport> sheet1Data = FastExcelUtil.readExcelData(file, BaseImport.class, readSheets.get(0).getSheetNo(), 21);
List<BaseImport> sheet2Data = FastExcelUtil.readExcelData(file, BaseImport.class, 1, 21); List<BaseImport> sheet2Data = FastExcelUtil.readExcelData(file, BaseImport.class, readSheets.get(1).getSheetNo(), 21);
//大物数据处理 //大物数据处理
List<BaseImport> dataList = bigItemDataProcess(invoiceNo, sheet1Data, sheet2Data); List<BaseImport> dataList = bigItemDataProcess(invoiceNo, sheet1Data, sheet2Data);
@ -102,21 +101,20 @@ public class ImportAsnServiceImpl implements ImportAsnService {
} }
// 处理发票箱单模板 // 处理发票箱单模板
private void invoicePackingTemplate(MultipartFile file) { private void invoicePackingTemplate(MultipartFile file, List<ReadSheet> readSheets) {
// 获取发票 // 读取第二个sheet的invoiceNo
FastExcelCellListener reader = new FastExcelCellListener().addTargetCell(2, 11); // invoiceNo FastExcelCellListener reader = new FastExcelCellListener().addTargetCell(3, 11); // invoiceNo
Map<String, String> cellValues = FastExcelUtil.readExcelCellValues(file, reader); FastExcelUtil.readExcelCellValues(file, reader, readSheets.get(1).getSheetNo());//
String invoiceNo = cellValues.get("2-11"); String invoiceNo = reader.getCellValue(3, 11);
// 读取sheet数据 // 读取sheet数据
List<InvoicePackingImport> sheet1Data = FastExcelUtil.readExcelData(file, InvoicePackingImport.class, 0, 24); List<InvoicePackingImport> sheet1Data = FastExcelUtil.readExcelData(file, InvoicePackingImport.class, readSheets.get(0).getSheetNo(), 24);
// 读取sheet数据 // 读取sheet数据
List<InvoicePackingImport> sheet2Data = FastExcelUtil.readExcelData(file, InvoicePackingImport.class, 1, 5); List<InvoicePackingImport> sheet2Data = FastExcelUtil.readExcelData(file, InvoicePackingImport.class, readSheets.get(1).getSheetNo(), 5);
//发票箱单数据处理 //发票箱单数据处理
List<BaseImport> dataList = invoicePackingDataProcess(invoiceNo, sheet1Data,sheet2Data); List<BaseImport> dataList = invoicePackingDataProcess(invoiceNo, sheet1Data, sheet2Data);
//批量导入 //批量导入
importAsnData(dataList); importAsnData(dataList);
@ -239,41 +237,56 @@ public class ImportAsnServiceImpl implements ImportAsnService {
} }
//验证模板是否使用正确 //验证模板是否使用正确
private void isValidTemplateType(MultipartFile file, String templateType) { private List<ReadSheet> isValidTemplateType(MultipartFile file, String templateType) {
// 根据模板类型进行不同的处理 // 根据模板类型进行不同的处理
if ("template1".equals(templateType)) { if ("template1".equals(templateType)) {
List<ReadSheet> readSheets = FastExcelUtil.readSheets(file);
if (readSheets.size() != 1) {
throw new BadRequestException("标准导入模板中只能包含1个sheet目录");
}
List<String> requiredColumns = Arrays.asList("INVOICE NO.", "BOI", "PO&LN NO.", "PART NO.", "DESCRIPTION", "Q'TY \n" + "(PCS)", "C/NO."); List<String> requiredColumns = Arrays.asList("INVOICE NO.", "BOI", "PO&LN NO.", "PART NO.", "DESCRIPTION", "Q'TY \n" + "(PCS)", "C/NO.");
List<String> headers = FastExcelUtil.readHeadContent(file, requiredColumns, 0, 0); List<String> headers = FastExcelUtil.readHeadContent(file, readSheets.get(0).getSheetNo(), 0);
if (!SmartStringUtil.containsAllIgnoreCase(requiredColumns, headers)) { if (!SmartStringUtil.containsAllIgnoreCase(requiredColumns, headers)) {
throw new BadRequestException("标准导入模板不正确,请确认模板信息"); throw new BadRequestException("标准导入模板不正确,请确认模板信息");
} }
} else if ("template2".equals(templateType)){ return readSheets;
} else if ("template2".equals(templateType)) {
List<ReadSheet> readSheets = FastExcelUtil.readSheets(file);
if (readSheets.size() != 2) {
throw new BadRequestException("大物导入模板中只能包含2个sheet目录");
}
List<String> requiredColumns = Arrays.asList("BOI", "PO&LN NO.", "PART NO.", "DESCRIPTION", "Q'TY \n" + "(PCS)"); List<String> requiredColumns = Arrays.asList("BOI", "PO&LN NO.", "PART NO.", "DESCRIPTION", "Q'TY \n" + "(PCS)");
List<String> sheet1Headers = FastExcelUtil.readHeadContent(file, requiredColumns, 0, 20); List<String> sheet1Headers = FastExcelUtil.readHeadContent(file, readSheets.get(0).getSheetNo(), 20);
if (!SmartStringUtil.containsAllIgnoreCase(requiredColumns, sheet1Headers)) { if (!SmartStringUtil.containsAllIgnoreCase(requiredColumns, sheet1Headers)) {
throw new BadRequestException("大物第1个Sheet目录模板不正确,请确认模板信息"); throw new BadRequestException("大物第1个Sheet目录模板不正确,请确认模板信息");
} }
List<String> requiredColumns2 = Collections.singletonList("C/NO."); List<String> requiredColumns2 = Collections.singletonList("C/NO.");
List<String> sheet2Headers = FastExcelUtil.readHeadContent(file, requiredColumns2, 1, 20); List<String> sheet2Headers = FastExcelUtil.readHeadContent(file, readSheets.get(1).getSheetNo(), 20);
if (!SmartStringUtil.containsAllIgnoreCase(requiredColumns2, sheet2Headers)) { if (!SmartStringUtil.containsAllIgnoreCase(requiredColumns2, sheet2Headers)) {
throw new BadRequestException("大物第2个Sheet目录模板不正确,请确认模板信息"); throw new BadRequestException("大物第2个Sheet目录模板不正确,请确认模板信息");
} }
return readSheets;
} else if ("template3".equals(templateType)) { } else if ("template3".equals(templateType)) {
List<ReadSheet> readSheets = FastExcelUtil.readSheets(file);
if (readSheets.size() != 2) {
throw new BadRequestException("发票箱单模板中只能包含2个sheet目录");
}
List<String> requiredColumns = Collections.singletonList("(BOI)"); List<String> requiredColumns = Collections.singletonList("(BOI)");
List<String> headers = FastExcelUtil.readHeadContent(file, requiredColumns, 0, 23); List<String> headers = FastExcelUtil.readHeadContent(file, readSheets.get(0).getSheetNo(), 23);
if (!SmartStringUtil.containsAllIgnoreCase(requiredColumns, headers)) { if (!SmartStringUtil.containsAllIgnoreCase(requiredColumns, headers)) {
throw new BadRequestException("发票箱单第1个Sheet目录模板不正确,请确认模板信息"); throw new BadRequestException("发票箱单第1个Sheet目录模板不正确,请确认模板信息");
} }
List<String> requiredColumns2 = Arrays.asList("A-PROS\n" + "CASE NO", "KMT NO. PO&LN NO.", "PART NO.", "DESCRIPTION", "Q'TY"); List<String> requiredColumns2 = Arrays.asList("A-PROS\n" + "CASE NO", "KMT NO. PO&LN NO.", "PART NO.", "DESCRIPTION", "Q'TY");
List<String> headers2 = FastExcelUtil.readHeadContent(file, requiredColumns2, 1, 4); List<String> headers2 = FastExcelUtil.readHeadContent(file, readSheets.get(1).getSheetNo(), 4);
if (!SmartStringUtil.containsAllIgnoreCase(requiredColumns2, headers2)) { if (!SmartStringUtil.containsAllIgnoreCase(requiredColumns2, headers2)) {
throw new BadRequestException("发票箱单第2个Sheet目录模板不正确,请确认模板信息"); throw new BadRequestException("发票箱单第2个Sheet目录模板不正确,请确认模板信息");
} }
return readSheets;
} else {
throw new BadRequestException("模板类型错误");
} }
} }

View File

@ -322,7 +322,7 @@ public class ImportBomAccountServiceImpl implements ImportBomAccountService {
"组顺/刻印号前2位", "组顺/刻印号前2位",
"台用量" "台用量"
); );
List<String> headers = FastExcelUtil.readHeadContent(file, requiredColumns, 0, 0); List<String> headers = FastExcelUtil.readHeadContent(file, 0, 0);
if (!SmartStringUtil.containsAllIgnoreCase(requiredColumns, headers)) { if (!SmartStringUtil.containsAllIgnoreCase(requiredColumns, headers)) {
throw new BadRequestException("标准导入模板不正确,请确认模板信息"); throw new BadRequestException("标准导入模板不正确,请确认模板信息");
} }

View File

@ -111,7 +111,7 @@ public class ImportItemServiceImpl implements ImportItemService {
"高", "高",
"保管期限" "保管期限"
); );
List<String> headers = FastExcelUtil.readHeadContent(file, requiredColumns, 0, 0); List<String> headers = FastExcelUtil.readHeadContent(file, 0, 0);
if (!SmartStringUtil.containsAllIgnoreCase(requiredColumns, headers)) { if (!SmartStringUtil.containsAllIgnoreCase(requiredColumns, headers)) {
throw new BadRequestException("标准导入模板不正确,请确认模板信息"); throw new BadRequestException("标准导入模板不正确,请确认模板信息");
} }

View File

@ -127,7 +127,7 @@ public class ImportPointServiceImpl implements ImportPointService {
"纳所", "纳所",
"标签类型" "标签类型"
); );
List<String> headers = FastExcelUtil.readHeadContent(file, requiredColumns, 0, 0); List<String> headers = FastExcelUtil.readHeadContent(file, 0, 0);
if (!SmartStringUtil.containsAllIgnoreCase(requiredColumns, headers)) { if (!SmartStringUtil.containsAllIgnoreCase(requiredColumns, headers)) {
throw new BadRequestException("标准导入模板不正确,请确认模板信息"); throw new BadRequestException("标准导入模板不正确,请确认模板信息");
} }

View File

@ -2,42 +2,45 @@ package com.youchain.utils;
import cn.idev.excel.context.AnalysisContext; import cn.idev.excel.context.AnalysisContext;
import cn.idev.excel.read.listener.ReadListener; import cn.idev.excel.read.listener.ReadListener;
import com.youchain.exception.BadRequestException;
import java.util.HashMap; import java.util.*;
import java.util.HashSet; import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;
import java.util.Set;
public class FastExcelCellListener implements ReadListener<Map<Integer, String>> { public class FastExcelCellListener implements ReadListener<Map<Integer, String>> {
private final Map<String, String> cellValues = new HashMap<>(); private final Map<CellPosition, String> cellValues = new ConcurrentHashMap<>();
private final Set<String> targetCells = new HashSet<>(); private final Set<CellPosition> targetCells = new HashSet<>();
private boolean isCellRead = false; private volatile boolean allCellsRead = false;
/** /**
* *
* @param row 0 *
* @param col 0 * @param row 1Excel
* @param col 1Excel
* @return * @return
*/ */
public FastExcelCellListener addTargetCell(int row, int col) { public FastExcelCellListener addTargetCell(int row, int col) {
targetCells.add(row + "-" + col); if (row < 1 || col < 1) {
throw new BadRequestException("行列索引必须从1开始");
}
targetCells.add(new CellPosition(row, col));
return this; return this;
} }
@Override @Override
public void invoke(Map<Integer, String> data, AnalysisContext context) { public void invoke(Map<Integer, String> rowData, AnalysisContext context) {
if (isCellRead) { // 如果所有目标单元格已读取完毕,直接返回
if (allCellsRead) {
return; return;
} }
int currentRowIndex = context.readRowHolder().getRowIndex()-1; // EasyExcel 的行索引从0开始转换为Excel格式从1开始
int currentRowIndex = context.readRowHolder().getRowIndex() + 1;
for (String targetCell : targetCells) { // 检查当前行是否包含目标单元格
String[] parts = targetCell.split("-"); for (CellPosition targetCell : targetCells) {
int targetRow = Integer.parseInt(parts[0]); if (currentRowIndex == targetCell.row) {
int targetCol = Integer.parseInt(parts[1]); // 列索引需要减1转换为0-based
String cellValue = rowData.get(targetCell.col - 1);
if (currentRowIndex == targetRow-1) {
String cellValue = data.get(targetCol-1);
if (cellValue != null) { if (cellValue != null) {
cellValues.put(targetCell, cellValue); cellValues.put(targetCell, cellValue);
} }
@ -46,7 +49,7 @@ public class FastExcelCellListener implements ReadListener<Map<Integer, String>>
// 检查是否所有目标单元格都已读取 // 检查是否所有目标单元格都已读取
if (cellValues.size() == targetCells.size()) { if (cellValues.size() == targetCells.size()) {
isCellRead = true; allCellsRead = true;
} }
} }
@ -57,19 +60,56 @@ public class FastExcelCellListener implements ReadListener<Map<Integer, String>>
/** /**
* *
* @param row 0 *
* @param col 0 * @param row 1Excel
* @return * @param col 1Excel
* @return null
*/ */
public String getCellValue(int row, int col) { public String getCellValue(int row, int col) {
return cellValues.get(row + "-" + col); return cellValues.get(new CellPosition(row, col));
} }
/** /**
* * key
* @return Map *
* @return Mapkey"row-col"
*/ */
public Map<String, String> getAllCellValues() { public Map<String, String> getAllCellValues() {
return new HashMap<>(cellValues); Map<String, String> result = new HashMap<>();
cellValues.forEach((pos, value) ->
result.put(pos.row + "-" + pos.col, value));
return result;
} }
/**
*
*/
public static class CellPosition {
private final int row;
private final int col;
public CellPosition(int row, int col) {
this.row = row;
this.col = col;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CellPosition that = (CellPosition) o;
return row == that.row && col == that.col;
}
@Override
public int hashCode() {
return Objects.hash(row, col);
}
@Override
public String toString() {
return "(" + row + "," + col + ")";
}
}
} }

View File

@ -1,7 +1,9 @@
package com.youchain.utils; package com.youchain.utils;
import cn.idev.excel.ExcelReader;
import cn.idev.excel.ExcelWriter; import cn.idev.excel.ExcelWriter;
import cn.idev.excel.FastExcel; import cn.idev.excel.FastExcel;
import cn.idev.excel.read.metadata.ReadSheet;
import cn.idev.excel.write.metadata.WriteSheet; import cn.idev.excel.write.metadata.WriteSheet;
import cn.idev.excel.write.metadata.style.WriteCellStyle; import cn.idev.excel.write.metadata.style.WriteCellStyle;
import cn.idev.excel.write.metadata.style.WriteFont; import cn.idev.excel.write.metadata.style.WriteFont;
@ -12,13 +14,14 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.IndexedColors; import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.MediaTypeFactory; import org.springframework.http.MediaTypeFactory;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
@ -170,7 +173,7 @@ public class FastExcelUtil {
} }
public static List<Map<Integer, Object>> readExcelData2(MultipartFile file, int headRowNumber) { public static List<Map<Integer, Object>> readExcelData2(MultipartFile file, int headRowNumber) {
try { try {
return FastExcel.read(file.getInputStream()) return FastExcel.read(file.getInputStream())
.sheet() .sheet()
@ -188,10 +191,10 @@ public class FastExcelUtil {
* @param file Excel * @param file Excel
* @param reader * @param reader
*/ */
public static Map<String, String> readExcelCellValues(MultipartFile file, FastExcelCellListener reader) { public static Map<String, String> readExcelCellValues(MultipartFile file, FastExcelCellListener reader, int sheetNo) {
try { try {
FastExcel.read(file.getInputStream(), reader) FastExcel.read(file.getInputStream(), reader)
.sheet() .sheet(sheetNo)
.doReadSync(); .doReadSync();
} catch (IOException e) { } catch (IOException e) {
throw new BadRequestException("数据格式存在问题,无法读取"); throw new BadRequestException("数据格式存在问题,无法读取");
@ -230,13 +233,9 @@ public class FastExcelUtil {
/** /**
* Excel * Excel
* *
* @param requiredColumns
* @return true * @return true
*/ */
public static List<String> readHeadContent(MultipartFile file, List<String> requiredColumns, int sheetNo, int headRowNumber) { public static List<String> readHeadContent(MultipartFile file, int sheetNo, int headRowNumber) {
if (requiredColumns.isEmpty()) {
return Collections.emptyList();
}
try { try {
//判断头部内容是否包含所有必填列 //判断头部内容是否包含所有必填列
return readHeadContent(file.getInputStream(), sheetNo, headRowNumber); return readHeadContent(file.getInputStream(), sheetNo, headRowNumber);
@ -245,8 +244,48 @@ public class FastExcelUtil {
} }
} }
private static String readHeadContent(File file, int headRowNumber) { public static List<ReadSheet> readSheets(MultipartFile file) {
return ""; try (ExcelReader excelReader = FastExcel.read(file.getInputStream()).build()) {
// 获取所有Sheet
List<ReadSheet> allSheets = excelReader.excelExecutor().sheetList();
// 使用 POI 检测隐的sheet
Set<String> hiddenSheetNames = getHiddenSheetNames(file);
//过滤隐藏的sheet
return allSheets.stream()
.filter(sheet -> !hiddenSheetNames.contains(sheet.getSheetName()))
.collect(Collectors.toList());
} catch (IOException e) {
log.error("读取Excel Sheet信息失败", e);
throw new BadRequestException("读取Excel Sheet信息失败");
}
}
/**
* Sheet
*
* @param file
*/
private static Set<String> getHiddenSheetNames(MultipartFile file) {
Set<String> hiddenSheets = new HashSet<>();
try (InputStream inputStream = file.getInputStream();
Workbook workbook = WorkbookFactory.create(inputStream)) {
int numberOfSheets = workbook.getNumberOfSheets();
for (int i = 0; i < numberOfSheets; i++) {
if (workbook.isSheetHidden(i) || workbook.isSheetVeryHidden(i)) {
String sheetName = workbook.getSheetName(i);
hiddenSheets.add(sheetName);
}
}
} catch (Exception e) {
throw new BadRequestException("获取隐藏的Sheet名称失败");
}
return hiddenSheets;
} }