|
@@ -1,61 +1,17 @@
|
|
package com.abi.qms.platform.infrastructure.mq;
|
|
package com.abi.qms.platform.infrastructure.mq;
|
|
|
|
|
|
-import cn.hutool.core.io.FileUtil;
|
|
|
|
-import cn.hutool.core.io.file.FileWriter;
|
|
|
|
-import com.abi.base.foundation.util.RedisClient;
|
|
|
|
-import com.abi.qms.platform.dao.entity.*;
|
|
|
|
-import com.abi.qms.platform.dao.enums.CodePackageOrderTypeEnum;
|
|
|
|
-import com.abi.qms.platform.dao.enums.InvalidEnum;
|
|
|
|
|
|
+import com.abi.qms.platform.dao.entity.QrPackage;
|
|
import com.abi.qms.platform.dao.enums.QrPackageGenerateStatusEnum;
|
|
import com.abi.qms.platform.dao.enums.QrPackageGenerateStatusEnum;
|
|
-import com.abi.qms.platform.dao.enums.QrRepertoryTypeEnum;
|
|
|
|
-import com.abi.qms.platform.dao.mapper.*;
|
|
|
|
-import com.abi.qms.platform.dao.tablestore.entity.QrCode;
|
|
|
|
-import com.abi.qms.platform.dao.vo.result.QrRepertoryColumnVO;
|
|
|
|
-import com.abi.qms.platform.dao.vo.result.QrRepertoryVO;
|
|
|
|
-import com.abi.qms.platform.feign.BasicServiceClient;
|
|
|
|
-import com.abi.qms.platform.infrastructure.qr.build.parent.SerialBuildCode;
|
|
|
|
-import com.abi.qms.platform.infrastructure.util.BuildCodeUtil;
|
|
|
|
-import com.abi.qms.platform.infrastructure.util.RandomCodeUtils;
|
|
|
|
-import com.abi.qms.platform.service.QrPackageBookingOrderService;
|
|
|
|
|
|
+import com.abi.qms.platform.service.GenerateCodeService;
|
|
import com.abi.qms.platform.service.QrPackageService;
|
|
import com.abi.qms.platform.service.QrPackageService;
|
|
import com.abi.task.common.api.exception.BusinessException;
|
|
import com.abi.task.common.api.exception.BusinessException;
|
|
-import com.abi.task.common.tablestore.TableStorePlusUtils;
|
|
|
|
-import com.abi.task.common.tablestore.common.TableStoreEntity;
|
|
|
|
-import com.abi.task.common.utils.PojoConverterUtils;
|
|
|
|
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
|
|
-import com.rabbitmq.client.Channel;
|
|
|
|
import lombok.SneakyThrows;
|
|
import lombok.SneakyThrows;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
-import net.lingala.zip4j.core.ZipFile;
|
|
|
|
-import net.lingala.zip4j.exception.ZipException;
|
|
|
|
-import net.lingala.zip4j.model.ZipParameters;
|
|
|
|
-import net.lingala.zip4j.util.Zip4jConstants;
|
|
|
|
-import org.apache.commons.fileupload.FileItem;
|
|
|
|
-import org.apache.commons.fileupload.FileItemFactory;
|
|
|
|
-import org.apache.commons.fileupload.disk.DiskFileItemFactory;
|
|
|
|
-import org.apache.commons.lang3.ObjectUtils;
|
|
|
|
import org.apache.commons.lang3.StringUtils;
|
|
import org.apache.commons.lang3.StringUtils;
|
|
-import org.redisson.api.RLock;
|
|
|
|
-import org.redisson.api.RedissonClient;
|
|
|
|
-import org.springframework.amqp.core.AmqpTemplate;
|
|
|
|
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
|
|
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
|
|
import org.springframework.amqp.rabbit.annotation.RabbitListener;
|
|
import org.springframework.amqp.rabbit.annotation.RabbitListener;
|
|
-import org.springframework.amqp.support.AmqpHeaders;
|
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
-import org.springframework.messaging.Message;
|
|
|
|
import org.springframework.stereotype.Component;
|
|
import org.springframework.stereotype.Component;
|
|
-import org.springframework.util.DigestUtils;
|
|
|
|
-import org.springframework.web.multipart.MultipartFile;
|
|
|
|
-import org.springframework.web.multipart.commons.CommonsMultipartFile;
|
|
|
|
-
|
|
|
|
-import java.io.File;
|
|
|
|
-import java.io.FileInputStream;
|
|
|
|
-import java.io.IOException;
|
|
|
|
-import java.io.OutputStream;
|
|
|
|
-import java.nio.charset.StandardCharsets;
|
|
|
|
-import java.time.LocalDateTime;
|
|
|
|
-import java.util.*;
|
|
|
|
-import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
* 生成码-消费者
|
|
* 生成码-消费者
|
|
@@ -70,72 +26,11 @@ public class GenerateCodeConsumer {
|
|
public static final String GENERATE_CODE_BY_REPERTORY_QUEUE = "generate_code_queue";
|
|
public static final String GENERATE_CODE_BY_REPERTORY_QUEUE = "generate_code_queue";
|
|
|
|
|
|
@Autowired
|
|
@Autowired
|
|
- private QrPackageMapper qrPackageMapper;
|
|
|
|
-
|
|
|
|
- @Autowired
|
|
|
|
- private QrBoxCodeFormatMapper qrBoxCodeFormatMapper;
|
|
|
|
-
|
|
|
|
- @Autowired
|
|
|
|
- private QrRepertoryMapper qrRepertoryMapper;
|
|
|
|
-
|
|
|
|
- @Autowired
|
|
|
|
- private QrRepertorySerialNumberMapper qrRepertorySerialNumberMapper;
|
|
|
|
|
|
+ private GenerateCodeService generateCodeService;
|
|
|
|
|
|
@Autowired
|
|
@Autowired
|
|
private QrPackageService qrPackageService;
|
|
private QrPackageService qrPackageService;
|
|
|
|
|
|
- @Autowired
|
|
|
|
- private RedissonClient redissonClient;
|
|
|
|
-
|
|
|
|
- @Autowired
|
|
|
|
- private QrPackageBatchMapper qrPackageBatchMapper;
|
|
|
|
-
|
|
|
|
- @Autowired
|
|
|
|
- private BasicServiceClient basicServiceClient;
|
|
|
|
-
|
|
|
|
- @Autowired
|
|
|
|
- private BaseFactoryMapper baseFactoryMapper;
|
|
|
|
-
|
|
|
|
- @Autowired
|
|
|
|
- private QrBoxCodeFormatSplitMapper qrBoxCodeFormatSplitMapper;
|
|
|
|
-
|
|
|
|
- @Autowired
|
|
|
|
- private QrIndexMapper qrIndexMapper;
|
|
|
|
-
|
|
|
|
- @Autowired
|
|
|
|
- private RedisClient redisClient;
|
|
|
|
-
|
|
|
|
- @Autowired
|
|
|
|
- private BaseMaterialMapper baseMaterialMapper;
|
|
|
|
-
|
|
|
|
- @Autowired
|
|
|
|
- private AmqpTemplate amqpTemplate;
|
|
|
|
-
|
|
|
|
- @Autowired
|
|
|
|
- private QrPackageBookingOrderService qrPackageBookingOrderService;
|
|
|
|
-
|
|
|
|
- //生成码数据
|
|
|
|
- final List<QrData> qrDataList = new LinkedList<>();
|
|
|
|
-
|
|
|
|
- //生成码包路径
|
|
|
|
-// private File file = new File(this.getClass().getResource("/").getPath()+"/code");
|
|
|
|
- private File file = new File("/code");
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- //批量添加文件
|
|
|
|
- private ArrayList<String> fileVerifyMd5List = new ArrayList<>();
|
|
|
|
-
|
|
|
|
- /** 允许单个码生成重复的次数 */
|
|
|
|
- private static final int REPEAT_BUILD_CODE_TIMES = 10;
|
|
|
|
-
|
|
|
|
- /** 声明码对应的值 */
|
|
|
|
- public Long codeIndex = 0L;
|
|
|
|
-
|
|
|
|
- //该包下共有多少码数量
|
|
|
|
- public Long sum = 0L;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
@SneakyThrows
|
|
@SneakyThrows
|
|
@RabbitHandler
|
|
@RabbitHandler
|
|
@RabbitListener(queues = GenerateCodeConsumer.GENERATE_CODE_BY_REPERTORY_QUEUE,ackMode = "AUTO")
|
|
@RabbitListener(queues = GenerateCodeConsumer.GENERATE_CODE_BY_REPERTORY_QUEUE,ackMode = "AUTO")
|
|
@@ -145,21 +40,8 @@ public class GenerateCodeConsumer {
|
|
throw new BusinessException("队列监听数据为空!");
|
|
throw new BusinessException("队列监听数据为空!");
|
|
}
|
|
}
|
|
try {
|
|
try {
|
|
- Object code_qr_index = redisClient.get("code_qr_index");
|
|
|
|
- if(ObjectUtils.isEmpty(code_qr_index)){
|
|
|
|
- QueryWrapper<QrIndex> indexQuery= new QueryWrapper<>();
|
|
|
|
- indexQuery.orderByDesc("index_current").last("limit 1");
|
|
|
|
- QrIndex qrIndex = qrIndexMapper.selectOne(indexQuery);
|
|
|
|
- if(!ObjectUtils.isEmpty(qrIndex)){
|
|
|
|
- codeIndex = qrIndex.getIndexCurrent();
|
|
|
|
- }
|
|
|
|
- redisClient.set("code_qr_index",codeIndex);
|
|
|
|
- } else {
|
|
|
|
- codeIndex = Long.parseLong(code_qr_index.toString());
|
|
|
|
- }
|
|
|
|
// 生成码
|
|
// 生成码
|
|
- loopGenerateCode(Long.parseLong(id));
|
|
|
|
-
|
|
|
|
|
|
+ generateCodeService.generateQrCode(Long.parseLong(id));
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
log.error("生成码失败", e);
|
|
log.error("生成码失败", e);
|
|
// 回滚
|
|
// 回滚
|
|
@@ -169,530 +51,4 @@ public class GenerateCodeConsumer {
|
|
qrPackageService.failedRollback(qrPackage);
|
|
qrPackageService.failedRollback(qrPackage);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 生成码
|
|
|
|
- */
|
|
|
|
- private void loopGenerateCode(Long qrPackageId) {
|
|
|
|
- log.info("1 loopGenerateCode begin -->"+System.currentTimeMillis());
|
|
|
|
- log.info("请求参数id为 -->{}",qrPackageId);
|
|
|
|
- //0-查询码包,校验状态,标记生成中
|
|
|
|
- QrPackage qrPackage = qrPackageMapper.selectById(qrPackageId);
|
|
|
|
- // 码数据已生成,return
|
|
|
|
- if (QrPackageGenerateStatusEnum.GENERATE_SUCCESS.is(qrPackage.getGenerateStatus())) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- //批量添加文件
|
|
|
|
- ArrayList<File> fileList = new ArrayList<>();
|
|
|
|
- // 更改生成状态为生成中
|
|
|
|
- qrPackage.setGenerateStatus(QrPackageGenerateStatusEnum.GENERATING.getCode());
|
|
|
|
- qrPackageMapper.updateById(qrPackage);
|
|
|
|
- log.info("2 loopGenerateCode update status -->"+System.currentTimeMillis());
|
|
|
|
-
|
|
|
|
- //1-准备参数
|
|
|
|
- //查询幅面
|
|
|
|
- QrBoxCodeFormat qrBoxCodeFormat = qrBoxCodeFormatMapper.selectById(qrPackage.getBoxCodeFormatId());
|
|
|
|
- //查询拆分数量
|
|
|
|
- List<QrBoxCodeFormatSplit> split= qrBoxCodeFormatSplitMapper.querySplit(qrBoxCodeFormat.getId(),qrBoxCodeFormat.getQrRepertoryId());
|
|
|
|
- Map<Long,QrBoxCodeFormatSplit> splitCache = split.stream().distinct() .collect(Collectors.toMap(QrBoxCodeFormatSplit::getQrRepertoryColumnId,t->t));
|
|
|
|
- // 码库 & 码库的列
|
|
|
|
- QrRepertoryVO qrRepertory = qrRepertoryMapper.selectQrRepertoryDetailById(qrBoxCodeFormat.getQrRepertoryId());
|
|
|
|
- List<QrRepertoryColumnVO> qrRepertoryColumnList = qrRepertory.getQrRepertoryColumnList();
|
|
|
|
- Long qrRepertoryId = qrRepertory.getId();
|
|
|
|
- //根据码包id查询,获取批次号
|
|
|
|
- QueryWrapper<QrPackageBatch> param = new QueryWrapper<>();
|
|
|
|
- param.eq("package_id", qrPackage.getId());
|
|
|
|
- List<QrPackageBatch> qrPackageBatches = qrPackageBatchMapper.selectList(param);
|
|
|
|
- log.info("3 loopGenerateCode prepared data info -->"+System.currentTimeMillis());
|
|
|
|
-
|
|
|
|
- // 存放每列的url
|
|
|
|
- Map<Long, String> urlMap = new LinkedHashMap<>();
|
|
|
|
- // key:qr_repertory_column_id + child_index value:QrRepertorySerialNumber,后续会更新流水号
|
|
|
|
- // child_index用于标记同一列的第几个码格式变量
|
|
|
|
- Map<String, QrRepertorySerialNumber> qrRepertorySerialNumberMap = new LinkedHashMap<>();
|
|
|
|
- // 处理url和流水号--后续生成码要用到
|
|
|
|
- getUrlAndSerialNumber(qrRepertoryColumnList, qrRepertoryId, urlMap, qrRepertorySerialNumberMap);
|
|
|
|
- log.info("4 loopGenerateCode do some qrcode opts -->"+System.currentTimeMillis());
|
|
|
|
-
|
|
|
|
- //2-生成二维码
|
|
|
|
- for (QrPackageBatch qrPackageBatch:qrPackageBatches) {
|
|
|
|
- //计算备用码包数量
|
|
|
|
- Long standbyRatio = 0L;
|
|
|
|
- if(null != qrPackage.getStandbyRatio() && qrPackage.getStandbyRatio() != 0){
|
|
|
|
- standbyRatio=new Double( Math.ceil(qrPackageBatch.getBatchQrNumber()*qrPackage.getStandbyRatio()*1.0/100)).longValue();
|
|
|
|
- }
|
|
|
|
- // 这批下的申请数量
|
|
|
|
- Long qrNumber = qrPackageBatch.getBatchQrNumber()+standbyRatio;
|
|
|
|
- //批次号
|
|
|
|
- String batchNumber = qrPackageBatch.getBatchNumber();
|
|
|
|
- //重复次数
|
|
|
|
- int repeatTimes = 0;
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * qrRepertoryColumnList 码库的列
|
|
|
|
- * qrRepertoryId 码库id
|
|
|
|
- * urlMap 存放每列的url
|
|
|
|
- * qrRepertorySerialNumberMap 用于标记同一列的第几个码格式变量
|
|
|
|
- * qrNumber 码数量
|
|
|
|
- * batchNumber 批次号
|
|
|
|
- * localDateTime 创建时间
|
|
|
|
- * boxCodeFormat 箱码幅面
|
|
|
|
- */
|
|
|
|
- // 循环生成码
|
|
|
|
- List<QrData> codeList = loopGenerateCode(qrRepertoryColumnList, qrRepertoryId, urlMap, qrRepertorySerialNumberMap, qrNumber, batchNumber, repeatTimes,qrBoxCodeFormat,splitCache);
|
|
|
|
- log.info("5 loopGenerateCode get codeList -->"+System.currentTimeMillis());
|
|
|
|
- // 更新码库流水号
|
|
|
|
- if (!qrRepertorySerialNumberMap.isEmpty()) {
|
|
|
|
- for (Map.Entry<String, QrRepertorySerialNumber> entry : qrRepertorySerialNumberMap.entrySet()) {
|
|
|
|
- QrRepertorySerialNumber qrRepertorySerialNumber = entry.getValue();
|
|
|
|
- QrRepertorySerialNumber updateSerialNumber = new QrRepertorySerialNumber()
|
|
|
|
- .setId(qrRepertorySerialNumber.getId())
|
|
|
|
- .setSerialNumber(qrRepertorySerialNumber.getSerialNumber());
|
|
|
|
- qrRepertorySerialNumberMapper.updateById(updateSerialNumber);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- //转化为tablestore的对象列表
|
|
|
|
- List<TableStoreEntity> tableStoreEntityList = convertToTableStoreEntity(codeList, qrPackageBatch);
|
|
|
|
- log.info("6 loopGenerateCode transform tableStoreEntityList -->"+System.currentTimeMillis());
|
|
|
|
-
|
|
|
|
- // table数据库 批量插入
|
|
|
|
- saveTableStore(qrPackageBatch, codeList);
|
|
|
|
- log.info("7 loopGenerateCode save tablestore async -->"+System.currentTimeMillis());
|
|
|
|
-
|
|
|
|
- // 创建码文件
|
|
|
|
- createCodeFile(qrRepertory,batchNumber,qrBoxCodeFormat,fileList);
|
|
|
|
- log.info("8 loopGenerateCode create file -->"+System.currentTimeMillis());
|
|
|
|
- qrDataList.clear();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- //3-保存压缩文件并上传oss
|
|
|
|
- //压缩后得名字 正式码_SAP订单号_物料名称_文件内码数量
|
|
|
|
- String materialName = null;
|
|
|
|
- if(CodePackageOrderTypeEnum.SAP_ORDER.is(qrPackage.getOrderType())){
|
|
|
|
- BaseMaterial baseMaterial = baseMaterialMapper.selectById(qrPackage.getMaterialId());
|
|
|
|
- materialName = baseMaterial==null?"":baseMaterial.getMaterialName();
|
|
|
|
- }else{
|
|
|
|
- QrPackageBookingOrder bookingOrder = qrPackageBookingOrderService.getBookingOrder(qrPackage.getBookingOrder());
|
|
|
|
- materialName = bookingOrder==null?"":bookingOrder.getMaterialName();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- String zipName = "正式码_"+qrPackage.getSapOrderNo()+"_"+materialName+"_"+sum+".zip";
|
|
|
|
- sum = 0L;
|
|
|
|
- //压缩密码
|
|
|
|
- String pas = RandomCodeUtils.getStr(6);
|
|
|
|
- log.info("生成密码:"+pas);
|
|
|
|
- //压缩加密文件
|
|
|
|
- zipEncryption(file, fileList,pas,zipName);
|
|
|
|
- //上传阿里云,并更新码包的下载路径 保存zip密码
|
|
|
|
- try{
|
|
|
|
- MultipartFile multipartFile = toMultipartFile(file.getPath()+"/"+zipName, zipName);
|
|
|
|
- Object returDat = basicServiceClient.uploadFileOss(multipartFile);
|
|
|
|
- if(null != returDat){
|
|
|
|
- Map<String,Object> result =(Map<String, Object>)returDat;
|
|
|
|
- //放入oss地址
|
|
|
|
- qrPackage.setDownloadPath(null == result.get("data") ? "" :(String) result.get("data"));
|
|
|
|
- }
|
|
|
|
- //放入oss地址和密码
|
|
|
|
- qrPackage.setZipPassword(pas);
|
|
|
|
- fileList.clear();
|
|
|
|
- //删除生成文件
|
|
|
|
- FileUtil.del(file);
|
|
|
|
- }catch (Exception e){
|
|
|
|
- throw new BusinessException("上传OSS失败");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- //3-更改生成状态为已生成
|
|
|
|
- qrPackage.setGenerateStatus(QrPackageGenerateStatusEnum.GENERATE_SUCCESS.getCode());
|
|
|
|
- qrPackage.setGenerateTime(LocalDateTime.now());
|
|
|
|
- //将MD5的字符换逗号拼接放入码包
|
|
|
|
- qrPackage.setFileVerifyMd5(String.join(",",fileVerifyMd5List));
|
|
|
|
- //根据包材厂获取包材厂负责人邮箱
|
|
|
|
- QueryWrapper<BaseFactory> baseQuery = new QueryWrapper<>();
|
|
|
|
- baseQuery.eq("id", qrPackage.getFactoryCoverId());
|
|
|
|
- BaseFactory baseFactory = baseFactoryMapper.selectOne(baseQuery);
|
|
|
|
- //发送邮件
|
|
|
|
- String aliPath = qrPackage.getDownloadPath().substring(qrPackage.getDownloadPath().lastIndexOf("/") + 1);
|
|
|
|
- qrPackageService.sendEmailForQrPackageCreated(baseFactory.getEmail(),qrPackage,aliPath,qrPackage.getZipPassword());
|
|
|
|
- //邮件发送后修改状态
|
|
|
|
- qrPackageMapper.updateById(qrPackage);
|
|
|
|
- QrIndex index = new QrIndex();
|
|
|
|
- index.setIndexCurrent(codeIndex);
|
|
|
|
- qrIndexMapper.insert(index);
|
|
|
|
- redisClient.set("code_qr_index",codeIndex);
|
|
|
|
- codeIndex = 0L;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 转换成 MultipartFile
|
|
|
|
- * @param filePath
|
|
|
|
- * @param fileName
|
|
|
|
- * @return
|
|
|
|
- */
|
|
|
|
- private MultipartFile toMultipartFile(String filePath, String fileName){
|
|
|
|
-
|
|
|
|
- File file = new File(filePath);
|
|
|
|
-
|
|
|
|
- FileItemFactory factory = new DiskFileItemFactory(16, null);
|
|
|
|
- FileItem fileItem = factory.createItem(fileName, "text/plain", true, file.getName());
|
|
|
|
- int bytesRead = 0;
|
|
|
|
- byte[] buffer = new byte[8192];
|
|
|
|
- try {
|
|
|
|
- FileInputStream fis = new FileInputStream(file);
|
|
|
|
- OutputStream os = fileItem.getOutputStream();
|
|
|
|
- while ((bytesRead = fis.read(buffer, 0, 8192)) != -1) {
|
|
|
|
- os.write(buffer, 0, bytesRead);
|
|
|
|
- }
|
|
|
|
- os.close();
|
|
|
|
- fis.close();
|
|
|
|
- } catch (IOException e) {
|
|
|
|
- e.printStackTrace();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- MultipartFile multipartFile = new CommonsMultipartFile(fileItem);
|
|
|
|
- return multipartFile;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private List<TableStoreEntity> convertToTableStoreEntity(List<QrData> codeList,QrPackageBatch qrPackageBatch){
|
|
|
|
- //保存所有码的列表
|
|
|
|
- List<TableStoreEntity> qrCodes = new ArrayList<>();
|
|
|
|
- //将每一列的码拆成多条码保存
|
|
|
|
- codeList.forEach(sout-> {
|
|
|
|
- List<QrInnerData> innerDataList = sout.getInnerDataList();
|
|
|
|
- List<QrCode> qrCodeCope = PojoConverterUtils.copyList(innerDataList, QrCode.class);
|
|
|
|
- //批次号 码包
|
|
|
|
- qrCodeCope.forEach(stable->{
|
|
|
|
- stable.setBatchNumberId(qrPackageBatch.getId());
|
|
|
|
- stable.setPackageId(qrPackageBatch.getPackageId());
|
|
|
|
- stable.setCreateTime(LocalDateTime.now());
|
|
|
|
- stable.setInvalid(InvalidEnum.NOT_INVALID.getCode());
|
|
|
|
- });
|
|
|
|
- qrCodes.addAll(qrCodeCope);
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- return qrCodes;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 批量新增tableStore,码表
|
|
|
|
- */
|
|
|
|
- private void saveTableStore(QrPackageBatch qrPackageBatch, List<QrData> codeList) {
|
|
|
|
- List<QrCode> qrCodes = new ArrayList<>();
|
|
|
|
- for (QrData sout : codeList) {
|
|
|
|
- List<QrInnerData> innerDataList = sout.getInnerDataList();
|
|
|
|
- List<QrCode> qrCodeCope = PojoConverterUtils.copyList(innerDataList, QrCode.class);
|
|
|
|
- // 批次号 码包
|
|
|
|
- qrCodeCope.forEach(stable -> {
|
|
|
|
- stable.setBatchNumberId(qrPackageBatch.getId());
|
|
|
|
- stable.setPackageId(qrPackageBatch.getPackageId());
|
|
|
|
- stable.setCreateTime(LocalDateTime.now());
|
|
|
|
- stable.setInvalid(InvalidEnum.NOT_INVALID.getCode());
|
|
|
|
- });
|
|
|
|
- qrCodes.addAll(qrCodeCope);
|
|
|
|
- }
|
|
|
|
- // 开始多线程写tableStore
|
|
|
|
- int repeatTimes = qrCodes.size() / 200;
|
|
|
|
- int leftover = qrCodes.size() % 200;
|
|
|
|
- for (int i = 0; i < repeatTimes+1; i++) {
|
|
|
|
- if (i == repeatTimes){
|
|
|
|
- amqpTemplate.convertAndSend(TableStoreBatchInsertConsumer.TABLE_STORE_BATCH_INSERT_QUEUE, qrCodes.subList(i*200,i*200+leftover));
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
- amqpTemplate.convertAndSend(TableStoreBatchInsertConsumer.TABLE_STORE_BATCH_INSERT_QUEUE, qrCodes.subList(i*200,i*200+200));
|
|
|
|
- }
|
|
|
|
- sum+=qrCodes.size();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * qrRepertoryColumnList 码库的列
|
|
|
|
- * qrRepertoryId 码库id
|
|
|
|
- * urlMap 存放每列的url
|
|
|
|
- * qrRepertorySerialNumberMap 用于标记同一列的第几个码格式变量
|
|
|
|
- * qrNumber 码数量
|
|
|
|
- * batchNumber 批次号
|
|
|
|
- * localDateTime 创建时间
|
|
|
|
- * repeatTimes 失败次数
|
|
|
|
- * formatNumber 幅面数量
|
|
|
|
- */
|
|
|
|
- private List<QrData> loopGenerateCode(List<QrRepertoryColumnVO> qrRepertoryColumnList, Long qrRepertoryId, Map<Long, String> urlMap, Map<String, QrRepertorySerialNumber> qrRepertorySerialNumberMap, Long qrNumber, String batchNumber, int repeatTimes,QrBoxCodeFormat boxCodeFormat,Map<Long, QrBoxCodeFormatSplit> splitCache ) {
|
|
|
|
- while (true) {
|
|
|
|
- LocalDateTime localDateTime = LocalDateTime.now();
|
|
|
|
- // 计算还需生成的数量
|
|
|
|
- long needGenerateNumber = qrNumber;
|
|
|
|
- if (needGenerateNumber <= 0) {
|
|
|
|
- log.info("批次号:{},码生成完毕", batchNumber);
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- // 用Set存放不重复的码
|
|
|
|
- HashSet<String> uniqueSet = new HashSet<>();
|
|
|
|
- // 生成码要用的参数
|
|
|
|
- Map<String, Object> paramMap = new HashMap<>();
|
|
|
|
- // 码
|
|
|
|
- StringBuilder codeSb = new StringBuilder();
|
|
|
|
- for (int i = 0; i < needGenerateNumber; i++) {
|
|
|
|
- QrData qrData = new QrData()
|
|
|
|
- .setQrRepertoryId(qrRepertoryId)
|
|
|
|
- .setBatchNumber(batchNumber)
|
|
|
|
- .setQrRepertoryType(QrRepertoryTypeEnum.SYSTEM_GENERATE.getCode())
|
|
|
|
- .setCreateTime(localDateTime);
|
|
|
|
-
|
|
|
|
- List<QrInnerData> qrInnerDataList = new LinkedList<>();
|
|
|
|
- //箱子码幅面
|
|
|
|
- for (int a = 0; a < boxCodeFormat.getFormatNumber(); a++) {
|
|
|
|
- for (int j = 0; j < qrRepertoryColumnList.size(); j++) {
|
|
|
|
- QrRepertoryColumnVO qrRepertoryColumn = qrRepertoryColumnList.get(j);
|
|
|
|
- Long qrRepertoryColumnId = qrRepertoryColumn.getId();
|
|
|
|
- //声明拆分数量
|
|
|
|
- int splitNum = 0;
|
|
|
|
- if(splitCache.containsKey(qrRepertoryColumnId)){
|
|
|
|
- splitNum = splitCache.get(qrRepertoryColumnId).getSplitNum();
|
|
|
|
- }
|
|
|
|
- // 非clone列,设置code和url
|
|
|
|
- String code = buildUniqueCode(uniqueSet, qrRepertoryColumn, codeSb, paramMap, qrRepertorySerialNumberMap, 0);
|
|
|
|
- if (code == null) {
|
|
|
|
- throw new RuntimeException("生成码失败,重复生成码次数超过" + REPEAT_BUILD_CODE_TIMES + "次");
|
|
|
|
- }
|
|
|
|
- //判断拆分数量是否为空
|
|
|
|
- if( splitNum >0){
|
|
|
|
- List<char[]> codeStr = segmentation(code, splitNum);
|
|
|
|
- for (char[] chars:codeStr) {
|
|
|
|
- QrInnerData qrInnerData = new QrInnerData();
|
|
|
|
- qrInnerData.setCode(String.valueOf(chars));
|
|
|
|
- qrInnerData.setQrRepertoryColumnId(qrRepertoryColumnId).setSortNumber(qrRepertoryColumn.getSortNumber());
|
|
|
|
- qrInnerData.setCodeIndex(codeIndex+=1);
|
|
|
|
- qrInnerDataList.add(qrInnerData);
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- QrInnerData qrInnerData = new QrInnerData();
|
|
|
|
- qrInnerData.setCode(code);
|
|
|
|
- qrInnerData.setQrRepertoryColumnId(qrRepertoryColumnId).setSortNumber(qrRepertoryColumn.getSortNumber());
|
|
|
|
- qrInnerData.setCodeIndex(codeIndex+=1);
|
|
|
|
- qrInnerDataList.add(qrInnerData);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- qrData.setInnerDataList(qrInnerDataList);
|
|
|
|
- qrDataList.add(qrData);
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- try {
|
|
|
|
- redisClient.delete("box_code_format_split");
|
|
|
|
- return qrDataList;
|
|
|
|
- } catch (Exception e) {
|
|
|
|
- redisClient.delete("box_code_format_split");
|
|
|
|
- log.error("封装码失败", e);
|
|
|
|
- if (++repeatTimes >= REPEAT_BUILD_CODE_TIMES) {
|
|
|
|
- throw new RuntimeException("生成码失败,重复生成码次数超过" + REPEAT_BUILD_CODE_TIMES + "次");
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return null;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 处理url和流水号
|
|
|
|
- */
|
|
|
|
- private void getUrlAndSerialNumber(List<QrRepertoryColumnVO> qrRepertoryColumnList, Long qrRepertoryId, Map<Long, String> urlMap, Map<String, QrRepertorySerialNumber> qrRepertorySerialNumberMap) {
|
|
|
|
- for (int i = 0; i < qrRepertoryColumnList.size(); i++) {
|
|
|
|
- QrRepertoryColumnVO qrRepertoryColumn = qrRepertoryColumnList.get(i);
|
|
|
|
- Long qrRepertoryColumnId = qrRepertoryColumn.getId();
|
|
|
|
- urlMap.put(qrRepertoryColumnId, "");
|
|
|
|
- // 使用到流水号参数的列
|
|
|
|
- String[] buildClassArr = qrRepertoryColumn.getQrFormatVO().getCodeVariableBuildClass().split(",");
|
|
|
|
- for (int j = 0; j < buildClassArr.length; j++) {
|
|
|
|
- String buildClass = buildClassArr[j];
|
|
|
|
- if (buildClass.startsWith(SerialBuildCode.SERIAL_START_WITH)) {
|
|
|
|
- // 查询码库流水号,若存在,则流水号从记录值开始;若不存在,从0开始
|
|
|
|
- QueryWrapper<QrRepertorySerialNumber> qrRepertorySerialNumberQw = new QueryWrapper<>();
|
|
|
|
- qrRepertorySerialNumberQw.eq("qr_repertory_column_id", qrRepertoryColumnId);
|
|
|
|
- qrRepertorySerialNumberQw.eq("child_index", j);
|
|
|
|
- // 加锁查询插入流水号
|
|
|
|
- RLock lock = redissonClient.getLock("serial_number_lock_" + qrRepertoryColumnId + "_" + j);
|
|
|
|
- QrRepertorySerialNumber qrRepertorySerialNumber = null;
|
|
|
|
- try {
|
|
|
|
- lock.lock();
|
|
|
|
- qrRepertorySerialNumber = qrRepertorySerialNumberMapper.selectOne(qrRepertorySerialNumberQw);
|
|
|
|
- if (qrRepertorySerialNumber == null) {
|
|
|
|
- qrRepertorySerialNumber = new QrRepertorySerialNumber()
|
|
|
|
- .setQrRepertoryId(qrRepertoryId)
|
|
|
|
- .setQrRepertoryColumnId(qrRepertoryColumnId)
|
|
|
|
- .setChildIndex(j)
|
|
|
|
- .setSerialBuildClass(buildClass)
|
|
|
|
- .setSerialNumber(0L);
|
|
|
|
- qrRepertorySerialNumberMapper.insert(qrRepertorySerialNumber);
|
|
|
|
- }
|
|
|
|
- } finally {
|
|
|
|
- lock.unlock();
|
|
|
|
- }
|
|
|
|
- // key:qr_repertory_column_id + child_index
|
|
|
|
- qrRepertorySerialNumberMap.put(qrRepertoryColumnId + "_" + j, qrRepertorySerialNumber);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 创建码文件
|
|
|
|
- */
|
|
|
|
- private void createCodeFile( QrRepertoryVO qrRepertory,String batchNumber,QrBoxCodeFormat boxCodeFormat,ArrayList<File> fileList) {
|
|
|
|
- List<QrRepertoryColumnVO> qrRepertoryColumnList = qrRepertory.getQrRepertoryColumnList();
|
|
|
|
- StringBuilder content = new StringBuilder();
|
|
|
|
- // 第一行为每列的名称,用“,”分隔
|
|
|
|
- String dataComposition = qrRepertoryColumnList.stream().map(col -> col.getAlias()).collect(Collectors.joining(","));
|
|
|
|
- content.append(dataComposition);
|
|
|
|
- //暂时根据项目幅面分,没有根据拆分数量分
|
|
|
|
- if(boxCodeFormat.getFormatNumber() > 1){
|
|
|
|
- for (int i = 1; i < boxCodeFormat.getFormatNumber(); i++) {
|
|
|
|
- content.append(",").append(dataComposition);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- content.append("\r\n");
|
|
|
|
- // 拼接码
|
|
|
|
- List<QrInnerData> innerDataList;
|
|
|
|
- String innerData;
|
|
|
|
- for (QrData qrData : qrDataList) {
|
|
|
|
- innerDataList = qrData.getInnerDataList();
|
|
|
|
- innerData = innerDataList.stream().map(qrInnerData -> qrInnerData.getCode()).collect(Collectors.joining(","));
|
|
|
|
- content.append(innerData).append("\r\n");
|
|
|
|
- }
|
|
|
|
- //如果文件不存在,创建一个文件
|
|
|
|
- try{
|
|
|
|
- if (!file.exists()) {
|
|
|
|
- file.mkdir();
|
|
|
|
- }
|
|
|
|
- }catch (Exception e){
|
|
|
|
- log.error("创建文件异常",e);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // 生成txt
|
|
|
|
- FileWriter fileWriter = new FileWriter(file.getPath()+"/"+ batchNumber + ".txt");
|
|
|
|
- fileWriter.write(content.toString());
|
|
|
|
- fileList.add(new File(file.getPath()+"/"+ batchNumber + ".txt"));
|
|
|
|
-
|
|
|
|
- //生成md5(用于前端校验是否被替换)
|
|
|
|
- String fileVerifyMd5 = DigestUtils.md5DigestAsHex(content.toString().getBytes(StandardCharsets.UTF_8));
|
|
|
|
- fileVerifyMd5List.add(fileVerifyMd5);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 生成不重复的码
|
|
|
|
- */
|
|
|
|
- private String buildUniqueCode( HashSet<String> uniqueSet, QrRepertoryColumnVO qrRepertoryColumn, StringBuilder codeSb, Map<String, Object> paramMap, Map<String, QrRepertorySerialNumber> qrRepertorySerialNumberMap, int buildTimes) {
|
|
|
|
- // 生成码
|
|
|
|
- buildCodeByClass(qrRepertoryColumn, codeSb, paramMap, qrRepertorySerialNumberMap);
|
|
|
|
- String code = codeSb.toString();
|
|
|
|
-
|
|
|
|
- // add成功,说明码没有重复
|
|
|
|
- if (uniqueSet.add(code)) {
|
|
|
|
- return code;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // 单个码重复次数大于上限
|
|
|
|
- if (buildTimes > REPEAT_BUILD_CODE_TIMES) {
|
|
|
|
- return null;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // 码重复,递归执行下一次
|
|
|
|
- return buildUniqueCode(uniqueSet, qrRepertoryColumn, codeSb, paramMap, qrRepertorySerialNumberMap, ++buildTimes);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 清空codeSb,调用buildSingleCode方法生成码
|
|
|
|
- */
|
|
|
|
- private void buildCodeByClass(QrRepertoryColumnVO qrRepertoryColumn, StringBuilder codeSb, Map<String, Object> paramMap, Map<String, QrRepertorySerialNumber> qrRepertorySerialNumberMap) {
|
|
|
|
- // 使用一个对象,删除内容,不每次都新建一个对象
|
|
|
|
- codeSb.delete(0, codeSb.length());
|
|
|
|
-
|
|
|
|
- String[] buildClassArr = qrRepertoryColumn.getQrFormatVO().getCodeVariableBuildClass().split(",");
|
|
|
|
-
|
|
|
|
- for (int j = 0; j < buildClassArr.length; j++) {
|
|
|
|
- String buildClass = buildClassArr[j];
|
|
|
|
- String code;
|
|
|
|
- if (buildClass.startsWith(SerialBuildCode.SERIAL_START_WITH)) {
|
|
|
|
- QrRepertorySerialNumber qrRepertorySerialNumber = qrRepertorySerialNumberMap.get(qrRepertoryColumn.getId() + "_" + j);
|
|
|
|
- // 查询当前流水号的值,放入map中
|
|
|
|
- paramMap.put(buildClass, qrRepertorySerialNumber.getSerialNumber());
|
|
|
|
- code = BuildCodeUtil.buildSingleCode(buildClass, paramMap);
|
|
|
|
- // 重新赋值
|
|
|
|
- qrRepertorySerialNumber.setSerialNumber(Long.parseLong(code));
|
|
|
|
- } else {
|
|
|
|
- code = BuildCodeUtil.buildSingleCode(buildClass, paramMap);
|
|
|
|
- }
|
|
|
|
- codeSb.append(code);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * zip加密
|
|
|
|
- * @param file
|
|
|
|
- * @param files txt文件
|
|
|
|
- * @param pas 密码
|
|
|
|
- * @param zipName 压缩后的名字
|
|
|
|
- */
|
|
|
|
- private void zipEncryption(File file ,ArrayList<File> files,String pas,String zipName){
|
|
|
|
- try {
|
|
|
|
- //创建压缩文件
|
|
|
|
- ZipFile zipFile = new ZipFile(file.getPath()+"/"+zipName);
|
|
|
|
- //设置压缩文件参数
|
|
|
|
- ZipParameters parameters = new ZipParameters();
|
|
|
|
- //设置压缩方法
|
|
|
|
- parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
|
|
|
|
-
|
|
|
|
- //设置压缩级别
|
|
|
|
- //DEFLATE_LEVEL_FASTEST - Lowest compression level but higher speed of compression
|
|
|
|
- //DEFLATE_LEVEL_FAST - Low compression level but higher speed of compression
|
|
|
|
- //DEFLATE_LEVEL_NORMAL - Optimal balance between compression level/speed
|
|
|
|
- //DEFLATE_LEVEL_MAXIMUM - High compression level with a compromise of speed
|
|
|
|
- //DEFLATE_LEVEL_ULTRA - Highest compression level but low speed
|
|
|
|
- parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
|
|
|
|
-
|
|
|
|
- //设置压缩文件加密
|
|
|
|
- parameters.setEncryptFiles(true);
|
|
|
|
-
|
|
|
|
- //设置加密方法
|
|
|
|
- parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_AES);
|
|
|
|
-
|
|
|
|
- //设置aes加密强度
|
|
|
|
- parameters.setAesKeyStrength(Zip4jConstants.AES_STRENGTH_256);
|
|
|
|
-
|
|
|
|
- //设置密码
|
|
|
|
- parameters.setPassword(pas);
|
|
|
|
-
|
|
|
|
- //添加文件到压缩文件
|
|
|
|
- zipFile.addFiles(files, parameters);
|
|
|
|
- } catch (ZipException e) {
|
|
|
|
- e.printStackTrace();
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 分割数量 -- 码.length / 要分割数量 = 最后一组+余数;
|
|
|
|
- * @param str 要分割码
|
|
|
|
- * @param groupSum 分割数量
|
|
|
|
- * @return 分割后的码
|
|
|
|
- */
|
|
|
|
- public static List<char[]> segmentation(String str, int groupSum){
|
|
|
|
- List<char[]> result = new ArrayList<>();
|
|
|
|
-
|
|
|
|
- if (null == str){
|
|
|
|
- return null;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (groupSum < 0 || str.length() < groupSum){
|
|
|
|
- result.add(str.toCharArray());
|
|
|
|
- }else {
|
|
|
|
- int group = str.length() / groupSum ;
|
|
|
|
- int count = 0;
|
|
|
|
- while (true){
|
|
|
|
- if (result.size() + 1 == groupSum){
|
|
|
|
- result.add(str.substring(count * group).toCharArray());
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- result.add(str.substring(count * group ,count * group + group ).toCharArray());
|
|
|
|
- count ++ ;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return result;
|
|
|
|
- }
|
|
|
|
}
|
|
}
|