Commit cdb52718 authored by wdy's avatar wdy

Merge branch 'wangdingyi' into 'dev'

车型试验原始记录附件下载

See merge request !408
parents 97ed5b01 bb64e0e4
......@@ -20,4 +20,11 @@ public interface TestRecordsMapper extends BaseMapper<TestRecords> {
* @return
*/
List<TestRecords> selectListByGeneralTaskId(@Param("id") Long id);
/**
* 根据任务id获取用例
* @param taskId
* @return
*/
List<TestRecords> selectListByTaskId(Long taskId);
}
package com.ruoyi.service;
import java.io.ByteArrayInputStream;
import java.io.IOException;
/**
* PDF模板管理Service接口
* @author gxk
......@@ -31,4 +34,10 @@ public interface PdfTemplateManagementService {
*/
String generateOriginalRecord(Long taskId) throws Exception;
/**
* 下载附件
* @param taskId
* @return
*/
void createZipStream(Long taskId) throws IOException;
}
......@@ -26,4 +26,11 @@ public interface TestRecordsService extends IService<TestRecords> {
* @param taskId
*/
void singleSendPost(String id,Long taskId);
/**
* 根据任务id获取用例
* @param taskId
* @return
*/
List<TestRecords> selectListByTaskId(Long taskId);
}
package com.ruoyi.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.itextpdf.text.*;
import com.itextpdf.text.Font;
import com.itextpdf.text.Image;
......@@ -36,11 +39,13 @@ import com.ruoyi.mapper.TaskMapper;
import com.ruoyi.mapper.TestRecordsMapper;
import com.ruoyi.service.PdfTemplateManagementService;
import com.ruoyi.service.ReviewEnterpriseArchiveService;
import com.ruoyi.service.TestRecordsService;
import com.ruoyi.system.mapper.SysDictDataMapper;
import io.minio.MinioClient;
import io.minio.ObjectWriteArgs;
import io.minio.PutObjectArgs;
import lombok.SneakyThrows;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
......@@ -48,10 +53,14 @@ import org.springframework.transaction.annotation.Transactional;
import java.io.*;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* PDF模板管理Service业务层处理
......@@ -88,6 +97,9 @@ public class PdfTemplateManagementServiceImpl implements PdfTemplateManagementSe
@Autowired
private TestRecordsMapper testRecordsMapper;
@Autowired
private TestRecordsService testRecordsService;
/**
* 检验报告PDF下载
*
......@@ -310,6 +322,99 @@ public class PdfTemplateManagementServiceImpl implements PdfTemplateManagementSe
return uploadMinio(arrayOutputStream, "车辆试验原始记录-" + getReportName());
}
/**
* 车辆试验原始记录附件下载
* @param taskId
* @throws IOException
*/
@Override
public void createZipStream(Long taskId) throws IOException {
// 用于存储已经添加的文件名
Set<String> addedFiles = new HashSet<>();
// 压缩包的名称和路径
String zipFilePath = "D:\\downloaded_files.zip";
// 创建ZIP输出流
// FileOutputStream fos = new FileOutputStream(zipFilePath);
// ZipOutputStream zos = new ZipOutputStream(fos);
try (FileOutputStream fos = new FileOutputStream(zipFilePath);
ZipOutputStream zos = new ZipOutputStream(fos)) {
List<TestRecords> list = testRecordsService.selectListByTaskId(taskId);
// 转换列表中每个 TestRecords 对象的 attachmentId 字段为字符串数组
List<String[]> convertedList = list.stream()
.filter(testRecord -> {
String attachmentId = testRecord.getAttachmentId();
return attachmentId != null;
})
.map(testRecord -> testRecord.getAttachmentId().split("、"))
.collect(Collectors.toList());
// 遍历convertedList中的每个数组
for (String[] attachments : convertedList) {
// 遍历数组中的每个元素
for (String attachmentId : attachments) {
HttpResponse response = HttpUtil.createPost("https://10.12.48.78:8090/api/project/download/" + attachmentId)
.execute();
if (response.isOk()) {
// 从响应头中获取文件名,这里Content-Disposition头包含文件名
String contentDisposition = response.header("Content-Disposition");
String fileName = parseAndDecodeFilename(contentDisposition);
if (StrUtil.isNotBlank(fileName) && !addedFiles.contains(fileName)) {
addedFiles.add(fileName); // 添加文件名到集合中
// 创建ZIP条目并写入到ZIP输出流
ZipEntry zipEntry = new ZipEntry(fileName);
zos.putNextEntry(zipEntry);
// 直接从HTTP响应中读取字节并写入到ZIP输出流
IOUtils.copy(response.bodyStream(), zos);
// 完成条目写入
zos.closeEntry();
// 关闭输出流
// IoUtil.close(zos);
// IoUtil.close(fos);
System.out.println("文件已添加到压缩包:" + zipFilePath);
} else {
System.err.println("无法从响应头中提取文件名");
}
} else {
System.err.println("下载失败,状态码:" + response.getStatus());
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 解码文件名称
* @param contentDisposition
* @return
* @throws UnsupportedEncodingException
*/
private String parseAndDecodeFilename(String contentDisposition) throws UnsupportedEncodingException {
String[] parts = contentDisposition.split("; ");
for (String part : parts) {
if (part.startsWith("filename*")) {
// 分割出编码后的文件名,忽略前缀如 utf8''
int start = part.indexOf("''") + 2;
String encodedFileName = part.substring(start).trim();
// 解码文件名
return URLDecoder.decode(encodedFileName, String.valueOf(StandardCharsets.UTF_8));
}
}
return null; // 如果没有找到filename*则返回null
}
/**
* 创建临时文档
* @param sample 样品信息
......
......@@ -260,6 +260,16 @@ public class TestRecordsServiceImpl extends ServiceImpl<TestRecordsMapper, TestR
}
}
/**
* 根据任务id获取用例
* @param taskId
* @return
*/
@Override
public List<TestRecords> selectListByTaskId(Long taskId) {
return testRecordsMapper.selectListByTaskId(taskId);
}
public static String convertMarkdownToHtml(String markdownContent) {
// 创建 Markdown 解析器
Parser parser = Parser.builder().build();
......
package com.ruoyi.web;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
......@@ -8,13 +9,22 @@ import com.ruoyi.common.core.domain.R;
import com.ruoyi.domain.Task;
import com.ruoyi.service.PdfTemplateManagementService;
import com.ruoyi.service.TaskService;
import com.ruoyi.web.request.FileRequest;
import com.ruoyi.web.request.PdfFileRequest;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* @author gxk
*/
......@@ -150,4 +160,21 @@ public class PdfTemplateManagementController {
}
return R.ok(url);
}
@Anonymous
@ApiOperation("下载附件")
@PostMapping("/downloadFile")
public void downloadFile(@Validated @RequestBody FileRequest request, HttpServletResponse response) throws IOException {
String zipFilePath = "D:\\downloaded_files.zip";
pdfTemplateManagementService.createZipStream(request.getTaskId());
// 设置响应头以便浏览器识别为下载
response.setHeader("Content-Disposition", "attachment; filename=downloaded_files.zip");
response.setContentType("application/zip");
// 将压缩文件流发送到客户端
try (FileInputStream fis = new FileInputStream(new File(zipFilePath))) {
IoUtil.copy(fis, response.getOutputStream());
}
}
}
package com.ruoyi.web.request;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@ApiModel(value = "FileRequest", description = "下载附件")
@Data
public class FileRequest {
@ApiModelProperty("任务id")
Long taskId;
}
......@@ -52,6 +52,11 @@
where
t.id = #{id}
</select>
<select id="selectListByTaskId" resultType="com.ruoyi.domain.TestRecords">
SELECT id, project_id, task_id, usecase, usecase_no, usecase_id, test_time, description, risk_level, test_method, test_result, remediation, test_details, attachment_id, attachment_name
FROM t_test_records
WHERE task_id = #{taskId}
</select>
</mapper>
......@@ -6,72 +6,129 @@ import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.core.util.ZipUtil;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.domain.TestRecords;
import com.ruoyi.service.TestRecordsService;
import org.apache.commons.io.IOUtils;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@SpringBootTest
public class TestDownload {
@Autowired
private TestRecordsService testRecordsService;
@Test
public void Test() {
try {
public void Test() throws FileNotFoundException {
Set<String> addedFiles = new HashSet<>(); // 用于存储已经添加的文件名
// 压缩包的名称和路径
String zipFilePath = "downloaded_files.zip";
String zipFilePath = "D:\\downloaded_files.zip";
// 创建ZIP输出流
// FileOutputStream fos = new FileOutputStream(zipFilePath);
// ZipOutputStream zos = new ZipOutputStream(fos);
try (FileOutputStream fos = new FileOutputStream(zipFilePath);
ZipOutputStream zos = new ZipOutputStream(fos)) {
Long taskId = 1808391769025445890L;
List<TestRecords> list = testRecordsService.selectListByTaskId(taskId);
list.forEach(testRecord -> {
System.out.println("testRecord = " + testRecord);
});
HttpResponse response = HttpUtil.createPost("https://10.12.48.78:8090/api/project/download/fd40de37-9c57-4597-8f74-d0754dfa17b2")
// 转换列表中每个 TestRecords 对象的 attachmentId 字段为字符串数组
List<String[]> convertedList = list.stream()
.filter(testRecord -> {
String attachmentId = testRecord.getAttachmentId();
return attachmentId != null;
})
.map(testRecord -> testRecord.getAttachmentId().split("、"))
.collect(Collectors.toList());
convertedList.forEach(testRecord -> {
System.out.println("convertedList = " + testRecord);
});
// 遍历convertedList中的每个数组
for (String[] attachments : convertedList) {
// 遍历数组中的每个元素
for (String attachmentId : attachments) {
HttpResponse response = HttpUtil.createPost("https://10.12.48.78:8090/api/project/download/" + attachmentId)
.execute();
if (response.isOk()) {
// 从响应头中获取文件名,这里假设Content-Disposition头包含文件名
System.out.println("response = " + response);
// 从响应头中获取文件名,这里Content-Disposition头包含文件名
String contentDisposition = response.header("Content-Disposition");
String fileName = extractFileNameFromContentDisposition(contentDisposition);
String fileName = parseAndDecodeFilename(contentDisposition);
if (StrUtil.isNotBlank(fileName)) {
if (StrUtil.isNotBlank(fileName) && !addedFiles.contains(fileName)) {
addedFiles.add(fileName); // 添加文件名到集合中
// 保存下载的文件到临时位置
String tempFilePath = "temp_" + fileName;
FileUtil.writeBytes(IoUtil.readBytes(response.bodyStream()), FileUtil.file(tempFilePath));
// 创建ZIP条目并写入到ZIP输出流
ZipEntry zipEntry = new ZipEntry(fileName);
zos.putNextEntry(zipEntry);
System.out.println("文件下载成功:" + fileName);
// 直接从HTTP响应中读取字节并写入到ZIP输出流
IOUtils.copy(response.bodyStream(), zos);
// 将临时文件添加到压缩包中
// ZipUtil.addFile(zipFilePath, tempFilePath);
// 完成条目写入
zos.closeEntry();
// 关闭输出流
// IoUtil.close(zos);
// IoUtil.close(fos);
System.out.println("文件已添加到压缩包:" + zipFilePath);
// 删除临时文件
FileUtil.del(tempFilePath);
} else {
System.err.println("无法从响应头中提取文件名");
}
} else {
System.err.println("下载失败,状态码:" + response.getStatus());
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 从Content-Disposition头中提取文件名。
* 注意:这是一个简化的示例,真实场景可能需要更复杂的解析逻辑。
*
* @param contentDisposition Content-Disposition头的值
* @return 提取的文件名,如果未找到则返回空字符串
* 解码文件名称
* @param contentDisposition
* @return
* @throws UnsupportedEncodingException
*/
private static String extractFileNameFromContentDisposition(String contentDisposition) {
if (StrUtil.isBlank(contentDisposition)) {
return "";
}
String[] parts = contentDisposition.split(";");
private static String parseAndDecodeFilename(String contentDisposition) throws UnsupportedEncodingException {
String[] parts = contentDisposition.split("; ");
for (String part : parts) {
part = part.trim();
if (part.startsWith("filename=")) {
return part.substring(part.indexOf('=') + 1).replace("\"", "");
if (part.startsWith("filename*")) {
// 分割出编码后的文件名,忽略前缀如 utf8''
int start = part.indexOf("''") + 2;
String encodedFileName = part.substring(start).trim();
// 解码文件名
return URLDecoder.decode(encodedFileName, String.valueOf(StandardCharsets.UTF_8));
}
}
return "";
return null; // 如果没有找到filename*则返回null
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment