refactor(缺陷管理): 富文本图片预览问题

This commit is contained in:
song-cc-rock 2024-03-19 11:45:55 +08:00 committed by Craftsman
parent e309ea7261
commit 7791b800a4
7 changed files with 115 additions and 22 deletions

View File

@ -34,6 +34,8 @@ public class FilterChainUtils {
filterChainDefinitionMap.put("/attachment/download/file/**", "anon");
//用例评审副文本访问
filterChainDefinitionMap.put("/review/functional/case/download/file/**", "anon");
//缺陷管理富文本访问
filterChainDefinitionMap.put("/bug/attachment/preview/md/**", "anon");
filterChainDefinitionMap.put("/system/version/current", "anon");

View File

@ -133,6 +133,7 @@ public class BugAttachmentController {
return bugAttachmentService.upgrade(request, SessionUtils.getUserId());
}
// 富文本相关接口
@PostMapping("/upload/md/file")
@Operation(summary = "缺陷管理-富文本附件-上传")
@RequiresPermissions(logical = Logical.OR, value = {PermissionConstants.PROJECT_BUG_ADD, PermissionConstants.PROJECT_BUG_UPDATE})
@ -140,11 +141,9 @@ public class BugAttachmentController {
return bugAttachmentService.uploadMdFile(file);
}
@PostMapping(value = "/preview/md/compressed")
@GetMapping(value = "/preview/md/{projectId}/{fileId}/{compressed}")
@Operation(summary = "缺陷管理-富文本缩略图-预览")
@RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ)
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
public ResponseEntity<byte[]> previewMdImg(@Validated @RequestBody BugFileSourceRequest request) {
return bugAttachmentService.downloadOrPreview(request);
public ResponseEntity<byte[]> previewMd(@PathVariable String projectId, @PathVariable String fileId, @PathVariable("compressed") boolean compressed) {
return bugAttachmentService.previewMd(projectId, fileId, compressed);
}
}

View File

@ -9,7 +9,10 @@ import io.metersphere.bug.dto.request.*;
import io.metersphere.bug.dto.response.BugColumnsOptionDTO;
import io.metersphere.bug.dto.response.BugDTO;
import io.metersphere.bug.dto.response.BugDetailDTO;
import io.metersphere.bug.service.*;
import io.metersphere.bug.service.BugLogService;
import io.metersphere.bug.service.BugNoticeService;
import io.metersphere.bug.service.BugService;
import io.metersphere.bug.service.BugSyncService;
import io.metersphere.project.dto.ProjectTemplateOptionDTO;
import io.metersphere.project.service.ProjectApplicationService;
import io.metersphere.project.service.ProjectTemplateService;
@ -53,8 +56,6 @@ public class BugController {
@Resource
private BugSyncService bugSyncService;
@Resource
private BugStatusService bugStatusService;
@Resource
private ProjectTemplateService projectTemplateService;
@Resource
private ProjectApplicationService projectApplicationService;

View File

@ -261,10 +261,17 @@ public class BugAttachmentService {
String fileId = IDGenerator.nextStr();
FileRequest fileRequest = new FileRequest();
fileRequest.setFileName(file.getOriginalFilename());
String systemTempDir = DefaultRepositoryDir.getSystemTempDir();
fileRequest.setFolder(systemTempDir + "/" + fileId);
fileRequest.setFolder(DefaultRepositoryDir.getSystemTempDir() + "/" + fileId);
try {
FileCenter.getDefaultRepository().saveFile(file, fileRequest);
String fileType = StringUtils.substring(fileName, fileName.lastIndexOf(".") + 1);
if (TempFileUtils.isImage(fileType)) {
//图片文件自动生成预览图
byte[] previewImg = TempFileUtils.compressPic(file.getBytes());
fileRequest.setFolder(DefaultRepositoryDir.getSystemTempCompressDir() + "/" + fileId);
fileRequest.setStorage(StorageType.MINIO.toString());
fileService.upload(previewImg, fileRequest);
}
} catch (Exception e) {
LogUtils.error(e);
throw new MSException(e.getMessage());
@ -625,7 +632,7 @@ public class BugAttachmentService {
* @param source 文件来源
*/
public void transferTmpFile(String bugId, String projectId, List<String> uploadFileIds, String userId, String source) {
if (org.apache.commons.collections.CollectionUtils.isEmpty(uploadFileIds)) {
if (CollectionUtils.isEmpty(uploadFileIds)) {
return;
}
//过滤已上传过的
@ -741,4 +748,85 @@ public class BugAttachmentService {
}
}
}
public ResponseEntity<byte[]> previewMd(String projectId, String fileId, boolean compressed) {
byte[] bytes;
String fileName;
BugLocalAttachmentExample example = new BugLocalAttachmentExample();
example.createCriteria().andFileIdEqualTo(fileId);
List<BugLocalAttachment> bugAttachments = bugLocalAttachmentMapper.selectByExample(example);
if (CollectionUtils.isEmpty(bugAttachments)) {
//在临时文件获取
fileName = getTempFileNameByFileId(fileId);
bytes = getPreviewImg(fileName, fileId, compressed);
} else {
//在正式目录获取
BugLocalAttachment attachment = bugAttachments.get(0);
fileName = attachment.getFileName();
FileRequest fileRequest = new FileRequest();
fileRequest.setFileName(attachment.getFileName());
if (compressed) {
fileRequest.setFolder(DefaultRepositoryDir.getBugPreviewDir(projectId, attachment.getBugId()) + "/" + attachment.getFileId());
} else {
fileRequest.setFolder(DefaultRepositoryDir.getBugDir(projectId, attachment.getBugId()) + "/" + attachment.getFileId());
}
fileRequest.setStorage(StorageType.MINIO.name());
try {
bytes = fileService.download(fileRequest);
} catch (Exception e) {
throw new MSException("get file error");
}
}
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType("application/octet-stream"))
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"")
.body(bytes);
}
public byte[] getPreviewImg(String fileName, String fileId, boolean isCompressed) {
String systemTempDir;
if (isCompressed) {
systemTempDir = DefaultRepositoryDir.getSystemTempCompressDir();
} else {
systemTempDir = DefaultRepositoryDir.getSystemTempDir();
}
FileRequest previewRequest = new FileRequest();
previewRequest.setFileName(fileName);
previewRequest.setStorage(StorageType.MINIO.name());
previewRequest.setFolder(systemTempDir + "/" + fileId);
byte[] previewImg = null;
try {
previewImg = fileService.download(previewRequest);
} catch (Exception e) {
LogUtils.error("获取预览图失败:{}", e);
}
if (previewImg == null || previewImg.length == 0) {
try {
if (isCompressed) {
previewImg = this.compressPicWithFileMetadata(fileName, fileId);
previewRequest.setFolder(DefaultRepositoryDir.getSystemTempCompressDir() + "/" + fileId);
fileService.upload(previewImg, previewRequest);
}
return previewImg;
} catch (Exception e) {
LogUtils.error("获取预览图失败:{}", e);
}
}
return previewImg;
}
//获取文件并压缩的方法需要上锁防止并发超过一定数量时内存溢出
private synchronized byte[] compressPicWithFileMetadata(String fileName, String fileId) throws Exception {
byte[] fileBytes = this.getFile(fileName, fileId);
return TempFileUtils.compressPic(fileBytes);
}
public byte[] getFile(String fileName, String fileId) throws Exception {
FileRequest fileRequest = new FileRequest();
fileRequest.setFileName(fileName);
fileRequest.setFolder(DefaultRepositoryDir.getSystemTempDir() + "/" + fileId);
fileRequest.setStorage(StorageType.MINIO.name());
return fileService.download(fileRequest);
}
}

View File

@ -1264,11 +1264,14 @@ public class BugService {
return;
}
String fileId = IDGenerator.nextStr();
// 第三方平台的图片下载命名为平台名称+随机数字
String fileName = updateBug.getPlatform() + "-" + IDGenerator.nextNum() + ".jpg";
byte[] bytes;
try {
// upload platform attachment to minio
bytes = in.readAllBytes();
FileCenter.getDefaultRepository().saveFile(bytes, buildBugFileRequest(updateBug.getProjectId(), updateBug.getId(), fileId, "image.png"));
// 第三方平台下载的图片默认不压缩
FileCenter.getDefaultRepository().saveFile(bytes, buildBugFileRequest(updateBug.getProjectId(), updateBug.getId(), fileId, fileName));
} catch (Exception e) {
throw new MSException(e.getMessage());
}
@ -1277,14 +1280,14 @@ public class BugService {
localAttachment.setId(IDGenerator.nextStr());
localAttachment.setBugId(updateBug.getId());
localAttachment.setFileId(fileId);
localAttachment.setFileName("image.png");
localAttachment.setFileName(fileName);
localAttachment.setSize((long) bytes.length);
localAttachment.setCreateTime(System.currentTimeMillis());
localAttachment.setCreateUser("admin");
localAttachment.setSource(BugAttachmentSourceType.RICH_TEXT.name());
bugLocalAttachmentMapper.insert(localAttachment);
// 替换富文本中的临时URL
updateBug.setDescription(updateBug.getDescription().replace("alt=\"" + key + "\"", "src=\"/attachment/download/file/" + updateBug.getProjectId() + "/" + fileId + "/true\""));
// 替换富文本中的临时URL为预览URL
updateBug.setDescription(updateBug.getDescription().replace("alt=\"" + key + "\"", "src=\"/bug/attachment/preview/md/" + updateBug.getProjectId() + "/" + fileId + "/false\""));
}));
}
}

View File

@ -49,7 +49,7 @@ public class BugAttachmentControllerTests extends BaseTest {
public static final String BUG_ATTACHMENT_CHECK_UPDATE = "/bug/attachment/check-update";
public static final String BUG_ATTACHMENT_UPDATE = "/bug/attachment/update";
public static final String BUG_ATTACHMENT_UPLOAD_MD = "/bug/attachment/upload/md/file";
public static final String BUG_ATTACHMENT_PREVIEW_MD = "/bug/attachment/preview/md/compressed";
public static final String BUG_ATTACHMENT_PREVIEW_MD = "/bug/attachment/preview/md";
@Test
@Order(0)
@ -61,12 +61,7 @@ public class BugAttachmentControllerTests extends BaseTest {
// Mock minio save file exception
MockMultipartFile file = new MockMultipartFile("file", "test.txt", MediaType.APPLICATION_OCTET_STREAM_VALUE, "aa".getBytes());
this.requestUploadFile(BUG_ATTACHMENT_UPLOAD_MD, file);
BugFileSourceRequest request = new BugFileSourceRequest();
request.setBugId("default-attachment-bug-id");
request.setProjectId("default-project-for-attachment");
request.setAssociated(false);
request.setFileId("not-exist-file-id");
this.requestPostDownloadFile(BUG_ATTACHMENT_PREVIEW_MD, null, request);
this.requestGetDownloadFile(BUG_ATTACHMENT_PREVIEW_MD + "/default-project-for-attachment/not-exist-file-id/true", null);
}
@Test

View File

@ -33,6 +33,11 @@ export default mergeConfig(
changeOrigin: true,
rewrite: (path: string) => path.replace(/^\/front\/attachment/, ''),
},
'/bug/attachment': {
target: 'http://172.16.200.18:8081/',
changeOrigin: true,
rewrite: (path: string) => path.replace(/^\/front\/bug\/attachment/, ''),
},
'/plugin/image': {
target: 'http://172.16.200.18:8081/',
changeOrigin: true,