1、project新增生成自动化报告接口

This commit is contained in:
2025-11-25 16:38:08 +08:00
parent 64dcf99f3b
commit bd7c0bb29c
11 changed files with 232 additions and 17 deletions

View File

@@ -121,4 +121,13 @@ public class DataClientFeignClientImpl implements IDataFeignClient {
}
}
@Override
public void downloadFileToLocal(Long fileId,String path) {
try {
dataClient.downloadFileToLocal(fileId,path);
} catch (Exception e) {
log.error("下载文件响应", e);
}
}
}

View File

@@ -5,6 +5,7 @@ import com.sdm.common.entity.req.data.*;
import com.sdm.common.entity.req.system.LaunchApproveReq;
import com.sdm.common.entity.resp.data.FileMetadataInfoResp;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
@@ -43,5 +44,9 @@ public interface IDataFeignClient {
@GetMapping("/data/queryFileMetadataInfo")
SdmResponse<FileMetadataInfoResp> queryFileMetadataInfo(@RequestParam(value = "uuid") String uuid, @RequestParam(value = "uuidOwnType") String uuidOwnType);
@PostMapping("/data/downloadFileToLocal")
void downloadFileToLocal(@RequestParam(value = "fileId") @Validated Long fileId, @RequestParam(value = "path") @Validated String path);
}

View File

@@ -7,6 +7,7 @@ import com.alibaba.fastjson2.JSONObject;
import com.sdm.common.entity.ExportExcelFormat;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
@@ -258,7 +259,7 @@ public class ExcelUtil {
String value = rowObj.getString(exportExcelFormat.getKey());
if(value != null && !"null".equalsIgnoreCase(value)) {
JSONObject dictData = exportExcelFormat.getDictData();
if(dictData != null)
if(ObjectUtils.isNotEmpty(dictData))
{
value = dictData.getString(value);
}

View File

@@ -405,6 +405,17 @@ public class DataFileController implements IDataFeignClient {
return IDataFileService.batchAddFileInfo(req);
}
/**
* 下载文件到本地临时目录
*
* @param fileId
* @param path
*/
@PostMapping("/downloadFileToLocal")
@Operation(summary = "下载文件到本地临时目录", description = "下载文件到本地临时目录")
public void downloadFileToLocal(@RequestParam(value = "fileId") @Validated Long fileId, @RequestParam(value = "path") @Validated String path) {
IDataFileService.downloadFileToLocal(fileId,path);
}
}

View File

@@ -320,4 +320,9 @@ public interface IDataFileService {
SdmResponse<List<BatchAddFileInfoResp>> batchAddFileInfo(UploadFilesReq req);
/**
* 下载文件到本地临时目录
*/
void downloadFileToLocal(Long fileId,String path);
}

View File

@@ -59,10 +59,7 @@ import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
@@ -2205,4 +2202,30 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService {
}, nonSensitiveTaskPool);
}
@Override
public void downloadFileToLocal(Long fileId,String path) {
try {
FileMetadataInfo fileMetadataInfo = fileMetadataInfoService.lambdaQuery().eq(FileMetadataInfo::getId, fileId).one();
if (ObjectUtils.isEmpty(fileMetadataInfo)) {
return;
}
String fileObjectKey = fileMetadataInfo.getObjectKey();
boolean hasDownloadPermission = fileUserPermissionService.hasFilePermission(fileMetadataInfo.getId(), ThreadLocalContext.getUserId(), FilePermissionEnum.DOWNLOAD);
if (!hasDownloadPermission) {
return;
}
// 从MinIO下载文件
byte[] fileData = minioService.downloadFile(fileObjectKey);
// 写入响应流
File folder = new File(path);
folder.mkdir();
FileOutputStream outputStream = new FileOutputStream(path + File.separator + fileMetadataInfo.getOriginalName());
outputStream.write(fileData);
outputStream.flush();
outputStream.close();
} catch (Exception e) {
log.error("下载文件失败", e);
}
}
}

View File

@@ -1548,4 +1548,35 @@ public class SystemFileIDataFileServiceImpl implements IDataFileService {
}
return SdmResponse.success();
}
@Override
public void downloadFileToLocal(Long fileId,String downloadPath) {
if (StringUtils.isNotBlank(downloadPath) && downloadPath.contains("..")) {
log.error(downloadPath + "非法文件路径!");
return;
}
String path = Tools.getRootPath(rootPath, String.valueOf(ThreadLocalContext.getTenantId())) + File.separator + downloadPath;
File file = new File(path);
if (!file.exists()) {
log.error("文件不存在" + path);
}
try {
// 以流的形式下载文件
InputStream fis = new BufferedInputStream(new FileInputStream(file));
byte[] buffer = new byte[fis.available()];
// 读取fis的数据到buffer数组里
fis.read(buffer);
fis.close();
byte[] fileBuffer = buffer;
OutputStream toClient = new BufferedOutputStream(new FileOutputStream(path));
toClient.write(fileBuffer);
toClient.flush();
toClient.close();
} catch (IOException e) {
log.error("下载文件失败:" + e);
}
}
}

View File

@@ -5,14 +5,12 @@ import com.sdm.common.entity.req.data.CreateDirReq;
import com.sdm.common.entity.req.data.QueryDirReq;
import com.sdm.common.entity.req.data.UploadFilesReq;
import com.sdm.project.model.entity.SimulationRun;
import com.sdm.project.model.req.GetRunVersionReq;
import com.sdm.project.model.req.ProjectTreeTagReq;
import com.sdm.project.model.req.SpdmAddTaskRunReq;
import com.sdm.project.model.req.SpdmTaskRunReq;
import com.sdm.project.model.req.*;
import com.sdm.project.model.resp.RunVersionInfoResp;
import com.sdm.project.service.ISimulationRunService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
@@ -112,4 +110,14 @@ public class SimulationRunController {
return runService.getRunVersion(req);
}
/**
* 生成自动化报告
*
* @return
*/
@PostMapping("/generateReport")
public void generateReport(@RequestBody SpdmReportReq req, HttpServletResponse response) {
runService.generateReport(req,response);
}
}

View File

@@ -0,0 +1,32 @@
package com.sdm.project.model.req;
import com.sdm.project.model.bo.TaskNode;
import com.sdm.project.model.entity.SimulationPerformance;
import lombok.Data;
import java.util.List;
/**
* @Author xuyundi
* @Date 2024/3/5
* @Note
*/
@Data
public class SpdmReportReq {
/**
* 任务执行————关键结果————图片结果的文件id集合
*/
private List<Long> imageFileIdList;
/**
* 性能指标集合
*/
private List<SimulationPerformance> performanceList;
/**
* 算例父节点信息集合
*/
private List<TaskNode> parentNodeInfoList;
}

View File

@@ -6,11 +6,9 @@ import com.sdm.common.entity.req.data.QueryDirReq;
import com.sdm.common.entity.req.data.UploadFilesReq;
import com.sdm.project.model.entity.SimulationRun;
import com.baomidou.mybatisplus.extension.service.IService;
import com.sdm.project.model.req.GetRunVersionReq;
import com.sdm.project.model.req.ProjectTreeTagReq;
import com.sdm.project.model.req.SpdmAddTaskRunReq;
import com.sdm.project.model.req.SpdmTaskRunReq;
import com.sdm.project.model.req.*;
import com.sdm.project.model.resp.RunVersionInfoResp;
import jakarta.servlet.http.HttpServletResponse;
import java.util.List;
@@ -42,4 +40,5 @@ public interface ISimulationRunService extends IService<SimulationRun> {
SdmResponse<RunVersionInfoResp> getRunVersion(GetRunVersionReq req);
void generateReport(SpdmReportReq req, HttpServletResponse response);
}

View File

@@ -6,10 +6,7 @@ import com.sdm.common.common.SdmResponse;
import com.sdm.common.common.ThreadLocalContext;
import com.sdm.common.entity.enums.DirTypeEnum;
import com.sdm.common.entity.enums.NodeTypeEnum;
import com.sdm.common.entity.req.data.CreateDirReq;
import com.sdm.common.entity.req.data.DelDirReq;
import com.sdm.common.entity.req.data.QueryDirReq;
import com.sdm.common.entity.req.data.UploadFilesReq;
import com.sdm.common.entity.req.data.*;
import com.sdm.common.entity.req.system.UserQueryReq;
import com.sdm.common.entity.resp.data.FileMetadataInfoResp;
import com.sdm.common.entity.resp.system.CIDUserResp;
@@ -20,6 +17,7 @@ import com.sdm.project.common.MemberTypeEnum;
import com.sdm.project.common.RunPerformanceStatusEnum;
import com.sdm.project.dao.SimulationProjectMapper;
import com.sdm.project.dao.SimulationRunMapper;
import com.sdm.project.model.bo.TaskNode;
import com.sdm.project.model.bo.TaskNodeTag;
import com.sdm.project.model.entity.SimulationPerformance;
import com.sdm.project.model.entity.SimulationRun;
@@ -35,6 +33,7 @@ import com.sdm.project.service.ISimulationPerformanceService;
import com.sdm.project.service.ISimulationRunService;
import com.sdm.project.service.ISimulationTaskMemberService;
import com.sdm.project.service.ISimulationTaskService;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
@@ -44,6 +43,9 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;
@@ -80,6 +82,8 @@ public class SimulationRunServiceImpl extends ServiceImpl<SimulationRunMapper, S
@Autowired
private IDataFeignClient dataFeignClient;
private static final String TEMP_REPORT_PATH = "/opt/report/";
private int getCurrentNodeDepth(NodeAllBase eachNode) {
String tag1 = eachNode.getTag1();
String tag2 = eachNode.getTag2();
@@ -656,4 +660,91 @@ public class SimulationRunServiceImpl extends ServiceImpl<SimulationRunMapper, S
return allRuns.stream().filter(run -> StringUtils.isEmpty(run.getParentId())).collect(Collectors.toList());
}
@Override
public void generateReport(SpdmReportReq req, HttpServletResponse response) {
log.info("生成自动化报告参数为:{}",req);
// 根据文件id下载文件到临时目录
List<Long> imageFileIdList = req.getImageFileIdList();
if (CollectionUtils.isNotEmpty(imageFileIdList)) {
String randomId = RandomUtil.generateString(16);
log.info("临时路径为:{}" , randomId);
for (Long fileId : imageFileIdList) {
dataFeignClient.downloadFileToLocal(fileId, TEMP_REPORT_PATH + randomId);
}
// 调用脚本
log.info("调用脚本中。。。。。。");
String commands = "python /opt/script/exportWord.py " + TEMP_REPORT_PATH + randomId + File.separator;
log.info("command:" + commands);
List<String> result = new ArrayList<>();
int runningStatus = -1;
try {
log.info("开始同步执行脚本");
Process process = Runtime.getRuntime().exec(commands);
log.info("准备获取脚本输出");
log.info("开始获取脚本输出");
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
log.info("executePython" + line);
result.add(line);
}
log.info("脚本执行完成");
runningStatus = process.waitFor();
log.info("脚本运行状态:" + runningStatus);
} catch (IOException | InterruptedException e) {
log.error("执行脚本失败:" + e);
return;
}
if (runningStatus != 0) {
log.error("执行脚本失败");
return;
} else {
log.info(commands + "执行脚本完成!");
}
try {
// 获取临时路径中脚本生成的报告
FileInputStream fileInputStream = new FileInputStream(TEMP_REPORT_PATH + randomId + File.separator + "report.docx");
byte[] fileData = fileInputStream.readAllBytes();
// 设置响应头
response.reset();
response.setContentType("application/octet-stream;charset=UTF-8");
String encodedFileName = URLEncoder.encode("自动化报告_" + randomId, StandardCharsets.UTF_8);
response.addHeader("Content-Disposition", "attachment;filename=" + encodedFileName);
response.addHeader("Content-Length", String.valueOf(fileData.length));
// 写入响应流
OutputStream outputStream = response.getOutputStream();
outputStream.write(fileData);
outputStream.flush();
outputStream.close();
fileInputStream.close();
}catch (Exception ex) {
log.error("生成自动化报告失败:{}",ex.getMessage());
throw new RuntimeException("生成自动化报告失败");
}
// 删除临时路径
log.info("删除临时路径:{},中。。。。。。",randomId);
// deleteFolder(new File(TEMP_REPORT_PATH + randomId));
}
// 性能指标集合
List<SimulationPerformance> performanceList = req.getPerformanceList();
// 父节点集合
List<TaskNode> parentNodeInfoList = req.getParentNodeInfoList();
}
public static void deleteFolder(File folder) {
if (folder.isDirectory()) {
File[] files = folder.listFiles();
if (files != null) {
for (File file : files) {
deleteFolder(file);
}
}
}
folder.delete();
}
}