文件导入改善

This commit is contained in:
lym
2025-01-07 14:21:29 +08:00
parent 87bd765361
commit 376af44963
15 changed files with 919 additions and 674 deletions
@@ -152,6 +152,31 @@
<artifactId>podam</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.monitorjbl/xlsx-streamer -->
<dependency>
<groupId>com.monitorjbl</groupId>
<artifactId>xlsx-streamer</artifactId>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
</dependency>
<dependency>
<groupId>javax.xml.stream</groupId>
<artifactId>stax-api</artifactId>
</dependency>
<!-- JSON -->
<dependency>
<groupId>com.alibaba</groupId>
@@ -24,10 +24,9 @@ import com.cf.imes.module.executor.service.order.OrderService;
import com.cf.imes.module.executor.util.ExcelWriterUtil;
import com.cf.imes.module.executor.util.fileConversion.admin.api.webcad.ApiDataAchieve;
import com.cf.imes.module.executor.util.fileConversion.admin.api.webcad.ApiTypeRealize;
import com.cf.imes.module.executor.util.fileConversion.admin.files.excel.ExcelReadUtil;
import com.cf.imes.module.executor.util.fileConversion.admin.files.excel.ExcelTypeRealize;
import com.cf.imes.module.executor.util.fileConversion.admin.files.excel.OrderPlateImportExcelVO;
import com.cf.imes.module.executor.util.fileConversion.admin.files.excel.*;
import com.cf.imes.module.executor.util.fileConversion.admin.files.xml.VO.OrderXmlVO;
import com.cf.imes.module.executor.util.fileConversion.admin.files.xml.VO.XmlCheckVO;
import com.cf.imes.module.executor.util.fileConversion.admin.files.xml.XMLUtil;
import com.cf.imes.module.executor.util.fileConversion.admin.files.xml.XmlBuilder;
import com.cf.imes.module.executor.util.fileConversion.admin.files.xml.XmlTypeRealize;
@@ -72,7 +71,10 @@ public class OrderController {
private OrderMapper orderMapper;
@Resource
private ExcelReadUtil excelReadUtil;
private LargeFilesUtils largeFilesUtils;
@Resource
private ExcelCheckListUtil excelCheckListUtil;
@Resource
private ApiDataAchieve apiDataAchieve;
@@ -256,10 +258,10 @@ public class OrderController {
Map<String, Object> listMap = null;
OrderDO orderDO = null;
Map<String, Object> mapOrder = null;
Map<String, String> mapOrder = null;
Boolean flag = true;
String customOrderNoKey = "自定义单号";
boolean isLocked = redisLockUtil.lock(lockKey);
if (!isLocked) {
log.error(errKey, errValue);
@@ -267,45 +269,39 @@ public class OrderController {
} else {
try {
if (type == 0) { //excel
excelReadUtil.setErr(0);
Map<String, Object> map = excelReadUtil.read(file);
list = (List<OrderPlateImportExcelVO>) map.get("plate");
mapOrder = (Map<String, Object>) map.get("orderPri");
List<OrderPlateImportExcelVO>[] listBoth = largeFilesUtils.importExcelLargeFile(file);// 表头+列表
list = listBoth[1];// 列表
mapOrder = largeFilesUtils.changeToOrderMap(listBoth[0]); // 表头
if (index == 0) { // 全部
if (mapOrder != null) {
Map<String, Object> mapChange = excelReadUtil.changeOrderDO(mapOrder);
mapOrder = (Map<String, Object>) mapChange.get("file");
orderDO = (OrderDO) mapChange.get("order");
orderDO.setId((Long) snowFlakeGenerator.nextId(null));
AtomicBoolean error = (AtomicBoolean) mapChange.get("error");
flag = error.get();
}
} else {
ExcelCheckVO excelCheckVO = excelCheckListUtil.checkExcelList(mapOrder); // 表头验证
orderDO = excelCheckVO.getOrderDO();
orderDO.setId((Long) snowFlakeGenerator.nextId(null));
flag = excelCheckVO.getFlag();
} else { // 补板
orderDO = orderService.getOrder(orderId);
if (orderDO == null) {
mapOrder = new HashMap<>();
mapOrder.put("自定义单号", "生产单号不存在");
mapOrder.put(ProduceExcelConstants.ORDER_CUSTOM_ORDER_NO, "---< 生产单号不存在 >---");
flag = false;
}
}
if (mapOrder == null) {
mapOrder = new HashMap<>();
mapOrder.put(customOrderNoKey, "生产单内容解析为空");
String customOrderNo = mapOrder.get(ProduceExcelConstants.ORDER_CUSTOM_ORDER_NO);
if (index == 0 && customOrderNo != null && !orderService.customOrderNoIsExists(customOrderNo)) {
mapOrder.put(ProduceExcelConstants.ORDER_CUSTOM_ORDER_NO, customOrderNo + "重复");
flag = false;
}else if (orderDO == null) {
mapOrder.put(customOrderNoKey, "生产单内为空");
flag = false;
} else if (index == 0 && orderDO.getCustomOrderNo() != null && !orderService.customOrderNoIsExists(orderDO.getCustomOrderNo())) {
mapOrder.put(customOrderNoKey, mapOrder.get(customOrderNoKey) + customOrderNoKey + "重复");
flag = false;
} else if ( excelReadUtil.isErr() > 0 ){
flag = false;
} else if ( excelReadUtil.isErr() == 0 && flag ){
if (list.size() == 0) {
}
if (flag){
// list 校验
ExcelCheckVO excelCheckVO = excelCheckListUtil.checkExcelLargeFile(listBoth[1]);
list = excelCheckVO.getList();
flag = excelCheckVO.getFlag() & flag;
if (excelCheckVO.getFlag() && excelCheckVO.getList().size() == 0) {
orderDO.setStatus(OrderStatusEnum.EMPTY.getStatus());
} else {
} else if (excelCheckVO.getFlag()){
orderDO.setStatus(OrderStatusEnum.NEW_ORDER.getStatus());
listMap = excelTypeRealize.changeDate(list, orderDO.getId());
}
@@ -321,10 +317,10 @@ public class OrderController {
if (index == 0){
if (orderXmlVO != null) {
mapOrder = xmlUtil.changeDate(orderXmlVO, getUserOrganId()); // 生产单数据格式验证
orderDO = (OrderDO) mapOrder.get("order");
XmlCheckVO xmlCheckVO = xmlUtil.changeDate(orderXmlVO, getUserOrganId()); // 生产单数据格式验证
orderDO = xmlCheckVO.getOrderDO();
orderDO.setId((Long) snowFlakeGenerator.nextId(null));
flag = (Boolean) mapOrder.get("error");
flag = xmlCheckVO.getFlag();
}
} else {
orderDO = orderService.getOrder(orderId);
@@ -377,13 +373,16 @@ public class OrderController {
String xmlStr = XmlBuilder.objectToXmlStr(orderXmlVO);
XMLUtil.writeErr(response, xmlStr, " order_add_xml_err.xml");
}
} finally {
// 进行判断,为空,写入时出现了错误,数据库数据回滚,此时删除 ES 里的数据
OrderDO order = orderMapper.selectById(orderDO.getId());
if (order == null) {
orderInputProcessor.deleteByOrderId(orderDO.getId(), ORDER_PLATE_MODEL);
orderInputProcessor.deleteByOrderId(orderDO.getId(), ORDER_PLATE_MODEL_COMPRESS);
}
} finally {
redisLockUtil.unlock(lockKey);
}
}
@@ -520,9 +520,7 @@ public class OrderServiceImpl implements OrderService {
if (plateDetail != null && !plateDetail.isEmpty()){
List<OrderModelDO> orderModelDOs = BeanUtils.toBean(plateDetail, OrderModelDO.class);
orderInputProcessor.batchSaveModel(orderModelDOs);
// if (!orderModelDOs.isEmpty()) {
// orderModelDOs.forEach(orderModelDO -> orderModelDO.setOrderId(orderDO.getId()));
// System.out.println("----" + orderModelDOs);
// 将生产单板材的造型信息进行压缩并保存
OrderModelCompressDO orderModelCompressDO = new OrderModelCompressDO();
orderModelCompressDO.setOrderId(orderDO.getId());
@@ -763,7 +761,7 @@ public class OrderServiceImpl implements OrderService {
List<PartsDO> partsDOS = new ArrayList<>();
for (OrderPartsDO partsDO : partsLists) {
if (partsDO.getGoodsId() != null) { // 有goodsId
if (partsDO.getGoodsId() != null && !partsDO.getGoodsId().isEmpty()) { // 有goodsId
PartsDO part = partsMapper.selectByGoodID(partsDO.getGoodsId(), OrganContextHolder.getOrganId());
if (part == null) { // 不存在记录,存入数据库
partsDOS.add(BeanUtils.toBean(partsDO, PartsDO.class).setOrganId(OrganContextHolder.getOrganId()));
@@ -27,7 +27,7 @@ public class ExcelWriterUtil {
// 写excel
public static void write(HttpServletResponse response,
Map<String, Object> orderMap,
Map<String, String> orderMap,
List<OrderPlateImportExcelVO> list,
String filePathErr) {
ServletOutputStream outputStream = null;
@@ -44,20 +44,7 @@ public class ExcelWriterUtil {
//开启自动换行,自动换行表示每次写入一条list数据是都会重新生成一行空行,此选项默认是关闭的,需要提前设置为true
FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
//准备单组和数据
Map<String, String> map = new HashMap<>();
map.put("customOrderNo", (String) orderMap.get("自定义单号"));
map.put("customer", (String) orderMap.get("客户"));
map.put("address", (String) orderMap.get("客户地址"));
map.put("phoneNumber", (String) orderMap.get("客户电话"));
map.put("remark", (String) orderMap.get("备注"));
map.put("splitter", (String) orderMap.get("拆单员"));
map.put("salesman", (String) orderMap.get("业务员"));
map.put("dealerPhoneNumber", (String) orderMap.get("经销商电话"));
map.put("dealer", (String) orderMap.get("经销商"));
map.put("deliveryDate", (String) orderMap.get("出货日期"));
excelWriter.fill(map, writeSheet);
excelWriter.fill(orderMap, writeSheet);
//列表
excelWriter.fill(list, fillConfig, writeSheet);
@@ -1,5 +1,6 @@
package com.cf.imes.module.executor.util.fileConversion.admin;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
@@ -110,4 +111,27 @@ public class ToolUtil {
return true;
}
// 判断对象是否全为空或是null,进行去除
/**
* 检查给定的对象的所有字段是否为空或 null。
* @param obj 要检查的对象。
* @return 如果所有字段都是空或 null,则返回 true;否则返回 false。
*/
public static boolean isAllFieldsEmptyOrNull(Object obj) {
if (obj == null) return true;
Class<?> clazz = obj.getClass();
for (Field field : clazz.getDeclaredFields()) {
field.setAccessible(true);
try {
Object value = field.get(obj);
if (value != null && !(value instanceof String && ((String)value).trim().isEmpty())) {
return false;
}
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
return true;
}
}
@@ -0,0 +1,393 @@
package com.cf.imes.module.executor.util.fileConversion.admin.files.excel;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.nacos.common.utils.StringUtils;
import com.cf.imes.framework.organ.core.context.OrganContextHolder;
import com.cf.imes.module.executor.dal.dataobject.order.OrderDO;
import com.cf.imes.module.executor.enums.*;
import com.cf.imes.module.executor.util.fileConversion.admin.ToolUtil;
import com.cf.imes.module.system.api.dict.DictDataApi;
import com.cf.imes.module.system.api.dict.dto.DictDataRespDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Excel文件数据校验器
*/
@Slf4j
@Component
public class ExcelCheckListUtil {
@Resource
private DictDataApi dictDataApi;
private static final String ERR = "error";
private static final String DEALER_PHONE = "dealerPhoneNumber";
private static final String NUMBER_TYPE_ERR = "数量类型错误";
private static final String NOT_EMPTY= "不可为空";
private static final String NUMBER_ERR = "数量错误";
private static final String ACCORD_ENUM = "请按照提示词语选择填入";
private static final String POSITIVE_ERR = "数据需为正数";
private static final String NUMBER_LENGTH_ERR = "数据长度过长";
// 校验文件订单数据, 当有错时返回Map<String,String>,当数据完全正确时,返回OrderDO
public ExcelCheckVO checkExcelList(Map<String, String> orderMap) {
AtomicBoolean error = new AtomicBoolean(true);
// 非空判断
setIfInvalid(ProduceExcelConstants.ORDER_CUSTOMER, "---< 客户不能为空 >---", orderMap, 255, error);
setIfInvalid(ProduceExcelConstants.ORDER_SALESMAN, "---< 经销商不能为空 >---", orderMap, 255, error);
setIfInvalid(ProduceExcelConstants.ORDER_ADDRESS, "---< 客户地址不能为空 >---", orderMap, 255, error);
setIfInvalid(ProduceExcelConstants.ORDER_ADDRESS, "---< 客户地址不能为空 >---", orderMap, 255, error);
if (orderMap.get(ProduceExcelConstants.ORDER_PHONE_NUMBER) == null) {
orderMap.put(ProduceExcelConstants.ORDER_PHONE_NUMBER, "---< 客户电话不能为空 >---");
error.set(false);
} else {
setPhone(ProduceExcelConstants.ORDER_PHONE_NUMBER, "---< 客户电话格式错误 >---", orderMap, error);
}
if (orderMap.get(ProduceExcelConstants.ORDER_DEALER_PHONE_NUMBER) != null) {
setPhone(ProduceExcelConstants.ORDER_DEALER_PHONE_NUMBER, "---< 经销商电话格式错误 >---", orderMap, error);
}
LocalDate deliverDate = null;
if (orderMap.get(ProduceExcelConstants.ORDER_DELIVERY_DATE) == null) {
orderMap.put(ProduceExcelConstants.ORDER_DELIVERY_DATE, "---< 出货日期不能为空 >---");
error.set(false);
} else {
String s = orderMap.get(ProduceExcelConstants.ORDER_DELIVERY_DATE);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
Map<String, Object> mapDate = ToolUtil.changeDate(s, formatter);
if (mapDate.get(ERR) instanceof Integer && (Integer) mapDate.get(ERR) == -1) {
orderMap.put(ProduceExcelConstants.ORDER_DELIVERY_DATE, s + "---< 出货日期格式错误 >---");
error.set(false);
} else {
deliverDate = (LocalDate) mapDate.get("date");
if (deliverDate.isBefore(LocalDate.now())) {
deliverDate = LocalDate.now().plus(30, ChronoUnit.DAYS);
}
}
}
OrderDO orderDO = new OrderDO();
if (error.get()) {
orderDO = OrderDO.builder()
.organId(OrganContextHolder.getOrganId())
.dataType(DataTypeEnum.FILE_IMPORT.getStatus())
.orderDate(LocalDateTime.now())
.customer(ProduceExcelConstants.ORDER_CUSTOMER)
.customOrderNo(orderMap.get(ProduceExcelConstants.ORDER_CUSTOM_ORDER_NO))
.dealer(orderMap.get(ProduceExcelConstants.ORDER_DEALER))
.dealerPhoneNumber(orderMap.get(ProduceExcelConstants.ORDER_DEALER_PHONE_NUMBER))
.address(orderMap.get(ProduceExcelConstants.ORDER_CUSTOMER))
.phoneNumber(orderMap.get(ProduceExcelConstants.ORDER_PHONE_NUMBER))
.salesman(orderMap.get(ProduceExcelConstants.ORDER_SALESMAN))
.splitter(orderMap.get(ProduceExcelConstants.ORDER_SPLITTER))
.deliveryDate(deliverDate.atStartOfDay())
.orderType(OrderTypeEnum.MAIN_ORDER.getStatus())
.remark(orderMap.get(ProduceExcelConstants.ORDER_REMARK))
.build();
}
return new ExcelCheckVO().setFlag(error.get()).setOrderDO(orderDO).setMapOder(orderMap);
}
// order生产单校验电话号码
private void setPhone(String key, String errValue, Map<String, String> orderMap, AtomicBoolean error) {
if (!ToolUtil.validatePhoneNumber(orderMap.get(key))) {
orderMap.put(key, orderMap.get(key) + errValue);
error.set(false);
}
}
private void setIfInvalid(String key, String errValue, Map<String, String> orderMap, int length, AtomicBoolean error) {
orderMap.compute(key, (k, v) -> {
if (v == null) {
error.set(false);
return errValue;
} else {
int size = (v).length();
if (size > length) {
error.set(false);
return NUMBER_LENGTH_ERR;
}
}
return v;
});
}
// 校验文件生产数据
public ExcelCheckVO checkExcelLargeFile(List<OrderPlateImportExcelVO> list) {
List<OrderPlateImportExcelVO> resultList = new ArrayList<>();
// 100条一分,确定分片多少
int batchSize = 100;
int batchCount = (list.size() + batchSize - 1) / batchSize;
List<CompletableFuture<List<OrderPlateImportExcelVO>>> futures = new ArrayList<>();
AtomicBoolean flag = new AtomicBoolean(true);
// 遍历分片
for (int i = 0; i < batchCount; i++) {
int start = i * batchSize;
int end = Math.min(start + batchSize, list.size());
List<OrderPlateImportExcelVO> subList = list.subList(start, end);
CompletableFuture<List<OrderPlateImportExcelVO>> future = CompletableFuture.supplyAsync(() -> checkData(subList, flag));
futures.add(future);
}
// 等待所有异步操作完成,并收集结果
CompletableFuture.allOf(futures.toArray(new CompletableFuture[batchCount])).join();
for (CompletableFuture<List<OrderPlateImportExcelVO>> future : futures) {
try {
List<OrderPlateImportExcelVO> result = future.get(); // 获取每个任务的结果
resultList.addAll(result);
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
return new ExcelCheckVO().setFlag(flag.get()).setList(resultList);
}
// List数据校验
private List<OrderPlateImportExcelVO> checkData(List<OrderPlateImportExcelVO> list, AtomicBoolean flag) {
for (OrderPlateImportExcelVO vo : list) {
List<String> errList = new ArrayList<>();
// 全部需要值的字段
// 检查非空 类型、数量
isEmpty(vo.getGoodType(), errList, "类型",32, flag);
isEmpty(vo.getGoodsNumber(), errList, "数量", 10000000 ,flag);
// 检查商品物料编码或是商品名称、规格、材质、颜色不可全为空
if (StringUtils.isEmpty(vo.getGoodsName()) || StringUtils.isEmpty(vo.getSpec())
|| StringUtils.isEmpty(vo.getMaterial()) || StringUtils.isEmpty(vo.getColor()) || StringUtils.isEmpty(vo.getUnit())) {
errList.add("商品商品名称、规格、材质、颜色、单位不可为空");
flag.set(false);
}
if (StringUtils.equals(vo.getGoodType(), "配件")) {
// 复合部件必填
isNotEmptyAndBack(vo.getIsComposite(), QuarrelEnum.class, errList, "是否复合部件", 1, flag); // 判断传入的值,是否符合字典中的枚举类
// 配件类型必填
isNotEmptyAndBack(vo.getCategory(), CategoryEnum.class, errList, "配件类型", 32, flag);
// 配件长宽厚,存在判断是否可以转义
isEmptyAndPositiveNumberSize(vo.getGoodsWidth(), Double.class, 5, 3, errList, "配件宽", flag);
isEmptyAndPositiveNumberSize(vo.getGoodsHeight(), Double.class, 5, 3, errList, "配件高", flag);
isEmptyAndPositiveNumberSize(vo.getGoodsThickness(), Double.class, 5, 3, errList, "配件厚", flag);
// 配件类型为封边条的时候,需要填写配件宽厚
if (StringUtils.equals(vo.getCategory(), CategoryEnum.EDGING.getValue())) { // 封边条必须有宽高
isNotEmptyAndBack(vo.getGoodsWidth(), errList, "封边条宽", flag);
isNotEmptyAndBack(vo.getGoodsThickness(), errList, "封边条厚", flag);
}
// 配件数量判断
isEmptyAndPositiveNumber(vo.getGoodsNumber(), Double.class, errList, "配件数量", flag);
}
// 若商品类型为板材,需检查房间、柜体、板名称、成品长、成品宽、拆单长、拆单宽、厚、左封边、右封边、上封边、下封边、排版面、纹路、开门方向不能为空
if (StringUtils.equals(vo.getGoodType(), "板材")) {
checkPlate(vo, errList, flag);
}
// if (!flag.get()) {
// isErr.getAndIncrement();
// }
JSONArray jsonArray = JSON.parseArray(JSON.toJSONString(errList));// 错误列表
vo.setResult(String.valueOf(jsonArray));
}
return list;
}
// 非空判断,错误填入
private void isEmpty(String value, List<String> errList, String errValue, int length, AtomicBoolean flag) {
if (StringUtils.isEmpty(value)) {
errList.add(errValue + NOT_EMPTY);
flag.set(false);
} else {
// 字符串长度检查
int size = value.length();
if (size > length) {
errList.add(errValue + NUMBER_LENGTH_ERR);
flag.set(false);
}
}
}
// 错误判断通用方法
// 判断非零,错误返回;不为空时,判断是否符合枚举类
private void isNotEmptyAndBack(String value, Class<? extends Enum<?>> enumClass, List<String> errList, String errValue, int length , AtomicBoolean flag) {
if (StringUtils.isEmpty(value)) {
errList.add(errValue + NOT_EMPTY);
flag.set(false);
} else {
isEmptyAndSize(value, length, errList, errValue, flag);
try {
// 获取枚举类的所有值
Enum<?>[] enums = enumClass.getEnumConstants();
boolean isValid = false;
for (Enum<?> enumValue : enums) {
Field valueField = enumValue.getClass().getDeclaredField("value");
valueField.setAccessible(true);
String enumValueStr = (String) valueField.get(enumValue);
if (enumValueStr.equals(value)) {
isValid = true;
break;
}
}
if (!isValid) {
errList.add(errValue + ACCORD_ENUM);
flag.set(false);
}
} catch (IllegalArgumentException e) {
errList.add(errValue + ACCORD_ENUM);
flag.set(false);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
// 非零判断,有值判断---判断数值类型,数值长度
private void isEmptyAndPositiveNumberSize(String value, Class<?> targetType, Integer length, Integer decimalLength, List<String> errList, String errValue, AtomicBoolean flag) {
if (StringUtils.isNotEmpty(value)) {
if (Boolean.TRUE.equals(ToolUtil.convertToType(value, targetType))) {
if (Boolean.TRUE.equals(ToolUtil.checkNumber(value))) {
if (!ToolUtil.checkPrecision(value, length, decimalLength)) {
errList.add(errValue + NUMBER_LENGTH_ERR);
flag.set(false);
}
} else {
errList.add(errValue + POSITIVE_ERR);
flag.set(false);
}
} else {
errList.add(errValue + NUMBER_TYPE_ERR);
flag.set(false);
}
}
}
// 判断非零,错误返回
private void isNotEmptyAndBack(String value, List<String> errList, String errValue, AtomicBoolean flag) {
if (StringUtils.isEmpty(value)) {
errList.add(errValue + NOT_EMPTY);
flag.set(false);
}
}
// 判断非空,有值判断字符串的长度
private void isEmptyAndSize(String value, Integer length, List<String> errList, String errValue, AtomicBoolean flag) {
if (StringUtils.isNotEmpty(value)) {
int size = value.length();
if (size > length) {
errList.add(errValue + NUMBER_LENGTH_ERR);
flag.set(false);
}
}
}
// 判断非空,大于零判断
public void isEmptyAndPositiveNumber(String value, Class<?> targetType, List<String> errList, String errValue, AtomicBoolean flag) {
if (StringUtils.isNotEmpty(value)) {
if (Boolean.FALSE.equals(ToolUtil.convertToType(value, targetType))) {
errList.add(errValue + NUMBER_TYPE_ERR);
flag.set(false);
}else {
if (Boolean.FALSE.equals(checkNumber(value))) {
errList.add(errValue + "数量不能为0");
flag.set(false);
}
}
}
}
// 板材的数据以及长度的检验
public void checkPlate(OrderPlateImportExcelVO vo, List<String> errList , AtomicBoolean flag) {
// 数量类型判断
isEmptyAndPositiveNumber(vo.getGoodsNumber(), Integer.class, errList, "板材数量", flag);
// 板材纹理
isNotEmptyAndBack(vo.getWave(), IsHavaeEnum.class, errList, "板材纹理", 4, flag);
// 大板的长宽厚存在以及是否符合数个
isNotEmptyAndBack(vo.getGoodsWidth(), errList, "板材长度", flag);
isEmptyAndPositiveNumberSize(vo.getGoodsWidth(), Double.class, 5, 3, errList, "板材长度", flag);
isNotEmptyAndBack(vo.getGoodsHeight(), errList, "板材宽度", flag);
isEmptyAndPositiveNumberSize(vo.getGoodsHeight(), Double.class, 5, 3, errList, "板材宽度", flag);
isNotEmptyAndBack(vo.getGoodsThickness(), errList, "板材厚度", flag);
isEmptyAndPositiveNumberSize(vo.getGoodsThickness(), Double.class, 5, 3, errList, "板材厚度", flag);
// 房间、柜体、板名称 不可以为空
isEmpty(vo.getRoomsName(), errList, "房间名称", 64, flag);
isEmpty(vo.getCabinetsName(), errList, "柜体名称", 64, flag);
isEmpty(vo.getName(), errList, "板材名称", 64, flag);
//成品长、成品宽、拆单长、拆单宽、厚、左封边、右封边、上封边、下封边 不能为空
isNotEmptyAndBack(vo.getHeight(), errList, "成品长度", flag);
isEmptyAndPositiveNumberSize(vo.getHeight(), Double.class, 5, 3, errList, "成品长度", flag);
isNotEmptyAndBack(vo.getWidth(), errList, "成品宽度", flag);
isEmptyAndPositiveNumberSize(vo.getWidth(), Double.class, 5, 3, errList, "成品宽度", flag);
isNotEmptyAndBack(vo.getSplitHeight(), errList, "拆单长度", flag);
isEmptyAndPositiveNumberSize(vo.getSplitHeight(), Double.class, 5, 3, errList, "拆单长度", flag);
isNotEmptyAndBack(vo.getSplitWidth(), errList, "拆单宽度", flag);
isEmptyAndPositiveNumberSize(vo.getSplitWidth(), Double.class, 5, 3, errList, "拆单宽度", flag);
isNotEmptyAndBack(vo.getThickness(), errList, "厚度", flag);
isEmptyAndPositiveNumberSize(vo.getThickness(), Double.class, 5, 3, errList, "厚度", flag);
isNotEmptyAndBack(vo.getSealLeft(), errList, "左封边", flag);
isEmptyAndPositiveNumberSize(vo.getSealLeft(), Double.class, 5, 3, errList, "左封边", flag);
isNotEmptyAndBack(vo.getSealRight(), errList, "右封边", flag);
isEmptyAndPositiveNumberSize(vo.getSealRight(), Double.class, 5, 3, errList, "右封边", flag);
isNotEmptyAndBack(vo.getSealUp(), errList, "上封边", flag);
isEmptyAndPositiveNumberSize(vo.getSealUp(), Double.class, 5, 3, errList, "上封边", flag);
isNotEmptyAndBack(vo.getSealDown(), errList, "下封边", flag);
isEmptyAndPositiveNumberSize(vo.getSealDown(), Double.class, 5, 3, errList, "下封边", flag);
// 排版面、纹路、开门方向
isNotEmptyAndDict(vo.getTypographicFace(), DictTypeConstants.TYPOGRAPHY_TYPE, errList, "排版面", flag);
isNotEmptyAndDict(vo.getTexture(), DictTypeConstants.GRAIN_TYPE, errList, "纹路", flag);
isNotEmptyAndDict(vo.getOpenDoorType(), DictTypeConstants.DOOR_OPENING_DIRECTIONS, errList, "开门方向", flag);
}
// 判断非空,字典值判断
public void isNotEmptyAndDict(String value, String dictType, List<String> errList, String errValue, AtomicBoolean flag) {
if (StringUtils.isEmpty(value)) {
errList.add(errValue + NOT_EMPTY);
flag.set(false);
} else {
DictDataRespDTO dictDataRespDTO = dictDataApi.parseDictData(dictType, value).getData();
if (dictDataRespDTO == null) {
errList.add(errValue + ACCORD_ENUM);
flag.set(false);
}
}
}
// 数量大小判断
public Boolean checkNumber(String numberStr) {
if (numberStr == null) {
return false;
}
if (Double.parseDouble(numberStr) <= 0) {
return false;
}
return true;
}
}
@@ -0,0 +1,32 @@
package com.cf.imes.module.executor.util.fileConversion.admin.files.excel;
import com.cf.imes.module.executor.dal.dataobject.order.OrderDO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.List;
import java.util.Map;
/**
* Excel 校验数据类型
*/
@Schema(description = "Excel 校验数据类型")
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ToString(callSuper = true)
public class ExcelCheckVO {
@Schema(description = "校验结果")
private Boolean flag;
@Schema(description = "校验结果数据")
private List<OrderPlateImportExcelVO> list;
@Schema(description = "订单信息")
private OrderDO orderDO;
@Schema(description = "订单信息")
private Map<String, String> mapOder;
}
@@ -1,45 +0,0 @@
package com.cf.imes.module.executor.util.fileConversion.admin.files.excel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.*;
@Slf4j
public final class ExcelListener extends AnalysisEventListener<Map<Integer, String>> {
/**
* 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收
*/
// private static final int BATCH_COUNT = 100;
// private List<Map<Integer, String>> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
private List<Map<Integer, String>> cachedDataList = new ArrayList<Map<Integer, String>>();
private boolean stopParsing = false; // 添加一个标志位用于控制是否停止解析数据
@Override
public void invoke(Map<Integer, String> data, AnalysisContext context) {
log.info("解析到一条数据: {}", JSON.toJSONString(data));
if (data.get(0) != null && data.get(0).equals("***")) {
log.info("遇到指定数据 ***, 停止写入!");
stopParsing = true;
}
if (!stopParsing) {
data.entrySet().removeIf(entry -> Objects.isNull(entry.getValue()));
cachedDataList.add(data);
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
log.info("所有数据解析完成!");
}
public List<Map<Integer, String>> getDataLists() {
return cachedDataList;
}
}
@@ -1,564 +0,0 @@
package com.cf.imes.module.executor.util.fileConversion.admin.files.excel;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.nacos.common.utils.StringUtils;
import com.cf.imes.framework.organ.core.context.OrganContextHolder;
import com.cf.imes.module.executor.dal.dataobject.order.OrderDO;
import com.cf.imes.module.executor.enums.*;
import com.cf.imes.module.executor.util.fileConversion.admin.ToolUtil;
import com.cf.imes.module.system.api.dict.DictDataApi;
import com.cf.imes.module.system.api.dict.dto.DictDataRespDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.*;
import java.lang.reflect.Field;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@Slf4j
@Component
public class ExcelReadUtil { // 文件读取
private AtomicInteger isErr = new AtomicInteger(0);
@Resource
private DictDataApi dictDataApi;
private static final String ERR = "error";
private static final String DEALER_PHONE = "dealerPhoneNumber";
private static final String NUMBER_TYPE_ERR = "数量类型错误";
private static final String NOT_EMPTY= "不可为空";
private static final String NUMBER_ERR = "数量错误";
private static final String ACCORD_ENUM = "请按照提示词语选择填入";
private static final String POSITIVE_ERR = "数据需为正数";
private static final String NUMBER_LENGTH_ERR = "数据长度过长";
// 读excel
public Map<String, Object> read(MultipartFile file) throws IOException {
Map<String, Object> map = new HashMap<>();
ExcelListener excelListener = new ExcelListener();
// 读文件
EasyExcelFactory.read(file.getInputStream(), excelListener).headRowNumber(-1).sheet().doRead();
Map<String, Object> orderMap = new HashMap<>();// order
List<Map<Integer, String>> dataLists = excelListener.getDataLists();// 读取的内容
List<OrderPlateImportExcelVO> list = new ArrayList<>();// plate
AtomicBoolean index = new AtomicBoolean(true);
AtomicInteger i = new AtomicInteger();
dataLists.forEach(
item -> {
if (item.get(0) != null){
if (item.get(0).equals("###")) {
index.set(false);
}
}
if (index.get()) {
orderMap.put(item.get(0), item.get(1));
orderMap.put(item.get(19), item.get(20));
i.getAndIncrement();
} else {
if (i.getAndIncrement() > 6){
list.add(changeValue(item));
}
}
}
);
index.set(true);
map.put("orderPri", orderMap);
map.put("plate", list);
return map;
}
//
private void setIfInvalid(String key, String errValue, Map<String, Object> orderMap,int length, AtomicBoolean error) {
orderMap.compute(key, (k, v) -> {
if (v == null) {
error.set(false);
return errValue;
} else {
int size = ((String) v).length();
if (size > length) {
error.set(false);
return NUMBER_LENGTH_ERR;
}
}
return v;
});
}
private void setPhone(String key, String errValue, Map<String, Object> orderMap, AtomicBoolean error) {
if (!ToolUtil.validatePhoneNumber((String) orderMap.get(key))) {
orderMap.put(key, orderMap.get(key) + errValue);
error.set(false);
}
}
// order 数据转换
public Map<String, Object> changeOrderDO(Map<String, Object> orderMap) {
Map<String, Object> map = new HashMap<>();
if (MapUtils.isEmpty(orderMap)) {
map.put(ERR, false);
return map;
}
AtomicBoolean error = new AtomicBoolean(true);
setIfInvalid("客户", "---< 客户不能为空 >---", orderMap, 255, error);
setIfInvalid("经销商", "---< 经销商不能为空 >---", orderMap, 255, error);
setIfInvalid("客户地址", "---< 客户地址不能为空 >---", orderMap, 255, error);
setIfInvalid("客户地址", "---< 客户地址不能为空 >---", orderMap, 255, error);
if (orderMap.get("客户电话") == null) {
orderMap.put("客户电话", "---< 客户电话不能为空 >---");
error.set(false);
} else {
setPhone("客户电话", "---< 客户电话格式错误 >---", orderMap, error);
}
if (orderMap.get(DEALER_PHONE) != null) {
setPhone(DEALER_PHONE, "---< 经销商电话格式错误 >---", orderMap, error);
}
LocalDate deliverDate = null;
if (orderMap.get("出货日期") == null) {
orderMap.put("出货日期", "---< 出货日期不能为空 >---");
error.set(false);
} else {
String s = (String) orderMap.get("出货日期");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
Map<String, Object> mapDate = ToolUtil.changeDate(s, formatter);
if (mapDate.get(ERR) instanceof Integer && (Integer) mapDate.get(ERR) == -1) {
orderMap.put("出货日期", s + "---< 出货日期格式错误 >---");
error.set(false);
} else {
deliverDate = (LocalDate) mapDate.get("date");
if (deliverDate.isBefore(LocalDate.now())) {
deliverDate = LocalDate.now().plus(30, ChronoUnit.DAYS);
}
}
}
OrderDO orderDO = new OrderDO();
if (error.get()) {
orderDO = OrderDO.builder()
.organId(OrganContextHolder.getOrganId())
.dataType(DataTypeEnum.FILE_IMPORT.getStatus())
.orderDate(LocalDateTime.now())
.customer((String) orderMap.get("客户"))
.customOrderNo((String) orderMap.get("自定义单号"))
.dealer((String) orderMap.get("经销商"))
.dealerPhoneNumber((String) orderMap.get(DEALER_PHONE))
.address((String) orderMap.get("客户地址"))
.phoneNumber((String) orderMap.get("客户电话"))
.salesman((String) orderMap.get("业务员"))
.splitter((String) orderMap.get("拆单员"))
.deliveryDate(deliverDate.atStartOfDay())
.orderType(OrderTypeEnum.MAIN_ORDER.getStatus())
.remark((String) orderMap.get("备注"))
.build();
}
map.put("order", orderDO);
map.put("file", orderMap);
map.put(ERR, error);
return map;
}
// 赋值单元格数据
private OrderPlateImportExcelVO changeValue(Map<Integer, String> dataMap) {
OrderPlateImportExcelVO vo = new OrderPlateImportExcelVO();
for (Map.Entry<Integer, String> entry : dataMap.entrySet()) {
Integer key = entry.getKey();
String value = entry.getValue();
switch (key) {
case 0:
vo.setOrdinal(value);
break;
case 1:// 类型
vo.setGoodType(value);
break;
case 2:// 物料编码
vo.setGoodsId(value);
break;
case 3:// 商品名称
vo.setGoodsName(value);
break;
case 4:// 材质
vo.setMaterial(value);
break;
case 5:// 纹理
vo.setWave(value);
break;
case 6:// 颜色
vo.setColor(value);
break;
case 7:// 复合部件
vo.setIsComposite(value);
break;
case 8:// 配件类型
vo.setCategory(value);
break;
case 9:// 子类
vo.setType(value);
break;
case 10:// 厂家
vo.setFactory(value);
break;
case 11:// 品牌
vo.setBrand(value);
break;
case 12:// 型号
vo.setModel(value);
break;
case 13:// 板材/配件长
vo.setGoodsHeight(value);
break;
case 14:// 板材/配件宽
vo.setGoodsWidth(value);
break;
case 15:// 板材/配件厚
vo.setGoodsThickness(value);
break;
case 16:// 规格
vo.setSpec(value);
break;
case 17:// 单位
vo.setUnit(value);
break;
case 18:// 数量
vo.setGoodsNumber(value);
break;
case 19:// 房间
vo.setRoomsName(value);
break;
case 20:// 柜体
vo.setCabinetsName(value);
break;
case 21:// 加工组类型
vo.setSynthesisTypeName(value);
break;
case 22:// 加工组名称
vo.setCombinationName(value);
break;
case 23://板名称
vo.setName(value);
break;
case 24:// 自定义板编号
vo.setPlateNo(value);
break;
case 25:// 成品长
vo.setHeight(value);
break;
case 26:// 成品宽
vo.setWidth(value);
break;
case 27:// 拆单长
vo.setSplitHeight(value);
break;
case 28:// 拆单宽
vo.setSplitWidth(value);
break;
case 29:// 厚
vo.setThickness(value);
break;
case 30:// 左封边
vo.setSealLeft(value);
break;
case 31:// 右封边
vo.setSealRight(value);
break;
case 32:// 上封边
vo.setSealUp(value);
break;
case 33:// 下封边
vo.setSealDown(value);
break;
case 34:// 排版面
vo.setTypographicFace(value);
break;
case 35:// 纹路
vo.setTexture(value);
break;
case 36:// 开门方向
vo.setOpenDoorType(value);
break;
case 37://备注1
vo.setRemark1(value);
break;
case 38://备注2
vo.setRemark2(value);
break;
case 39://备注3
vo.setRemark3(value);
break;
case 40://备注4
vo.setRemark4(value);
break;
case 41://备注5
vo.setRemark5(value);
break;
case 42://备注6
vo.setRemark6(value);
break;
case 43://备注7
vo.setRemark7(value);
break;
case 44://备注8
vo.setRemark8(value);
break;
case 45://备注9
vo.setRemark9(value);
break;
case 46://备注10
vo.setRemark10(value);
break;
default:
// 处理默认情况,可以选择忽略或者做其他处理
break;
}
}
checkVO(vo);
return vo;
}
// 错误判断通用方法
// 判断非零,错误返回;不为空时,判断是否符合枚举类
private void isNotEmptyAndBack(String value, Class<? extends Enum<?>> enumClass, List<String> errList, String errValue, int length , AtomicBoolean flag) {
if (StringUtils.isEmpty(value)) {
errList.add(errValue + NOT_EMPTY);
flag.set(false);
} else {
isEmptyAndSize(value, length, errList, errValue, flag);
try {
// 获取枚举类的所有值
Enum<?>[] enums = enumClass.getEnumConstants();
boolean isValid = false;
for (Enum<?> enumValue : enums) {
Field valueField = enumValue.getClass().getDeclaredField("value");
valueField.setAccessible(true);
String enumValueStr = (String) valueField.get(enumValue);
if (enumValueStr.equals(value)) {
isValid = true;
break;
}
}
if (!isValid) {
errList.add(errValue + ACCORD_ENUM);
flag.set(false);
}
} catch (IllegalArgumentException e) {
errList.add(errValue + ACCORD_ENUM);
flag.set(false);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
// 非零判断,有值判断---判断数值类型,数值长度
private void isEmptyAndPositiveNumberSize(String value, Class<?> targetType, Integer length, Integer decimalLength, List<String> errList, String errValue, AtomicBoolean flag) {
if (StringUtils.isNotEmpty(value)) {
if (Boolean.TRUE.equals(ToolUtil.convertToType(value, targetType))) {
if (Boolean.TRUE.equals(ToolUtil.checkNumber(value))) {
if (!ToolUtil.checkPrecision(value, length, decimalLength)) {
errList.add(errValue + NUMBER_LENGTH_ERR);
flag.set(false);
}
} else {
errList.add(errValue + POSITIVE_ERR);
flag.set(false);
}
} else {
errList.add(errValue + NUMBER_TYPE_ERR);
flag.set(false);
}
}
}
// 判断非零,错误返回
private void isNotEmptyAndBack(String value, List<String> errList, String errValue, AtomicBoolean flag) {
if (StringUtils.isEmpty(value)) {
errList.add(errValue + NOT_EMPTY);
flag.set(false);
}
}
// 判断非空,有值判断字符串的长度
private void isEmptyAndSize(String value, Integer length, List<String> errList, String errValue, AtomicBoolean flag) {
if (StringUtils.isNotEmpty(value)) {
int size = value.length();
if (size > length) {
errList.add(errValue + NUMBER_LENGTH_ERR);
flag.set(false);
}
}
}
// 非空判断,错误填入
private void isEmpty(String value, List<String> errList, String errValue, int length, AtomicBoolean flag) {
if (StringUtils.isEmpty(value)) {
errList.add(errValue + NOT_EMPTY);
flag.set(false);
} else {
// 字符串长度检查
int size = value.length();
if (size > length) {
errList.add(errValue + NUMBER_LENGTH_ERR);
flag.set(false);
}
}
}
// 判断非空,大于零判断
public void isEmptyAndPositiveNumber(String value, Class<?> targetType, List<String> errList, String errValue, AtomicBoolean flag) {
if (StringUtils.isNotEmpty(value)) {
if (Boolean.FALSE.equals(ToolUtil.convertToType(value, targetType))) {
errList.add(errValue + NUMBER_TYPE_ERR);
flag.set(false);
}else {
if (Boolean.FALSE.equals(checkNumber(value))) {
errList.add(errValue + "数量不能为0");
flag.set(false);
}
}
}
}
// 判断非空,字典值判断
public void isNotEmptyAndDict(String value, String dictType, List<String> errList, String errValue, AtomicBoolean flag) {
if (StringUtils.isEmpty(value)) {
errList.add(errValue + NOT_EMPTY);
flag.set(false);
} else {
DictDataRespDTO dictDataRespDTO = dictDataApi.parseDictData(dictType, value).getData();
if (dictDataRespDTO == null) {
errList.add(errValue + ACCORD_ENUM);
flag.set(false);
}
}
}
// 板材的数据以及长度的检验
public void checkPlate(OrderPlateImportExcelVO vo, List<String> errList , AtomicBoolean flag) {
// 数量类型判断
isEmptyAndPositiveNumber(vo.getGoodsNumber(), Integer.class, errList, "板材数量", flag);
// 板材纹理
isNotEmptyAndBack(vo.getWave(), IsHavaeEnum.class, errList, "板材纹理", 4, flag);
// 大板的长宽厚存在以及是否符合数个
isNotEmptyAndBack(vo.getGoodsWidth(), errList, "板材长度", flag);
isEmptyAndPositiveNumberSize(vo.getGoodsWidth(), Double.class, 5, 3, errList, "板材长度", flag);
isNotEmptyAndBack(vo.getGoodsHeight(), errList, "板材宽度", flag);
isEmptyAndPositiveNumberSize(vo.getGoodsHeight(), Double.class, 5, 3, errList, "板材宽度", flag);
isNotEmptyAndBack(vo.getGoodsThickness(), errList, "板材厚度", flag);
isEmptyAndPositiveNumberSize(vo.getGoodsThickness(), Double.class, 5, 3, errList, "板材厚度", flag);
// 房间、柜体、板名称 不可以为空
isEmpty(vo.getRoomsName(), errList, "房间名称", 64, flag);
isEmpty(vo.getCabinetsName(), errList, "柜体名称", 64, flag);
isEmpty(vo.getName(), errList, "板材名称", 64, flag);
//成品长、成品宽、拆单长、拆单宽、厚、左封边、右封边、上封边、下封边 不能为空
isNotEmptyAndBack(vo.getHeight(), errList, "成品长度", flag);
isEmptyAndPositiveNumberSize(vo.getHeight(), Double.class, 5, 3, errList, "成品长度", flag);
isNotEmptyAndBack(vo.getWidth(), errList, "成品宽度", flag);
isEmptyAndPositiveNumberSize(vo.getWidth(), Double.class, 5, 3, errList, "成品宽度", flag);
isNotEmptyAndBack(vo.getSplitHeight(), errList, "拆单长度", flag);
isEmptyAndPositiveNumberSize(vo.getSplitHeight(), Double.class, 5, 3, errList, "拆单长度", flag);
isNotEmptyAndBack(vo.getSplitWidth(), errList, "拆单宽度", flag);
isEmptyAndPositiveNumberSize(vo.getSplitWidth(), Double.class, 5, 3, errList, "拆单宽度", flag);
isNotEmptyAndBack(vo.getThickness(), errList, "厚度", flag);
isEmptyAndPositiveNumberSize(vo.getThickness(), Double.class, 5, 3, errList, "厚度", flag);
isNotEmptyAndBack(vo.getSealLeft(), errList, "左封边", flag);
isEmptyAndPositiveNumberSize(vo.getSealLeft(), Double.class, 5, 3, errList, "左封边", flag);
isNotEmptyAndBack(vo.getSealRight(), errList, "右封边", flag);
isEmptyAndPositiveNumberSize(vo.getSealRight(), Double.class, 5, 3, errList, "右封边", flag);
isNotEmptyAndBack(vo.getSealUp(), errList, "上封边", flag);
isEmptyAndPositiveNumberSize(vo.getSealUp(), Double.class, 5, 3, errList, "上封边", flag);
isNotEmptyAndBack(vo.getSealDown(), errList, "下封边", flag);
isEmptyAndPositiveNumberSize(vo.getSealDown(), Double.class, 5, 3, errList, "下封边", flag);
// 排版面、纹路、开门方向
isNotEmptyAndDict(vo.getTypographicFace(), DictTypeConstants.TYPOGRAPHY_TYPE, errList, "排版面", flag);
isNotEmptyAndDict(vo.getTexture(), DictTypeConstants.GRAIN_TYPE, errList, "纹路", flag);
isNotEmptyAndDict(vo.getOpenDoorType(), DictTypeConstants.DOOR_OPENING_DIRECTIONS, errList, "开门方向", flag);
}
// OrderPlateImportExcelVO 数据验证
private Boolean checkVO(OrderPlateImportExcelVO vo) {
List<String> errList = new ArrayList<>();
AtomicBoolean flag = new AtomicBoolean(true);
// 全部需要值的字段
// 检查非空 类型、数量
isEmpty(vo.getGoodType(), errList, "类型",32, flag);
isEmpty(vo.getGoodsNumber(), errList, "数量", 10000000 ,flag);
// 检查商品物料编码或是商品名称、规格、材质、颜色不可全为空
if (StringUtils.isEmpty(vo.getGoodsName()) || StringUtils.isEmpty(vo.getSpec())
|| StringUtils.isEmpty(vo.getMaterial()) || StringUtils.isEmpty(vo.getColor()) || StringUtils.isEmpty(vo.getUnit())) {
errList.add("商品商品名称、规格、材质、颜色、单位不可为空");
flag.set(false);
}
if (StringUtils.equals(vo.getGoodType(), "配件")) {
// 复合部件必填
isNotEmptyAndBack(vo.getIsComposite(), QuarrelEnum.class, errList, "是否复合部件", 1, flag); // 判断传入的值,是否符合字典中的枚举类
// 配件类型必填
isNotEmptyAndBack(vo.getCategory(), CategoryEnum.class, errList, "配件类型", 32, flag);
// 配件长宽厚,存在判断是否可以转义
isEmptyAndPositiveNumberSize(vo.getGoodsWidth(), Double.class, 5, 3, errList, "配件宽", flag);
isEmptyAndPositiveNumberSize(vo.getGoodsHeight(), Double.class, 5, 3, errList, "配件高", flag);
isEmptyAndPositiveNumberSize(vo.getGoodsThickness(), Double.class, 5, 3, errList, "配件厚", flag);
// 配件类型为封边条的时候,需要填写配件宽厚
if (StringUtils.equals(vo.getCategory(), CategoryEnum.EDGING.getValue())) { // 封边条必须有宽高
isNotEmptyAndBack(vo.getGoodsWidth(), errList, "封边条宽", flag);
isNotEmptyAndBack(vo.getGoodsThickness(), errList, "封边条厚", flag);
}
// 配件数量判断
isEmptyAndPositiveNumber(vo.getGoodsNumber(), Double.class, errList, "配件数量", flag);
}
// 若商品类型为板材,需检查房间、柜体、板名称、成品长、成品宽、拆单长、拆单宽、厚、左封边、右封边、上封边、下封边、排版面、纹路、开门方向不能为空
if (StringUtils.equals(vo.getGoodType(), "板材")) {
checkPlate(vo, errList, flag);
}
if (!flag.get()) {
isErr.getAndIncrement();
}
JSONArray jsonArray = JSON.parseArray(JSON.toJSONString(errList));// 错误列表
vo.setResult(String.valueOf(jsonArray));
return flag.get();
}
public int isErr() {
return isErr.get();
}
public void setErr(int isErr) {
this.isErr.set(isErr);
}
// 数量大小判断
public Boolean checkNumber(String numberStr) {
if (numberStr == null) {
return false;
}
if (Double.parseDouble(numberStr) <= 0) {
return false;
}
return true;
}
}
@@ -138,11 +138,11 @@ public class ExcelTypeRealize {
// 配件信息合集,添加生产单id,添加生产单配件设计端商品编码,配件信息写入order_parts
Map<String, List<OrderPlateImportExcelVO>> partsIdMap = checkMap.get(PARTS).stream().collect(
Collectors.groupingBy(
excelVO -> excelVO.getGoodsId() != null ? excelVO.getGoodsId() : " ",
excelVO -> excelVO.getGoodsId() != null ? excelVO.getGoodsId() : "",
Collectors.toList()
));
partsIdMap.forEach((key, value) -> {
if (key.equals(" ")) { // 没有商品编号的 value.get(0).getGoodsId() == null
if (key.equals("")) { // 没有商品编号的 value.get(0).getGoodsId() == null
// 将相同条件的元素归为一个集合
Map<List<Object>, List<OrderPlateImportExcelVO>> partsMap = value.stream()
.collect(Collectors.groupingBy(
@@ -0,0 +1,317 @@
package com.cf.imes.module.executor.util.fileConversion.admin.files.excel;
import com.cf.imes.module.executor.util.fileConversion.admin.ToolUtil;
import com.monitorjbl.xlsx.StreamingReader;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
/**
* 大文件 excel 导入
*/
@Slf4j
@Component
public class LargeFilesUtils {
public List<OrderPlateImportExcelVO>[] importExcelLargeFile(MultipartFile file) {
try (InputStream inputStream = file.getInputStream();
Workbook workbook = StreamingReader.builder()
.rowCacheSize(1000)
.bufferSize(10240)
.open(inputStream)) {
Sheet sheet = workbook.getSheetAt(0);
return processRows(sheet);
} catch (Exception e) {
log.error("Error processing Excel file", e);
throw new RuntimeException("Failed to process Excel file", e);
}
}
private List<OrderPlateImportExcelVO>[] processRows(Sheet sheet) { // 一个是order,一个是plateLiat
List<OrderPlateImportExcelVO> preDelimiterList = new ArrayList<>();
List<OrderPlateImportExcelVO> postDelimiterList = new ArrayList<>();
AtomicBoolean fastRowBoolean = new AtomicBoolean(false);
AtomicBoolean delimiterFound = new AtomicBoolean(false);
AtomicBoolean stopReading = new AtomicBoolean(false);
for (Row row : sheet) {
if (stopReading.get() || shouldSkipRow(row, delimiterFound,fastRowBoolean, stopReading)) {
continue;
}
OrderPlateImportExcelVO vo = createOrderPlateFromRow(row);
if (delimiterFound.get()) {
postDelimiterList.add(vo);
} else {
preDelimiterList.add(vo);
}
handleSpecialDelimiters(row, () -> delimiterFound.set(true), () -> stopReading.set(true));
}
logResults(preDelimiterList.size(), postDelimiterList.size());
return new List[] { preDelimiterList, postDelimiterList.stream()
.filter(item -> !ToolUtil.isAllFieldsEmptyOrNull(item))
.collect(Collectors.toList()) };
}
private boolean shouldSkipRow(Row row, AtomicBoolean delimiterFound, AtomicBoolean fastRowBoolean, AtomicBoolean stopReading) {
if (stopReading.get()) return true;
String firstCellValue = getFirstCellValue(row);
if ("###".equals(firstCellValue) && !delimiterFound.get()) {
delimiterFound.set(true);
fastRowBoolean.set(true);
return true;
}
if (fastRowBoolean.get()) {
fastRowBoolean.set(false);
return true;
}
if ("***".equals(firstCellValue)) {
stopReading.set(true);
return true;
}
return false;
}
private String getFirstCellValue(Row row) {
Cell cell = row.getCell(0);
return cell != null ? cell.getStringCellValue() : "";
}
private OrderPlateImportExcelVO createOrderPlateFromRow(Row row) {
OrderPlateImportExcelVO vo = new OrderPlateImportExcelVO();
int columnIndex = 0;
for (Cell cell : row) {
setOrderPlateProperty(vo, cell, columnIndex++);
}
return vo;
}
private void setOrderPlateProperty(OrderPlateImportExcelVO vo, Cell cell, int index) {
String value = cell.getStringCellValue();
switch (index) {
case 0:
vo.setOrdinal(value);
break;
case 1:// 类型
vo.setGoodType(value);
break;
case 2:// 物料编码
vo.setGoodsId(value);
break;
case 3:// 商品名称
vo.setGoodsName(value);
break;
case 4:// 材质
vo.setMaterial(value);
break;
case 5:// 纹理
vo.setWave(value);
break;
case 6:// 颜色
vo.setColor(value);
break;
case 7:// 复合部件
vo.setIsComposite(value);
break;
case 8:// 配件类型
vo.setCategory(value);
break;
case 9:// 子类
vo.setType(value);
break;
case 10:// 厂家
vo.setFactory(value);
break;
case 11:// 品牌
vo.setBrand(value);
break;
case 12:// 型号
vo.setModel(value);
break;
case 13:// 板材/配件长
vo.setGoodsHeight(value);
break;
case 14:// 板材/配件宽
vo.setGoodsWidth(value);
break;
case 15:// 板材/配件厚
vo.setGoodsThickness(value);
break;
case 16:// 规格
vo.setSpec(value);
break;
case 17:// 单位
vo.setUnit(value);
break;
case 18:// 数量
vo.setGoodsNumber(value);
break;
case 19:// 房间
vo.setRoomsName(value);
break;
case 20:// 柜体
vo.setCabinetsName(value);
break;
case 21:// 加工组类型
vo.setSynthesisTypeName(value);
break;
case 22:// 加工组名称
vo.setCombinationName(value);
break;
case 23://板名称
vo.setName(value);
break;
case 24:// 自定义板编号
vo.setPlateNo(value);
break;
case 25:// 成品长
vo.setHeight(value);
break;
case 26:// 成品宽
vo.setWidth(value);
break;
case 27:// 拆单长
vo.setSplitHeight(value);
break;
case 28:// 拆单宽
vo.setSplitWidth(value);
break;
case 29:// 厚
vo.setThickness(value);
break;
case 30:// 左封边
vo.setSealLeft(value);
break;
case 31:// 右封边
vo.setSealRight(value);
break;
case 32:// 上封边
vo.setSealUp(value);
break;
case 33:// 下封边
vo.setSealDown(value);
break;
case 34:// 排版面
vo.setTypographicFace(value);
break;
case 35:// 纹路
vo.setTexture(value);
break;
case 36:// 开门方向
vo.setOpenDoorType(value);
break;
case 37://备注1
vo.setRemark1(value);
break;
case 38://备注2
vo.setRemark2(value);
break;
case 39://备注3
vo.setRemark3(value);
break;
case 40://备注4
vo.setRemark4(value);
break;
case 41://备注5
vo.setRemark5(value);
break;
case 42://备注6
vo.setRemark6(value);
break;
case 43://备注7
vo.setRemark7(value);
break;
case 44://备注8
vo.setRemark8(value);
break;
case 45://备注9
vo.setRemark9(value);
break;
case 46://备注10
vo.setRemark10(value);
break;
default:
// 处理默认情况,可以选择忽略或者做其他处理
break;
}
}
private void handleSpecialDelimiters(Row row, Runnable onDelimiter, Runnable onStop) {
String firstCellValue = getFirstCellValue(row);
if ("###".equals(firstCellValue)) onDelimiter.run();
if ("***".equals(firstCellValue)) onStop.run();
}
private void logResults(int preSize, int postSize) {
log.info("preDelimiterList size: {}, postDelimiterList size: {}", preSize, postSize);
}
// vo转换
public Map<String, String> changeToOrderMap(List<OrderPlateImportExcelVO> list) {
Map<String, String> orderMap = new HashMap<>();
// 初始化默认值
orderMap.put(ProduceExcelConstants.ORDER_CUSTOM_ORDER_NO, "");
orderMap.put(ProduceExcelConstants.ORDER_CUSTOMER, "");
orderMap.put(ProduceExcelConstants.ORDER_ADDRESS, "");
orderMap.put(ProduceExcelConstants.ORDER_PHONE_NUMBER, "");
orderMap.put(ProduceExcelConstants.ORDER_REMARK, "");
orderMap.put(ProduceExcelConstants.ORDER_SPLITTER, "");
orderMap.put(ProduceExcelConstants.ORDER_SALESMAN, "");
orderMap.put(ProduceExcelConstants.ORDER_DEALER_PHONE_NUMBER, "");
orderMap.put(ProduceExcelConstants.ORDER_DEALER, "");
orderMap.put(ProduceExcelConstants.ORDER_DELIVERY_DATE, "");
// 定义一个映射规则数组,用于指示每个索引应更新哪些键
String[][] keyMapping = {
{ProduceExcelConstants.ORDER_CUSTOM_ORDER_NO, ProduceExcelConstants.ORDER_CUSTOMER},
{ProduceExcelConstants.ORDER_DEALER, ProduceExcelConstants.ORDER_ADDRESS},
{ProduceExcelConstants.ORDER_DEALER_PHONE_NUMBER, ProduceExcelConstants.ORDER_PHONE_NUMBER},
{ProduceExcelConstants.ORDER_SALESMAN, ProduceExcelConstants.ORDER_DELIVERY_DATE},
{ProduceExcelConstants.ORDER_SPLITTER, ProduceExcelConstants.ORDER_REMARK}
};
for (int i = 0; i < Math.min(keyMapping.length, list.size()); i++) {
OrderPlateImportExcelVO vo = list.get(i);
String[] keys = keyMapping[i];
// 假设getGoodType()和getCabinetsName()只是示例方法,实际应用中应该根据实际情况选择合适的方法
if (vo.getGoodType() != null && !vo.getGoodType().isEmpty()) {
orderMap.put(keys[0], vo.getGoodType());
}
if (vo.getCabinetsName() != null && !vo.getCabinetsName().isEmpty()) {
orderMap.put(keys[1], vo.getCabinetsName());
}
}
return orderMap;
}
}
@@ -0,0 +1,21 @@
package com.cf.imes.module.executor.util.fileConversion.admin.files.excel;
/**
* Excel 常用字符
*/
public class ProduceExcelConstants {
// ========== order 模块 ==========
public static final String ORDER_CUSTOM_ORDER_NO = "customOrderNo";
public static final String ORDER_CUSTOMER = "customer";
public static final String ORDER_ADDRESS = "address";
public static final String ORDER_PHONE_NUMBER = "phoneNumber";
public static final String ORDER_REMARK = "remark";
public static final String ORDER_SPLITTER = "splitter";
public static final String ORDER_SALESMAN = "salesman";
public static final String ORDER_DEALER_PHONE_NUMBER = "dealerPhoneNumber";
public static final String ORDER_DEALER = "dealer";
public static final String ORDER_DELIVERY_DATE = "deliveryDate";
}
@@ -0,0 +1,28 @@
package com.cf.imes.module.executor.util.fileConversion.admin.files.xml.VO;
import com.cf.imes.module.executor.dal.dataobject.order.OrderDO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
/**
* Excel 校验数据类型
*/
@Schema(description = "Excel 校验数据类型")
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ToString(callSuper = true)
public class XmlCheckVO {
@Schema(description = "校验结果")
private Boolean flag;
@Schema(description = "校验结果数据")
private OrderXmlVO orderXmlVO;
@Schema(description = "订单信息")
private OrderDO orderDO;
}
@@ -121,8 +121,7 @@ public class XMLUtil {
}
// 生产单数据格式验证
public Map<String, Object> changeDate(OrderXmlVO orderXmlVO, Long organId) {
Map<String, Object> map = new HashMap<>();
public XmlCheckVO changeDate(OrderXmlVO orderXmlVO, Long organId) {
boolean error = validatePhoneNumbers(orderXmlVO);
LocalDate orderDate = null;
@@ -176,10 +175,7 @@ public class XMLUtil {
}
// 生产单信息验证
map.put("order", orderDO);
map.put("file", orderXmlVO);
map.put("error", error);
return map;
return new XmlCheckVO(error, orderXmlVO, orderDO);
}
// 数据格式转换