|
package org.springblade.mdm.program.service;
|
|
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONObject;
|
import lombok.AllArgsConstructor;
|
import lombok.extern.slf4j.Slf4j;
|
import org.apache.commons.codec.digest.DigestUtils;
|
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
import org.apache.commons.compress.archivers.zip.ZipFile;
|
import org.apache.commons.compress.utils.SeekableInMemoryByteChannel;
|
import org.apache.commons.lang3.StringUtils;
|
import org.springblade.core.log.exception.ServiceException;
|
import org.springblade.core.mp.base.BizEntity;
|
import org.springblade.core.mp.base.BizServiceImpl;
|
import org.springblade.core.oss.OssTemplate;
|
import org.springblade.core.oss.model.BladeFile;
|
import org.springblade.core.redis.cache.BladeRedis;
|
import org.springblade.core.secure.utils.AuthUtil;
|
import org.springblade.core.tool.utils.FileUtil;
|
import org.springblade.core.tool.utils.Func;
|
import org.springblade.core.tool.utils.IoUtil;
|
import org.springblade.mdm.flow.service.CureFlowService;
|
import org.springblade.mdm.program.entity.NcNode;
|
import org.springblade.mdm.program.entity.NcProgram;
|
import org.springblade.mdm.program.entity.NcProgramExchange;
|
import org.springblade.mdm.program.mapper.NcProgramExchangeMapper;
|
import org.springblade.mdm.program.vo.DncSendBackData;
|
import org.springblade.mdm.utils.CustomBinaryReader;
|
import org.springframework.beans.BeanUtils;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.web.multipart.MultipartFile;
|
|
import java.io.*;
|
import java.nio.file.Files;
|
import java.nio.file.Path;
|
import java.nio.file.Paths;
|
import java.time.Duration;
|
import java.time.LocalDateTime;
|
import java.util.*;
|
|
/**
|
* DNC回传文件处理服务
|
*
|
* @author yangys
|
*/
|
@Slf4j
|
@Service
|
@AllArgsConstructor
|
public class DNCSendBackService extends BizServiceImpl<NcProgramExchangeMapper, NcProgramExchange> {
|
private final CureFlowService cureFlowService;
|
private final NcProgramService ncProgramService;
|
private final NcNodeService ncNodeService;
|
private final OssTemplate ossTemplate;
|
private final BladeRedis bladeRedis;
|
|
private String getFileKey(){
|
return "dncexpfile-"+ AuthUtil.getUserId();
|
}
|
/**
|
* dnc回传文件上传
|
* @param file DNC回传文件
|
* @return 压缩包内程序包名的列表
|
*/
|
public List<DncSendBackData> dncSendBackUpload(MultipartFile file) {
|
List<DncSendBackData> list;
|
try {
|
BladeFile bfile = ossTemplate.putFile(file);//上传,供后续入库使用
|
//设置一个缓存,2小时过期
|
bladeRedis.setEx(getFileKey(),bfile.getName(), Duration.ofHours(2));
|
|
InputStream zipFileInputStream = file.getInputStream();//test
|
|
byte[] bytes = FileUtil.copyToByteArray(zipFileInputStream);
|
list = parseDncZipFromByteArray(bytes);
|
|
} catch (IOException e) {
|
log.error("上传dnc回传文件失败",e);
|
throw new ServiceException("解析DNC回传数据失败");
|
}
|
return list;
|
}
|
|
|
/**
|
* 从压缩包 解析回传程序列表,这里解析目录即可,目录就是程序包名
|
* @param zipData 压缩包字节
|
* @return 回传程序列表
|
* @throws IOException
|
*/
|
List<DncSendBackData> parseDncZipFromByteArray(byte[] zipData) throws IOException {
|
List<DncSendBackData> list = new ArrayList<>();
|
|
//Map<String,String> fileMd5Map = new HashMap<>();
|
Map<String,DncSendBackData> fileDataMap = new HashMap<>();
|
try (SeekableInMemoryByteChannel channel = new SeekableInMemoryByteChannel(zipData);
|
ZipFile zipFile = new ZipFile(channel)) {
|
|
ZipArchiveEntry entry;
|
Enumeration<ZipArchiveEntry> entries = zipFile.getEntries();
|
while (entries.hasMoreElements()) {
|
entry = entries.nextElement();
|
DncSendBackData progData = new DncSendBackData();
|
String entryName = entry.getName();
|
if (entry.isDirectory()){
|
//目录,才是程序包,
|
//查询数据库,对应上才能确认时有效的程序包
|
String packageName = StringUtils.removeEnd(entryName,"/");
|
List<NcNode> pkgList = ncNodeService.lambdaQuery().eq(NcNode::getNodeType,NcNode.TYPE_PROGRAM_PACKAGE).eq(NcNode::getName, packageName).eq(NcNode::getIsLastEdition,1).list();
|
if(!pkgList.isEmpty()) {
|
NcNode programPackageNode = pkgList.get(0);
|
progData.setId(programPackageNode.getId());
|
progData.setProgramName(packageName);
|
progData.setFileBackTime(LocalDateTime.now());
|
progData.setProgramNo(programPackageNode.getProgramNo());
|
list.add(progData);
|
}
|
}
|
}
|
|
}
|
|
return list;
|
}
|
|
|
/**
|
* 入库回传文件,并启动固化流程
|
* @param ids id列表逗号分隔,程序包名 节点的id
|
* @return
|
*/
|
@Transactional
|
public void dncFileAccept(String ids) throws IOException {
|
List<Long> idList = Func.toLongList(ids);
|
//
|
NcProgramExchange exchange;
|
String pkgFileName = bladeRedis.get(getFileKey());
|
updateNodeDataByDNCBackData(pkgFileName,idList);
|
List<NcNode> pkgList = ncNodeService.listByIds(idList);
|
for(NcNode pkgNode :pkgList){
|
exchange = new NcProgramExchange();
|
exchange.setName(pkgNode.getName());
|
exchange.setExchangeType(2);//回传
|
exchange.setNcNodeId(pkgNode.getId());
|
|
this.save(exchange);
|
}
|
|
//cureFlowService.startCure(pkgList);
|
}
|
|
/**
|
* 更新节点,主要是创建 程序包名 的新版本。
|
* @param pkgFileName zip文件名
|
* @param programPackageIdList 程序包名 节点的id列表
|
* @throws IOException 访问文件异常
|
*/
|
void updateNodeDataByDNCBackData(String pkgFileName, List<Long> programPackageIdList) throws IOException {
|
InputStream inputStream = this.ossTemplate.statFileStream(pkgFileName);
|
byte[] bytes = FileUtil.copyToByteArray(inputStream);
|
|
List<NcNode> nodeList = new ArrayList<>();
|
List<String> entryNameList = new ArrayList<>();
|
try (SeekableInMemoryByteChannel channel = new SeekableInMemoryByteChannel(bytes);
|
ZipFile zipFile = new ZipFile(channel)) {
|
|
ZipArchiveEntry entry;
|
Enumeration<ZipArchiveEntry> entries = zipFile.getEntries();
|
while (entries.hasMoreElements()) {
|
entry = entries.nextElement();
|
entryNameList.add(entry.getName());
|
}
|
|
//根据内部文件,读取和分析程序包和程序文件数据
|
List<String> dirList = entryNameList.stream().filter(s -> s.endsWith("/")).toList();
|
for(String dir : dirList){
|
String programPackageName = StringUtils.removeEnd(dir,"/");
|
NcNode oriProgramPkg = this.ncNodeService.getLastEditionProgramPackage(programPackageName);
|
if(oriProgramPkg == null){
|
log.warn("未发现匹配的程序包名{}",programPackageName);
|
continue;
|
}
|
|
if(!programPackageIdList.contains(oriProgramPkg.getId())){
|
//不在勾选的范围内
|
continue;
|
}
|
//临时测试注释
|
|
NcNode newProgramPkg = new NcNode();
|
BeanUtils.copyProperties(oriProgramPkg, newProgramPkg);
|
|
clearBaseProperties(newProgramPkg);
|
newProgramPkg.setIsLastEdition(1);
|
|
ncNodeService.save(newProgramPkg);
|
|
//旧数据更新为老版本
|
oriProgramPkg.setIsLastEdition(0);;
|
ncNodeService.updateById(oriProgramPkg);
|
|
//查找包下的文件数据,
|
entryNameList.stream().filter(s -> s.startsWith(dir)).forEach(entryName -> {
|
log.info("{}下的文件:{}",dir,entryName);
|
if(!entryName.endsWith("/")){
|
//实际的文件
|
String fileName = StringUtils.removeStart(entryName,dir);//去除文件名路径部分
|
NcNode oldProgramNode = this.ncNodeService.getLastEditionProgramFile(fileName,oriProgramPkg.getId());
|
if(oldProgramNode == null){
|
log.info("{}找不到程序文件",entryName);
|
return;
|
}
|
|
NcNode newProgramNode = new NcNode();
|
BeanUtils.copyProperties(oriProgramPkg, newProgramNode);
|
clearBaseProperties(newProgramNode);
|
newProgramNode.setIsLastEdition(1);
|
ncNodeService.save(newProgramNode);
|
|
ncNodeService.updateById(oriProgramPkg);
|
|
}
|
});
|
}
|
|
}
|
|
}
|
|
void setBaseProperties(BizEntity entity, JSONObject jsonObject){
|
entity.setCreateTime(jsonObject.getDate("createTime"));
|
entity.setUpdateTime(jsonObject.getDate("updateTime"));
|
entity.setStatus(jsonObject.getInteger("status"));
|
entity.setCreateUser(jsonObject.getLong("createUser"));
|
entity.setUpdateUser(jsonObject.getLong("updateUser"));
|
}
|
|
void clearBaseProperties(BizEntity entity){
|
entity.setId(null);
|
entity.setCreateTime(null);
|
entity.setUpdateTime(null);
|
entity.setStatus(null);
|
entity.setCreateUser(null);
|
entity.setUpdateUser(null);
|
}
|
}
|