package org.springblade.mdm.program.service; import com.alibaba.csp.sentinel.util.StringUtil; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.StringUtils; import org.flowable.engine.HistoryService; import org.flowable.engine.history.HistoricProcessInstance; import org.springblade.core.log.exception.ServiceException; import org.springblade.core.mp.base.BizServiceImpl; import org.springblade.core.oss.OssTemplate; import org.springblade.mdm.basesetting.machine.service.MachineService; import org.springblade.mdm.basesetting.machine.entity.Machine; import org.springblade.mdm.flow.constants.FlowConstant; import org.springblade.mdm.flow.entity.FlowProgramFile; import org.springblade.mdm.flow.service.FlowProgramFileService; import org.springblade.mdm.flow.service.TaskDispatchService; import org.springblade.mdm.program.entity.NcNode; import org.springblade.mdm.program.entity.NcNodeHis; import org.springblade.mdm.program.entity.NcProgramApproved; import org.springblade.mdm.program.entity.NcProgramExchange; import org.springblade.mdm.program.mapper.NcProgramExchangeMapper; import org.springblade.mdm.program.service.programannotation.*; import org.springblade.system.feign.IDictClient; import org.springframework.stereotype.Service; import java.io.*; import java.util.*; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; /** * 下发/回传程序统计 * * @author yangys */ @Slf4j @Service @AllArgsConstructor public class NcProgramExportDNCService extends BizServiceImpl { private final IDictClient dictClient; private final MachineService machineService; private final NcProgramApprovedService approvedService; private final NcNodeService ncNodeService; private final NcNodeHisService ncNodeHisService; private final OssTemplate ossTemplate; private final FlowProgramFileService flowProgramFileService; private final HistoryService historyService; private final TaskDispatchService taskDispatchService; private final MachineAnnotationConfig annotationConfig; private final AnnotationProcessorHelper annotationProcessorHelper; /** * 导出dnc压缩包 * @param approvedIdArray 待导出审批表id数组 */ public void exportDnc(Long[] approvedIdArray, OutputStream os) throws IOException { //FileOutputStream fos = new FileOutputStream("d:/exportDnc.zip"); try (ZipOutputStream zipOut = new ZipOutputStream(os);os) {//os for (Long approvedId : approvedIdArray) { NcProgramApproved approved = approvedService.getById(approvedId); addProgramPackageToZip(zipOut,approved); approved.setStatus(NcProgramApproved.STATUS_EXPORTED); approvedService.updateById(approved); NcNodeHis pkgNodeHis = this.ncNodeHisService.getById(approved.getNcNodeId()); if(pkgNodeHis.isDeviationProgram()){ //偏离单的程序,如果审批导出记录是解锁形成的,还是需要锁定;普通试切过的,不锁定 HistoricProcessInstance hisInst = historyService.createHistoricProcessInstanceQuery().processInstanceId(approved.getProcessInstanceId()).singleResult(); if(hisInst != null && hisInst.getProcessDefinitionKey().equals(FlowConstant.UNLOCK_PROCESS_KEY)){ NcNode pkgNode = this.ncNodeService.getById(approved.getNcNodeId()); if(pkgNode != null) { pkgNode.lock("下发导出锁定"); ncNodeService.updateById(pkgNode); } } } } }catch(Exception e){ Throwable [] err = e.getSuppressed(); throw new ServiceException("导出工控网错误"+e.getMessage()); } } /** * 将程序包和下属文件加入压缩包 * @param zipOut * @param approved */ private void addProgramPackageToZip(ZipOutputStream zipOut, NcProgramApproved approved) throws IOException{ NcNodeHis packageNodeHis = ncNodeHisService.getById(approved.getNcNodeId()); String packageFolder = packageNodeHis.getName()+"/"; ZipEntry zipEntry = new ZipEntry(packageFolder);// "/"结尾表示文件夹 zipOut.putNextEntry(zipEntry); zipOut.closeEntry(); Machine machine = machineService.getByCode(packageNodeHis.getMachineCode());//程序包节点,获取注释用 List programNodes = ncNodeHisService.lambdaQuery().eq(NcNodeHis::getParentId, approved.getNcNodeId()).list(); FlowProgramFile programFile; NcNodeHis programPackageNode = this.ncNodeHisService.getById(approved.getNcNodeId()); String status = AnnotationUtil.SQ; if(programPackageNode.isDeviationProgram()){ status = AnnotationUtil.LG; }else if(programPackageNode.hasCured()){ status = AnnotationUtil.GH; } long deviationSerial = -1;//偏离单序号 ,-1为非偏离单,不需要加入 if(packageNodeHis.isDeviationProgram()) { deviationSerial = taskDispatchService.getDeviationSerial(packageNodeHis.getProgramNo()); } for (NcNodeHis node : programNodes) { String filePathInZip = genFilePathInZip(packageFolder,node,deviationSerial); programFile = this.flowProgramFileService.getById(node.getFlowProgramFileId()); if(programFile.isProgram()) {//程序文件,才会加入压缩包 InputStream inputStream = ossTemplate.statFileStream(programFile.getOssName()); String sendDir = machine.getProgSendDir()==null? StringUtil.EMPTY:machine.getProgSendDir(); //AnnotationProcessor annoProcessor = ProcessorHelper.getProcessor(machine.getControlSystem(),annotationConfig); AnnotationProcessor annoProcessor = this.annotationProcessorHelper.getProcessor(machine.getControlSystem()); AnnotationData annoData = new AnnotationData(); annoData.setSendPath(sendDir); annoData.setProgramStatus(status); annoData.setDeviation(programPackageNode.getDeviation()); annoData.setFilename(programFile.getName()); InputStream addedInsFinal = annoProcessor.putAnnotation(annoData,inputStream); addedInsFinal.reset(); this.addInputStreamToZip(zipOut, addedInsFinal, filePathInZip); } } } /** * 生成在zip中的文件路径 * @param packageFolder zip中的文件夹 * @param programNode 程序节点 * @param deviationSerial 临时更改单序号 * @return zip中的文件路径 */ String genFilePathInZip(String packageFolder,NcNodeHis programNode,long deviationSerial){ //为文件名增加偏离单号 String filePathInZip; if(deviationSerial != -1){ //加入偏离单序号 String ext = FilenameUtils.getExtension(programNode.getName()); String dotExt = StringUtils.isNotBlank(ext)?"."+ext:ext;//带点的扩展名 String temp = programNode.getName(); if(StringUtils.isNotBlank(ext)) { temp = StringUtils.removeEnd(temp,dotExt); } filePathInZip = packageFolder + temp+"-P"+deviationSerial+dotExt; }else{ //非偏离单,直接使用原文件名 filePathInZip = packageFolder + programNode.getName(); } return filePathInZip; } /** * 将 输入流 中的内容写入zip * @param zipOut zip输出流 * @param inputStream 输入流 * @param entryName 文件名 * @throws IOException 写文件异常 */ void addInputStreamToZip(ZipOutputStream zipOut, InputStream inputStream, String entryName) throws IOException { // 创建新的 ZIP 条目 ZipEntry zipEntry = new ZipEntry(entryName); zipOut.putNextEntry(zipEntry); // 将输入流写入 ZIP 输出流 byte[] buffer = new byte[1024]; int length; while ((length = inputStream.read(buffer)) >= 0) { zipOut.write(buffer, 0, length); } // 关闭当前条目 zipOut.closeEntry(); } }