1
0

feat(web): 实现文件上传和下载功能

- 在 DataFileController 中添加文件上传和下载接口- 更新 WareController 中的图标处理逻辑
- 在 DataFile 实体中添加文件类型字段
- 更新 DataFileService 中的文件信息更新方法
- 在前端组件中添加文件上传和下载相关配置
This commit is contained in:
2024-12-17 10:31:34 +08:00
parent 94a3be2b58
commit 420651c073
6 changed files with 69 additions and 12 deletions

View File

@@ -1,5 +1,5 @@
export const information = {
debug: false,
debug: true,
// baseUrl: '',
baseUrl: 'http://127.0.0.1:20080',
title: '可信供给中心',
@@ -347,7 +347,12 @@ const formInputFileStaticColumns = [
type: 'action',
label: '下载',
level: 'link',
icon: 'fa fa-download'
icon: 'fa fa-download',
actionType: 'ajax',
api: {
...apiGet('${base}/upload/download/${id}'),
responseType: 'blob',
}
}
]
}

View File

@@ -21,6 +21,10 @@ function detailForm() {
name: 'icon',
label: '图标',
required: true,
receiver: apiPost("${base}/upload"),
autoFill: {
iconId: '${id}',
}
},
{
type: 'picker',
@@ -75,6 +79,7 @@ function detailForm() {
name: 'content',
label: '商品详情',
required: true,
receiver: '',
options: {
min_height: 300,
}

View File

@@ -1,10 +1,12 @@
package com.eshore.gringotts.web.domain.controller;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.eshore.gringotts.web.configuration.UploadConfiguration;
import com.eshore.gringotts.web.configuration.amis.AmisResponse;
import com.eshore.gringotts.web.domain.entity.DataFile;
import com.eshore.gringotts.web.domain.service.DataFileService;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.ByteArrayInputStream;
@@ -13,12 +15,15 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import javax.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.eclipse.collections.api.list.ImmutableList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -50,6 +55,40 @@ public class DataFileController {
this.sliceFolderPath = StrUtil.format("{}/slice", uploadFolderPath);
}
@PostMapping("")
public AmisResponse<FinishResponse> upload(@RequestParam("file") MultipartFile file) throws IOException {
String filename = file.getOriginalFilename();
Long id = dataFileService.initialDataFile(filename);
String url = StrUtil.format("/upload/download/{}", id);
byte[] bytes = file.getBytes();
String originMd5 = SecureUtil.md5(new ByteArrayInputStream(bytes));
File targetFile = new File(StrUtil.format("{}/{}", uploadFolderPath, originMd5));
if (targetFile.exists()) {
dataFileService.updateDataFile(id, FileUtil.getAbsolutePath(targetFile), FileUtil.size(targetFile), originMd5, file.getContentType());
return AmisResponse.responseSuccess(new FinishResponse(id, filename, url, url));
}
File cacheFile = new File(StrUtil.format("{}/{}", cacheFolderPath, id));
cacheFile = FileUtil.writeBytes(bytes, cacheFile);
String targetMd5 = SecureUtil.md5(cacheFile);
if (!StrUtil.equals(originMd5, targetMd5)) {
throw new RuntimeException("文件上传失败,校验不匹配");
}
FileUtil.move(cacheFile, targetFile, true);
dataFileService.updateDataFile(id, FileUtil.getAbsolutePath(targetFile), FileUtil.size(targetFile), targetMd5, file.getContentType());
return AmisResponse.responseSuccess(new FinishResponse(id, filename, url, url));
}
@GetMapping("/download/{id}")
public void download(@PathVariable Long id, HttpServletResponse response) throws IOException {
DataFile dataFile = dataFileService.detailOrThrow(id);
File targetFile = new File(dataFile.getPath());
response.setHeader("Access-Control-Expose-Headers", "Content-Type");
response.setHeader("Content-Type", dataFile.getType());
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
response.setHeader("Content-Disposition", StrUtil.format("attachment; filename={}", dataFile.getFilename()));
IoUtil.copy(new FileInputStream(targetFile), response.getOutputStream());
}
@PostMapping("/start")
public AmisResponse<StartResponse> start(@RequestBody StartRequest request) {
logger.info("Request: {}", request);
@@ -107,12 +146,19 @@ public class DataFileController {
if (!targetFile.exists()) {
FileUtil.move(cacheFile, targetFile, true);
}
dataFileService.updateDataFile(request.uploadId, FileUtil.getAbsolutePath(targetFile), FileUtil.size(targetFile), SecureUtil.md5(targetFile));
String absolutePath = FileUtil.getAbsolutePath(targetFile);
dataFileService.updateDataFile(
request.uploadId,
absolutePath,
FileUtil.size(targetFile),
SecureUtil.md5(targetFile),
FileUtil.getMimeType(absolutePath)
);
return AmisResponse.responseSuccess(new FinishResponse(
request.uploadId,
request.filename,
request.uploadId,
StrUtil.format("https://localhost:9090")
request.uploadId.toString(),
StrUtil.format("/upload/download/{}", request.uploadId)
));
} else {
throw new RuntimeException("合并文件失败");
@@ -166,7 +212,7 @@ public class DataFileController {
public static final class FinishResponse {
private Long id;
private String filename;
private Long value;
private String value;
private String url;
}
}

View File

@@ -1,7 +1,6 @@
package com.eshore.gringotts.web.domain.controller;
import com.eshore.gringotts.web.domain.base.controller.SimpleControllerSupport;
import com.eshore.gringotts.web.domain.base.entity.FileInfo;
import com.eshore.gringotts.web.domain.base.entity.SimpleListItem;
import com.eshore.gringotts.web.domain.base.entity.SimpleSaveItem;
import com.eshore.gringotts.web.domain.entity.Ware;
@@ -36,9 +35,9 @@ public class WareController extends SimpleControllerSupport<Ware, WareController
protected Ware fromSaveItem(SaveItem saveItem) throws Exception {
Ware ware = new Ware();
ware.setResource(dataResourceService.detailOrThrow(saveItem.getResourceId()));
ware.setName(ware.getName());
ware.setName(saveItem.getName());
ware.setDescription(saveItem.getDescription());
ware.setIcon(dataFileService.detailOrThrow(saveItem.getIcon().getValue()));
ware.setIcon(dataFileService.detailOrThrow(saveItem.getIconId()));
ware.setContent(saveItem.getContent());
return ware;
}
@@ -59,7 +58,7 @@ public class WareController extends SimpleControllerSupport<Ware, WareController
private Long resourceId;
private String name;
private String description;
private FileInfo icon;
private Long iconId;
private String content;
}
@@ -93,7 +92,7 @@ public class WareController extends SimpleControllerSupport<Ware, WareController
this.setResourceName(ware.getResource().getName());
this.setName(ware.getName());
this.setDescription(ware.getDescription());
this.setIcon(new FileInfo(ware.getIcon()));
this.setIconId(ware.getIcon().getId());
this.setContent(ware.getContent());
}
}

View File

@@ -30,4 +30,5 @@ public class DataFile extends LogicDeleteEntity {
private Long size;
private String md5;
private String path;
private String type;
}

View File

@@ -74,11 +74,12 @@ public class DataFileService extends SimpleServiceSupport<DataFile> {
return dataFileRepository.save(dataFile).getId();
}
public void updateDataFile(Long id, String path, Long size, String md5) {
public void updateDataFile(Long id, String path, Long size, String md5, String type) {
DataFile dataFile = dataFileRepository.findById(id).orElseThrow(UpdateDataFileFailedException::new);
dataFile.setSize(size);
dataFile.setMd5(md5);
dataFile.setPath(path);
dataFile.setType(type);
User loginUser = userService.currentLoginUser();
dataFile.setModifiedUser(loginUser);
dataFileRepository.save(dataFile);