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> { ...@@ -20,4 +20,11 @@ public interface TestRecordsMapper extends BaseMapper<TestRecords> {
* @return * @return
*/ */
List<TestRecords> selectListByGeneralTaskId(@Param("id") Long id); List<TestRecords> selectListByGeneralTaskId(@Param("id") Long id);
/**
* 根据任务id获取用例
* @param taskId
* @return
*/
List<TestRecords> selectListByTaskId(Long taskId);
} }
package com.ruoyi.service; package com.ruoyi.service;
import java.io.ByteArrayInputStream;
import java.io.IOException;
/** /**
* PDF模板管理Service接口 * PDF模板管理Service接口
* @author gxk * @author gxk
...@@ -31,4 +34,10 @@ public interface PdfTemplateManagementService { ...@@ -31,4 +34,10 @@ public interface PdfTemplateManagementService {
*/ */
String generateOriginalRecord(Long taskId) throws Exception; 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> { ...@@ -26,4 +26,11 @@ public interface TestRecordsService extends IService<TestRecords> {
* @param taskId * @param taskId
*/ */
void singleSendPost(String id,Long taskId); void singleSendPost(String id,Long taskId);
/**
* 根据任务id获取用例
* @param taskId
* @return
*/
List<TestRecords> selectListByTaskId(Long taskId);
} }
package com.ruoyi.service.impl; package com.ruoyi.service.impl;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.itextpdf.text.*; import com.itextpdf.text.*;
import com.itextpdf.text.Font; import com.itextpdf.text.Font;
import com.itextpdf.text.Image; import com.itextpdf.text.Image;
...@@ -36,11 +39,13 @@ import com.ruoyi.mapper.TaskMapper; ...@@ -36,11 +39,13 @@ import com.ruoyi.mapper.TaskMapper;
import com.ruoyi.mapper.TestRecordsMapper; import com.ruoyi.mapper.TestRecordsMapper;
import com.ruoyi.service.PdfTemplateManagementService; import com.ruoyi.service.PdfTemplateManagementService;
import com.ruoyi.service.ReviewEnterpriseArchiveService; import com.ruoyi.service.ReviewEnterpriseArchiveService;
import com.ruoyi.service.TestRecordsService;
import com.ruoyi.system.mapper.SysDictDataMapper; import com.ruoyi.system.mapper.SysDictDataMapper;
import io.minio.MinioClient; import io.minio.MinioClient;
import io.minio.ObjectWriteArgs; import io.minio.ObjectWriteArgs;
import io.minio.PutObjectArgs; import io.minio.PutObjectArgs;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
...@@ -48,10 +53,14 @@ import org.springframework.transaction.annotation.Transactional; ...@@ -48,10 +53,14 @@ import org.springframework.transaction.annotation.Transactional;
import java.io.*; import java.io.*;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.net.URL; import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.*; import java.util.*;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.IntStream; import java.util.stream.IntStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/** /**
* PDF模板管理Service业务层处理 * PDF模板管理Service业务层处理
...@@ -88,6 +97,9 @@ public class PdfTemplateManagementServiceImpl implements PdfTemplateManagementSe ...@@ -88,6 +97,9 @@ public class PdfTemplateManagementServiceImpl implements PdfTemplateManagementSe
@Autowired @Autowired
private TestRecordsMapper testRecordsMapper; private TestRecordsMapper testRecordsMapper;
@Autowired
private TestRecordsService testRecordsService;
/** /**
* 检验报告PDF下载 * 检验报告PDF下载
* *
...@@ -310,6 +322,99 @@ public class PdfTemplateManagementServiceImpl implements PdfTemplateManagementSe ...@@ -310,6 +322,99 @@ public class PdfTemplateManagementServiceImpl implements PdfTemplateManagementSe
return uploadMinio(arrayOutputStream, "车辆试验原始记录-" + getReportName()); 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 样品信息 * @param sample 样品信息
......
...@@ -260,6 +260,16 @@ public class TestRecordsServiceImpl extends ServiceImpl<TestRecordsMapper, TestR ...@@ -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) { public static String convertMarkdownToHtml(String markdownContent) {
// 创建 Markdown 解析器 // 创建 Markdown 解析器
Parser parser = Parser.builder().build(); Parser parser = Parser.builder().build();
......
package com.ruoyi.web; package com.ruoyi.web;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
...@@ -8,13 +9,22 @@ import com.ruoyi.common.core.domain.R; ...@@ -8,13 +9,22 @@ import com.ruoyi.common.core.domain.R;
import com.ruoyi.domain.Task; import com.ruoyi.domain.Task;
import com.ruoyi.service.PdfTemplateManagementService; import com.ruoyi.service.PdfTemplateManagementService;
import com.ruoyi.service.TaskService; import com.ruoyi.service.TaskService;
import com.ruoyi.web.request.FileRequest;
import com.ruoyi.web.request.PdfFileRequest; import com.ruoyi.web.request.PdfFileRequest;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired; 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.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; 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 * @author gxk
*/ */
...@@ -150,4 +160,21 @@ public class PdfTemplateManagementController { ...@@ -150,4 +160,21 @@ public class PdfTemplateManagementController {
} }
return R.ok(url); 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 @@ ...@@ -52,6 +52,11 @@
where where
t.id = #{id} t.id = #{id}
</select> </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> </mapper>
...@@ -6,72 +6,129 @@ import cn.hutool.core.util.StrUtil; ...@@ -6,72 +6,129 @@ import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpResponse; import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil; import cn.hutool.http.HttpUtil;
import cn.hutool.core.util.ZipUtil; 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.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import java.io.File; 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 @SpringBootTest
public class TestDownload { public class TestDownload {
@Autowired
private TestRecordsService testRecordsService;
@Test @Test
public void Test() { public void Test() throws FileNotFoundException {
try { 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(); .execute();
if (response.isOk()) { if (response.isOk()) {
// 从响应头中获取文件名,这里假设Content-Disposition头包含文件名 System.out.println("response = " + response);
// 从响应头中获取文件名,这里Content-Disposition头包含文件名
String contentDisposition = response.header("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); // 添加文件名到集合中
// 保存下载的文件到临时位置 // 创建ZIP条目并写入到ZIP输出流
String tempFilePath = "temp_" + fileName; ZipEntry zipEntry = new ZipEntry(fileName);
FileUtil.writeBytes(IoUtil.readBytes(response.bodyStream()), FileUtil.file(tempFilePath)); 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); System.out.println("文件已添加到压缩包:" + zipFilePath);
// 删除临时文件
FileUtil.del(tempFilePath);
} else { } else {
System.err.println("无法从响应头中提取文件名"); System.err.println("无法从响应头中提取文件名");
} }
} else { } else {
System.err.println("下载失败,状态码:" + response.getStatus()); System.err.println("下载失败,状态码:" + response.getStatus());
} }
}
}
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
/** /**
* 从Content-Disposition头中提取文件名。 * 解码文件名称
* 注意:这是一个简化的示例,真实场景可能需要更复杂的解析逻辑。 * @param contentDisposition
* * @return
* @param contentDisposition Content-Disposition头的值 * @throws UnsupportedEncodingException
* @return 提取的文件名,如果未找到则返回空字符串
*/ */
private static String extractFileNameFromContentDisposition(String contentDisposition) { private static String parseAndDecodeFilename(String contentDisposition) throws UnsupportedEncodingException {
if (StrUtil.isBlank(contentDisposition)) { String[] parts = contentDisposition.split("; ");
return "";
}
String[] parts = contentDisposition.split(";");
for (String part : parts) { for (String part : parts) {
part = part.trim(); if (part.startsWith("filename*")) {
if (part.startsWith("filename=")) { // 分割出编码后的文件名,忽略前缀如 utf8''
return part.substring(part.indexOf('=') + 1).replace("\"", ""); 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