1.调整导入建垛功能逻辑,优化执行速度

master
x_z 3 years ago
parent a8ff3575a0
commit fcb3c60142

@ -178,7 +178,12 @@ public class StackOrderController {
return ResultVOUtils.error(ResultEnum.PARAM_VERIFY_FALL, "请上传文件!"); return ResultVOUtils.error(ResultEnum.PARAM_VERIFY_FALL, "请上传文件!");
} }
ThreadUtil.execAsync(() -> { ThreadUtil.execAsync(() -> {
stackOrderService.importStackOrder(importStackOrderRequest.getFilePath()); try {
stackOrderService.importStackOrder(importStackOrderRequest.getFilePath(), importStackOrderRequest.getCustomerId());
} catch (Exception e) {
log.error("导入建垛失败", e);
throw new RuntimeException(e.getMessage());
}
}); });
return ResultVOUtils.success("导入成功"); return ResultVOUtils.success("导入成功");
} }

@ -5,6 +5,8 @@ import com.glxp.udi.admin.entity.product.StackCode;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper @Mapper
public interface StackCodeDao extends BaseMapper<StackCode> { public interface StackCodeDao extends BaseMapper<StackCode> {
@ -30,4 +32,11 @@ public interface StackCodeDao extends BaseMapper<StackCode> {
* @return * @return
*/ */
long countByCode(@Param("code") String code); long countByCode(@Param("code") String code);
/**
*
*
* @param list
*/
void batchInsert(List<StackCode> list);
} }

@ -13,4 +13,9 @@ public class ImportStackOrderRequest {
*/ */
private String filePath; private String filePath;
/**
* ID
*/
private String customerId;
} }

@ -2,6 +2,7 @@ package com.glxp.udi.admin.service.product;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.FileUtil;
import cn.hutool.core.thread.ThreadUtil; import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
@ -33,7 +34,6 @@ import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -133,14 +133,9 @@ public class StackOrderService {
* *
* @param filePath * @param filePath
*/ */
public void importStackOrder(String filePath) { public void importStackOrder(String filePath, String customerId) throws InterruptedException {
long t1 = System.currentTimeMillis();
List<StackCodeVo> list = EasyExcel.read(filePath).head(StackCodeVo.class).sheet().doReadSync(); List<StackCodeVo> list = EasyExcel.read(filePath).head(StackCodeVo.class).sheet().doReadSync();
long t2 = System.currentTimeMillis();
log.info("解析数据用时:{}", t2 - t1);
if (CollUtil.isEmpty(list)) { if (CollUtil.isEmpty(list)) {
log.error("解析垛码excel文件数据为空"); log.error("解析垛码excel文件数据为空");
throw new RuntimeException("垛码excel文件数据为空"); throw new RuntimeException("垛码excel文件数据为空");
@ -149,59 +144,60 @@ public class StackOrderService {
//条码集合 //条码集合
List<String> codeList = list.stream().map(StackCodeVo::getCode).collect(Collectors.toList()); List<String> codeList = list.stream().map(StackCodeVo::getCode).collect(Collectors.toList());
List<StackCode> stackCodes = new ArrayList<>(list.size()); //校验码在数据库中是否重复
//每1000个一次查询按照码数量分批
int batchNum = codeList.size() / 1000 + (codeList.size() % 1000 != 0 ? 1 : 0);
CountDownLatch checkCodeCDL = new CountDownLatch(batchNum);
//线程计数器 for (int i = 1; i <= batchNum; i++) {
CountDownLatch countDownLatch = new CountDownLatch(list.size()); int start = (i - 1) * 1000;
for (StackCodeVo vo : list) { int end = i * 1000;
executorService.submit(() -> { List<String> codePage = codeList.subList(start, end);
log.info("添加任务");
if (StrUtil.isBlank(vo.getOrderId()) || StrUtil.isBlank(vo.getCode())) {
log.error("数据为空,数据不规范");
throw new RuntimeException("垛码数据格式错误,解析失败");
}
List<String> codeTemp = new ArrayList<>(codeList.size()); QueryWrapper<StackCode> wrapper = new QueryWrapper<>();
BeanUtil.copyProperties(codeList, codeTemp); wrapper.in("code", codePage);
executorService.submit(() -> {
//判断此条码在数据库或者表中是否重复,如果有重复,则直接返回错误数据 Long count = stackCodeDao.selectCount(wrapper);
codeTemp.remove(vo.getCode()); //先移除自身 if (count > 0) {
if (codeTemp.contains(vo.getCode()) || stackCodeDao.countByCode(vo.getCode()) > 0) { log.error("条码重复,导入失败");
log.error("条码重复,重复的条码和流水号为:{}{}", vo.getCode(), vo.getOrderId());
throw new RuntimeException("条码重复"); throw new RuntimeException("条码重复");
} }
//构造码数据 //任务计数器 -1
StackCode stackCode = new StackCode(vo.getOrderId(), vo.getCode()); checkCodeCDL.countDown();
UdiEntity udi = FilterUdiUtils.getUdi(stackCode.getCode());
BeanUtil.copyProperties(udi, stackCode);
stackCodes.add(stackCode);
log.info("执行结束");
//线程执行结束,计数器 -1
countDownLatch.countDown();
}); });
} }
//阻塞到线程池任务执行结束 //等待查重结束
try { checkCodeCDL.await();
countDownLatch.await();
log.info("数据封装任务执行完毕"); //对集合去重,若集合中的数据存在重复,则导入失败
} catch (Exception e) { int oldLength = codeList.size();
log.error("解析封装失败失败", e); ArrayList<String> codes = CollUtil.distinct(codeList);
throw new RuntimeException("解析封装数据异常"); if (codes.size() < oldLength) {
log.error("条码重复");
throw new RuntimeException("条码重复");
} }
//封装码数据
List<StackCode> stackCodes = new ArrayList<>();
list.forEach(vo -> {
if (StrUtil.isBlank(vo.getOrderId()) || StrUtil.isBlank(vo.getCode())) {
log.error("数据为空,数据不规范");
throw new RuntimeException("垛码数据格式错误,解析失败");
}
//构造码数据
StackCode stackCode = new StackCode(vo.getOrderId(), vo.getCode());
UdiEntity udi = FilterUdiUtils.getUdi(stackCode.getCode());
BeanUtil.copyProperties(udi, stackCode);
stackCodes.add(stackCode);
});
long t3 = System.currentTimeMillis();
log.info("构造数据用时:{}", t3 - t2);
Map<String, List<StackCode>> stacks = stackCodes.stream().collect(Collectors.groupingBy(StackCode::getOrderIdFk)); Map<String, List<StackCode>> stacks = stackCodes.stream().collect(Collectors.groupingBy(StackCode::getOrderIdFk));
//根据每一个流水号,创建单据,生成条码 //根据每一个流水号,创建单据,生成条码
String customerId = String.valueOf(customerService.getCustomerId());
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, TransactionIsolationLevel.READ_COMMITTED);
StackCodeDao mapper = sqlSession.getMapper(StackCodeDao.class);
for (String serialNum : stacks.keySet()) { for (String serialNum : stacks.keySet()) {
StackOrder stackOrder = new StackOrder(); StackOrder stackOrder = new StackOrder();
String stackId = idUtil.getStackId(customerId); String stackId = idUtil.getStackId(customerId);
@ -212,21 +208,15 @@ public class StackOrderService {
//插入垛数据 //插入垛数据
stackOrderDao.insert(stackOrder); stackOrderDao.insert(stackOrder);
List<StackCode> data = stacks.get(serialNum); List<StackCode> data = stacks.get(serialNum);
List<StackCode> saveDataList = new CopyOnWriteArrayList<>(data); data.forEach(stackCode -> stackCode.setOrderIdFk(stackId));
saveDataList.parallelStream().forEach(stackCode -> {
stackCode.setOrderIdFk(stackId);
mapper.insert(stackCode);
});
sqlSession.commit(); //按照指定长度切分集合,批量插入
List<List<StackCode>> listList = ListUtil.split(data, 5000);
for (List<StackCode> stackCodeList : listList) {
stackCodeDao.batchInsert(stackCodeList);
}
} }
sqlSession.close();
long t4 = System.currentTimeMillis();
log.info("插入数据用时:{}", t4 - t3);
log.info("全程用时:{}", t4 - t1);
//导入成功,删除数据文件 //导入成功,删除数据文件
FileUtil.del(filePath); FileUtil.del(filePath);
} }

@ -15,11 +15,11 @@ public class FilterUdiUtils {
public static UdiEntity getUdi(String data) { public static UdiEntity getUdi(String data) {
if (data != null && data.length() > 2) { if (data != null && data.length() > 2) {
if (data.substring(0, 2).equals("MA")) { if (data.startsWith("MA")) {
return getZGCUdi(data); return getZGCUdi(data);
} else if (data.substring(0, 2).equals("01")) { } else if (data.startsWith("01")) {
return getGS1Udi(data); return getGS1Udi(data);
} else if (data.substring(0, 1).equals("#")) { } else if (data.charAt(0) == '#') {
return getGLXPUdi(data); return getGLXPUdi(data);
} }
} }
@ -83,7 +83,7 @@ public class FilterUdiUtils {
batchNo = data.substring(34, data.length()); batchNo = data.substring(34, data.length());
} }
}else if (data.length() >= 34 && data.substring(32, 34).equals("21")) { } else if (data.length() >= 34 && data.substring(32, 34).equals("21")) {
serialNo = data.substring(34, data.length()); serialNo = data.substring(34, data.length());
} }
} else if (data.length() >= 26 && data.substring(24, 26).equals("10")) { } else if (data.length() >= 26 && data.substring(24, 26).equals("10")) {

@ -8,10 +8,29 @@
</delete> </delete>
<select id="countByOrderId" resultType="java.lang.Long"> <select id="countByOrderId" resultType="java.lang.Long">
select count(*) from stack_code where orderIdFk = #{orderId} select count(*)
from stack_code
where orderIdFk = #{orderId}
</select> </select>
<select id="countByCode" resultType="long"> <select id="countByCode" resultType="long">
select count(*) from stack_code where code = #{code} select count(*)
from stack_code
where code = #{code}
</select> </select>
<insert id="batchInsert">
insert into stack_code (code, orderIdFk, batchNo, produceDate, expireDate, serialNo, nameCode) values
<foreach collection="list" item="item" index="index" separator=",">
(
#{item.code},
#{item.orderIdFk},
#{item.batchNo},
#{item.produceDate},
#{item.expireDate},
#{item.serialNo},
#{item.nameCode}
)
</foreach>
</insert>
</mapper> </mapper>
Loading…
Cancel
Save