Przeglądaj źródła

修改生成码包逻辑为无状态

tanzhongran 3 lat temu
rodzic
commit
02e4f95166

+ 6 - 0
abi-cloud-qr-platform-server/pom.xml

@@ -31,6 +31,12 @@
             <version>1.0-SNAPSHOT</version>
         </dependency>
 
+        <dependency>
+            <groupId>com.abi.gut</groupId>
+            <artifactId>abi-cloud-boot-starter</artifactId>
+            <version>0.0.1</version>
+        </dependency>
+
         <!-- 外部jar包 -->
         <dependency>
             <groupId>org.springframework.cloud</groupId>

+ 4 - 648
abi-cloud-qr-platform-server/src/main/java/com/abi/qms/platform/infrastructure/mq/GenerateCodeConsumer.java

@@ -1,61 +1,17 @@
 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.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.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.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.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.RabbitListener;
-import org.springframework.amqp.support.AmqpHeaders;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.messaging.Message;
 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";
 
 	@Autowired
-	private QrPackageMapper qrPackageMapper;
-
-	@Autowired
-	private QrBoxCodeFormatMapper qrBoxCodeFormatMapper;
-
-	@Autowired
-	private QrRepertoryMapper qrRepertoryMapper;
-
-	@Autowired
-	private QrRepertorySerialNumberMapper qrRepertorySerialNumberMapper;
+	private GenerateCodeService generateCodeService;
 
 	@Autowired
 	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
 	@RabbitHandler
 	@RabbitListener(queues = GenerateCodeConsumer.GENERATE_CODE_BY_REPERTORY_QUEUE,ackMode = "AUTO")
@@ -145,21 +40,8 @@ public class GenerateCodeConsumer {
 			throw new BusinessException("队列监听数据为空!");
 		}
 		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) {
 			log.error("生成码失败", e);
 			// 回滚
@@ -169,530 +51,4 @@ public class GenerateCodeConsumer {
 			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;
-	}
 }

+ 39 - 0
abi-cloud-qr-platform-server/src/main/java/com/abi/qms/platform/infrastructure/rabbitmq/SendMqUtil.java

@@ -0,0 +1,39 @@
+//package com.abi.qms.platform.infrastructure.rabbitmq;
+//
+//import cn.hutool.json.JSONUtil;
+//import lombok.extern.slf4j.Slf4j;
+//import org.springframework.amqp.rabbit.core.RabbitTemplate;
+//import org.springframework.stereotype.Component;
+//
+//import javax.annotation.Resource;
+//
+///**
+// * 发送MQ工具类
+// * @author AndyTan
+// */
+//@Component
+//@Slf4j
+//public class SendMqUtil {
+//
+//    @Resource(name="firstRabbitTemplate")
+//    private RabbitTemplate firstRabbitTemplate;
+//
+//    /**
+//     * 发送mq
+//     * @param obj
+//     */
+//    public void sendMq(String exchangeName,Object obj){
+//        firstRabbitTemplate.convertAndSend(exchangeName,null, JSONUtil.toJsonStr(obj));
+//    }
+//
+//
+//    public void sendDelayedMessage(String exchangeName,String routingKey,Object obj,Integer delay) {
+//        firstRabbitTemplate.convertAndSend(exchangeName, routingKey, JSONUtil.toJsonStr(obj), a -> {
+//            a.getMessageProperties().setExpiration(String.valueOf(delay));
+//            return a;
+//        });
+//    }
+//
+//
+//
+//}

+ 75 - 0
abi-cloud-qr-platform-server/src/main/java/com/abi/qms/platform/infrastructure/rabbitmq/config/DemoMq.java

@@ -0,0 +1,75 @@
+package com.abi.qms.platform.infrastructure.rabbitmq.config;
+
+
+import com.abi.qms.platform.infrastructure.rabbitmq.receiver.DemoMqReceiver;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.amqp.core.*;
+import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
+import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author congcong
+ */
+//@Configuration
+@Slf4j
+public class DemoMq {
+
+	//新增加MQ修改下面这两个即可
+	/**
+	 * 业务前缀
+	 */
+	private static final String MQ_PREFIX = "demo";
+
+	/**
+	 * MQ消费对象
+	 */
+	@Autowired
+	private DemoMqReceiver receiver;
+
+	//根据规则拼接出队列和交换器
+
+	public static final String EXCHANGE_NAME = MQ_PREFIX+"_callback_exchange";
+
+	public static final String QUEUE_NAME = MQ_PREFIX+"_callback_queue";
+
+	public static final String BINDING_NAME = MQ_PREFIX+"_callback_binding";
+
+	//往容器放入交换器、队列、绑定
+
+	@Bean(EXCHANGE_NAME)
+	public FanoutExchange fanoutExchange() {
+		return ExchangeBuilder.fanoutExchange(EXCHANGE_NAME).durable(true).build();
+	}
+
+	@Bean(QUEUE_NAME)
+	public Queue callbackQueue() {
+		return new Queue(QUEUE_NAME, true, false, false);
+	}
+
+	@Bean(BINDING_NAME)
+	public Binding callBackQueueBinding(@Qualifier(QUEUE_NAME) Queue queue, @Qualifier(EXCHANGE_NAME) FanoutExchange exchange) {
+		return BindingBuilder.bind(queue).to(exchange);
+	}
+
+	@Bean
+	public SimpleMessageListenerContainer listenerContainer(@Qualifier(QUEUE_NAME) Queue queue,
+															@Qualifier("firstConnectionFactory") CachingConnectionFactory connectionFactory) {
+		SimpleMessageListenerContainer container = getContainer(connectionFactory);
+		container.setQueues(queue);
+		container.setMessageListener(receiver);
+		return container;
+	}
+
+	private SimpleMessageListenerContainer getContainer(@Qualifier("firstConnectionFactory") CachingConnectionFactory firstConnectionFactory) {
+		SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(firstConnectionFactory);
+		container.setConcurrentConsumers(1);
+		container.setMaxConcurrentConsumers(2);
+		container.setPrefetchCount(0);
+		container.setAcknowledgeMode(AcknowledgeMode.MANUAL);
+		return container;
+	}
+}

+ 75 - 0
abi-cloud-qr-platform-server/src/main/java/com/abi/qms/platform/infrastructure/rabbitmq/config/GenerateQrCodeMq.java

@@ -0,0 +1,75 @@
+package com.abi.qms.platform.infrastructure.rabbitmq.config;
+
+
+import com.abi.qms.platform.infrastructure.rabbitmq.receiver.DemoMqReceiver;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.amqp.core.*;
+import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
+import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 生成二维码MQ
+ */
+//@Configuration
+@Slf4j
+public class GenerateQrCodeMq {
+
+	//新增加MQ修改下面这两个即可
+	/**
+	 * 业务前缀
+	 */
+	private static final String MQ_PREFIX = "generate_qr_code";
+
+	/**
+	 * MQ消费对象
+	 */
+	@Autowired
+	private DemoMqReceiver receiver;
+
+	//根据规则拼接出队列和交换器
+
+	public static final String EXCHANGE_NAME = MQ_PREFIX+"_callback_exchange";
+
+	public static final String QUEUE_NAME = MQ_PREFIX+"_callback_queue";
+
+	public static final String BINDING_NAME = MQ_PREFIX+"_callback_binding";
+
+	//往容器放入交换器、队列、绑定
+
+	@Bean(EXCHANGE_NAME)
+	public FanoutExchange fanoutExchange() {
+		return ExchangeBuilder.fanoutExchange(EXCHANGE_NAME).durable(true).build();
+	}
+
+	@Bean(QUEUE_NAME)
+	public Queue callbackQueue() {
+		return new Queue(QUEUE_NAME, true, false, false);
+	}
+
+	@Bean(BINDING_NAME)
+	public Binding callBackQueueBinding(@Qualifier(QUEUE_NAME) Queue queue, @Qualifier(EXCHANGE_NAME) FanoutExchange exchange) {
+		return BindingBuilder.bind(queue).to(exchange);
+	}
+
+	@Bean
+	public SimpleMessageListenerContainer listenerContainer(@Qualifier(QUEUE_NAME) Queue queue,
+															@Qualifier("firstConnectionFactory") CachingConnectionFactory connectionFactory) {
+		SimpleMessageListenerContainer container = getContainer(connectionFactory);
+		container.setQueues(queue);
+		container.setMessageListener(receiver);
+		return container;
+	}
+
+	private SimpleMessageListenerContainer getContainer(@Qualifier("firstConnectionFactory") CachingConnectionFactory firstConnectionFactory) {
+		SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(firstConnectionFactory);
+		container.setConcurrentConsumers(1);
+		container.setMaxConcurrentConsumers(2);
+		container.setPrefetchCount(0);
+		container.setAcknowledgeMode(AcknowledgeMode.AUTO);
+		return container;
+	}
+}

+ 77 - 0
abi-cloud-qr-platform-server/src/main/java/com/abi/qms/platform/infrastructure/rabbitmq/config/common/RabbitMqConfig.java

@@ -0,0 +1,77 @@
+//package com.abi.qms.platform.infrastructure.rabbitmq.config.common;
+//
+//import lombok.extern.slf4j.Slf4j;
+//import org.springframework.amqp.core.Message;
+//import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
+//import org.springframework.amqp.rabbit.connection.ConnectionFactory;
+//import org.springframework.amqp.rabbit.connection.CorrelationData;
+//import org.springframework.amqp.rabbit.core.RabbitTemplate;
+//import org.springframework.beans.factory.annotation.Qualifier;
+//import org.springframework.beans.factory.annotation.Value;
+//import org.springframework.context.annotation.Bean;
+//import org.springframework.context.annotation.Configuration;
+//import org.springframework.context.annotation.Primary;
+//
+//import static org.springframework.amqp.rabbit.connection.CachingConnectionFactory.ConfirmType.SIMPLE;
+//
+//@Configuration
+//@Slf4j
+//public class RabbitMqConfig {
+//
+//    @Bean(name = "firstConnectionFactory")
+//    @Primary
+//    public CachingConnectionFactory firstConnectionFactory(
+//            @Value("${spring.rabbitmq.addresses}") String address,
+//            @Value("${spring.rabbitmq.username}") String username,
+//            @Value("${spring.rabbitmq.password}") String password,
+//            @Value("${spring.rabbitmq.virtual-host}") String virtualHost) {
+//        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
+//        connectionFactory.setAddresses(address);
+//        connectionFactory.setUsername(username);
+//        connectionFactory.setPassword(password);
+//        connectionFactory.setVirtualHost(virtualHost);
+//        //    #确认消息已发送到交换机(Exchange)
+//        connectionFactory.setPublisherConfirmType(SIMPLE);
+//        //    #确认消息已发送到交换机(Exchange)
+//        connectionFactory.setPublisherReturns(true);
+//        return connectionFactory;
+//    }
+//
+//    @Bean(name = "firstRabbitTemplate")
+//    @Primary
+//    public RabbitTemplate firstRabbitTemplate(
+//            @Qualifier("firstConnectionFactory") ConnectionFactory connectionFactory) {
+//        RabbitTemplate firstRabbitTemplate = new RabbitTemplate(connectionFactory);
+//        firstRabbitTemplate.setMandatory(true);
+//        firstRabbitTemplate.setConfirmCallback(
+//                new RabbitTemplate.ConfirmCallback() {
+//                    @Override
+//                    public void confirm(
+//                            CorrelationData correlationData, boolean ack, String cause) {
+//                        log.info("ConfirmCallback:     " + "相关数据:" + correlationData);
+//                        log.info("ConfirmCallback:     " + "确认情况:" + ack);
+//                        log.info("ConfirmCallback:     " + "原因:" + cause);
+//                    }
+//                });
+//
+//        firstRabbitTemplate.setReturnCallback(
+//                new RabbitTemplate.ReturnCallback() {
+//                    @Override
+//                    public void returnedMessage(
+//                            Message message,
+//                            int replyCode,
+//                            String replyText,
+//                            String exchange,
+//                            String routingKey) {
+//                        log.info("ReturnCallback:     " + "消息:" + message);
+//                        log.info("ReturnCallback:     " + "回应码:" + replyCode);
+//                        log.info("ReturnCallback:     " + "回应信息:" + replyText);
+//                        log.info("ReturnCallback:     " + "交换机:" + exchange);
+//                        log.info("ReturnCallback:     " + "路由键:" + routingKey);
+//                    }
+//                });
+//
+//        return firstRabbitTemplate;
+//    }
+//
+//}

+ 46 - 0
abi-cloud-qr-platform-server/src/main/java/com/abi/qms/platform/infrastructure/rabbitmq/receiver/DemoMqReceiver.java

@@ -0,0 +1,46 @@
+package com.abi.qms.platform.infrastructure.rabbitmq.receiver;
+
+import cn.hutool.json.JSONUtil;
+import com.abi.qms.platform.dao.entity.UserInfo;
+import com.abi.qms.platform.infrastructure.rabbitmq.config.DemoMq;
+import com.rabbitmq.client.Channel;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.amqp.core.Message;
+import org.springframework.amqp.rabbit.annotation.RabbitListener;
+import org.springframework.amqp.rabbit.listener.api.ChannelAwareMessageListener;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author 接受MQ消费demo
+ */
+
+//@Component
+@Slf4j
+public class DemoMqReceiver implements ChannelAwareMessageListener {
+
+    @Override
+    @RabbitListener(queues = DemoMq.QUEUE_NAME)
+    public void onMessage(Message message, Channel channel) throws Exception {
+        long deliveryTag = message.getMessageProperties().getDeliveryTag();
+        try {
+            String messageInfo = new String(message.getBody(), "utf-8");
+            doReceiveMessage(messageInfo);
+            channel.basicAck(deliveryTag, false);
+        } catch (Exception e) {
+            log.error("DEMO异常:{}", e);
+            channel.basicAck(deliveryTag, false);
+        }
+    }
+
+    /**
+     * 业务代码
+     *
+     * @param messageInfo
+     */
+    private void doReceiveMessage(String messageInfo) {
+        UserInfo userInfo = JSONUtil.toBean(messageInfo, UserInfo.class);
+        log.info("DEMO接到MQ信息拉----》" + messageInfo);
+        log.info("转对象----》" + userInfo);
+    }
+
+}

+ 36 - 0
abi-cloud-qr-platform-server/src/main/java/com/abi/qms/platform/infrastructure/rabbitmq/receiver/GenerateQrCodeMqReceiver.java

@@ -0,0 +1,36 @@
+package com.abi.qms.platform.infrastructure.rabbitmq.receiver;
+
+import com.abi.qms.platform.infrastructure.rabbitmq.config.GenerateQrCodeMq;
+import com.abi.qms.platform.service.GenerateCodeService;
+import com.rabbitmq.client.Channel;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.amqp.core.Message;
+import org.springframework.amqp.rabbit.annotation.RabbitListener;
+import org.springframework.amqp.rabbit.listener.api.ChannelAwareMessageListener;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author 生成二维码MQ消费者
+ */
+
+//@Component
+@Slf4j
+public class GenerateQrCodeMqReceiver implements ChannelAwareMessageListener {
+
+    @Autowired
+    private GenerateCodeService generateCodeService;
+
+
+    @Override
+    @RabbitListener(queues = GenerateQrCodeMq.QUEUE_NAME)
+    public void onMessage(Message message, Channel channel) throws Exception {
+        try {
+            String messageInfo = new String(message.getBody(), "utf-8");
+            generateCodeService.generateQrCode(Long.parseLong(messageInfo));
+        } catch (Exception e) {
+            log.error("DEMO异常:{}", e);
+        }
+    }
+
+}

+ 14 - 0
abi-cloud-qr-platform-server/src/main/java/com/abi/qms/platform/service/GenerateCodeService.java

@@ -0,0 +1,14 @@
+package com.abi.qms.platform.service;
+
+/**
+ * 生成二维码service
+ */
+public interface GenerateCodeService {
+
+    /**
+     * 生成二维码
+     * @param qrPackageId
+     */
+    void generateQrCode(Long qrPackageId);
+
+}

+ 649 - 0
abi-cloud-qr-platform-server/src/main/java/com/abi/qms/platform/service/impl/GenerateCodeServiceImpl.java

@@ -0,0 +1,649 @@
+package com.abi.qms.platform.service.impl;
+
+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.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.mq.GenerateCodeConsumer;
+import com.abi.qms.platform.infrastructure.mq.TableStoreBatchInsertConsumer;
+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.GenerateCodeService;
+import com.abi.qms.platform.service.QrPackageBookingOrderService;
+import com.abi.qms.platform.service.QrPackageService;
+import com.abi.task.common.api.exception.BusinessException;
+import com.abi.task.common.utils.PojoConverterUtils;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import lombok.SneakyThrows;
+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.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.RabbitListener;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+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;
+
+@Slf4j
+@Service
+public class GenerateCodeServiceImpl implements GenerateCodeService {
+
+
+
+    @Autowired
+    private QrPackageMapper qrPackageMapper;
+
+    @Autowired
+    private QrBoxCodeFormatMapper qrBoxCodeFormatMapper;
+
+    @Autowired
+    private QrRepertoryMapper qrRepertoryMapper;
+
+    @Autowired
+    private QrRepertorySerialNumberMapper qrRepertorySerialNumberMapper;
+
+    @Autowired
+    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;
+
+    /** 允许单个码生成重复的次数 */
+    private static final int REPEAT_BUILD_CODE_TIMES = 10;
+
+    /**
+     * 生成码
+     */
+    @Override
+    public void generateQrCode(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<>();
+        //md5列表
+        ArrayList<String> fileVerifyMd5List = new ArrayList<>();
+        //该包下共有多少码数量
+        Long sum = 0L;
+
+        // 更改生成状态为生成中
+        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;
+
+            // 循环生成码
+            List<QrData> codeList = doLoopGenerateCode(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<QrCode> qrCodes = convertToTableStoreEntity(codeList, qrPackageBatch);
+            log.info("6 loopGenerateCode transform tableStoreEntityList -->"+System.currentTimeMillis());
+
+            // table数据库  批量插入
+            saveTableStore(qrCodes);
+            // 累加数量
+            sum = sum + qrCodes.size();
+            log.info("7 loopGenerateCode save tablestore async -->"+System.currentTimeMillis());
+
+            // 创建码文件
+            String md5 = createCodeFile(qrRepertory, batchNumber, qrBoxCodeFormat, fileList, codeList);
+            fileVerifyMd5List.add(md5);
+            log.info("8 loopGenerateCode create file -->"+System.currentTimeMillis());
+        }
+
+        //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";
+        //压缩密码
+        String pas = RandomCodeUtils.getStr(6);
+        log.info("生成密码:"+pas);
+        //压缩加密文件
+        File file = new File("/code");
+        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);
+    }
+
+    /**
+     * 拿到二维码背后的递增数
+     * @return
+     */
+    private Long getQrIndex(){
+        QueryWrapper<QrIndex>  indexQuery= new QueryWrapper<>();
+        indexQuery.orderByDesc("id").last("limit 1");
+        QrIndex qrIndex = qrIndexMapper.selectOne(indexQuery);
+
+        return qrIndex.getIndexCurrent();
+    }
+
+    /**
+     * 放入二维码背后的递增书
+     * @param codeIndex
+     */
+    private void setQrIndex(Long codeIndex){
+        QueryWrapper<QrIndex>  indexQuery= new QueryWrapper<>();
+        indexQuery.orderByDesc("id").last("limit 1");
+        QrIndex qrIndex = qrIndexMapper.selectOne(indexQuery);
+
+        //保存Db index的修改
+        qrIndex.setIndexCurrent(codeIndex);
+        qrIndexMapper.updateById(qrIndex);
+    }
+
+    /**
+     * 转换成 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<QrCode> convertToTableStoreEntity(List<QrData> codeList,QrPackageBatch qrPackageBatch){
+        //保存所有码的列表
+        List<QrCode> 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(List<QrCode> qrCodes) {
+        // 开始多线程写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));
+        }
+    }
+
+
+    /**
+     * qrRepertoryColumnList  码库的列
+     * qrRepertoryId 码库id
+     * urlMap 存放每列的url
+     * qrRepertorySerialNumberMap 用于标记同一列的第几个码格式变量
+     * qrNumber 码数量
+     * batchNumber 批次号
+     * localDateTime 创建时间
+     * repeatTimes 失败次数
+     * formatNumber 幅面数量
+     */
+    private List<QrData> doLoopGenerateCode(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 ) {
+        //生成码数据
+        final List<QrData> qrDataList = new LinkedList<>();
+        Long qrIndex = getQrIndex();
+
+        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(++qrIndex);
+                                qrInnerDataList.add(qrInnerData);
+                            }
+                        } else {
+                            QrInnerData qrInnerData = new QrInnerData();
+                            qrInnerData.setCode(code);
+                            qrInnerData.setQrRepertoryColumnId(qrRepertoryColumnId).setSortNumber(qrRepertoryColumn.getSortNumber());
+                            qrInnerData.setCodeIndex(++qrIndex);
+                            qrInnerDataList.add(qrInnerData);
+                        }
+                    }
+                }
+                qrData.setInnerDataList(qrInnerDataList);
+                qrDataList.add(qrData);
+            }
+            //保存index
+            setQrIndex(qrIndex);
+
+            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 String createCodeFile( QrRepertoryVO qrRepertory,String batchNumber,QrBoxCodeFormat boxCodeFormat,ArrayList<File> fileList,List<QrData> qrDataList) {
+        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");
+        }
+        //如果文件不存在,创建一个文件
+        File file = new File("/code");
+        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));
+        return 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;
+    }
+
+}

+ 6 - 2
abi-cloud-qr-platform-server/src/main/java/com/abi/qms/platform/service/impl/QrPackageServiceImpl.java

@@ -116,6 +116,9 @@ public class QrPackageServiceImpl implements QrPackageService {
     @Autowired
     private QrPackageBookingOrderService qrPackageBookingOrderService;
 
+//    @Autowired
+//    private SendMqUtil sendMqUtil;
+
     /**
      * 保存码包
      */
@@ -572,6 +575,8 @@ public class QrPackageServiceImpl implements QrPackageService {
 
         // 码库类型为系统生成时,放入rabbitmq,生成码
         if (QrRepertoryTypeEnum.SYSTEM_GENERATE.is(qrPackage.getQrRepertoryType())) {
+            //暂时这个有问题,先发老的
+            //sendMqUtil.sendMq(GenerateQrCodeMq.QUEUE_NAME,req.getId());
             amqpTemplate.convertAndSend(GenerateCodeConsumer.GENERATE_CODE_BY_REPERTORY_QUEUE, req.getId());
         }
     }
@@ -701,9 +706,8 @@ public class QrPackageServiceImpl implements QrPackageService {
 
     /**
      * 码包生成完成后发送邮件给码包厂负责人邮箱
-     *
      * @param targetEmail
-     * @param sapOrderNo
+     * @param qrPackage
      * @param filename
      * @param password
      */