From 600fd38fc6996b4e10a90a8671740de890e3ca99 Mon Sep 17 00:00:00 2001 From: yk Date: Sat, 7 Oct 2023 17:31:11 +0800 Subject: [PATCH] fix upload pdf file --- .../api/domain/ByteArrayMultipartFile.java | 68 +++++++++ .../file/api/feign/RemoteFileService.java | 5 +- .../factory/RemoteFileFallbackFactory.java | 2 +- .../xueyi/common/redis/utils/RedisUtil.java | 12 ++ .../file/controller/SysFileController.java | 21 ++- .../controller/DmResourcesController.java | 132 ++++++++++++++++-- 6 files changed, 224 insertions(+), 16 deletions(-) create mode 100644 xueyi-api/xueyi-api-file/src/main/java/com/xueyi/file/api/domain/ByteArrayMultipartFile.java diff --git a/xueyi-api/xueyi-api-file/src/main/java/com/xueyi/file/api/domain/ByteArrayMultipartFile.java b/xueyi-api/xueyi-api-file/src/main/java/com/xueyi/file/api/domain/ByteArrayMultipartFile.java new file mode 100644 index 00000000..d80c9903 --- /dev/null +++ b/xueyi-api/xueyi-api-file/src/main/java/com/xueyi/file/api/domain/ByteArrayMultipartFile.java @@ -0,0 +1,68 @@ +package com.xueyi.file.api.domain; + +/** + * @author yk + * @description + * @date 2023-10-07 15:43 + */ +import org.springframework.web.multipart.MultipartFile; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +public class ByteArrayMultipartFile implements MultipartFile { + + private final byte[] content; + private final String name; + private final String originalFilename; + private final String contentType; + + public ByteArrayMultipartFile(byte[] content) { + this.content = content; + this.name = "file"; // 默认字段名 + this.originalFilename = "file"; // 默认文件名 + this.contentType = "application/octet-stream"; // 默认内容类型 + } + + @Override + public String getName() { + return name; + } + + @Override + public String getOriginalFilename() { + return originalFilename; + } + + @Override + public String getContentType() { + return contentType; + } + + @Override + public boolean isEmpty() { + return content == null || content.length == 0; + } + + @Override + public long getSize() { + return content.length; + } + + @Override + public byte[] getBytes() throws IOException { + return content; + } + + @Override + public InputStream getInputStream() throws IOException { + return new ByteArrayInputStream(content); + } + + @Override + public void transferTo(java.io.File dest) throws IOException, IllegalStateException { + // 实现此方法根据需要 + } +} + diff --git a/xueyi-api/xueyi-api-file/src/main/java/com/xueyi/file/api/feign/RemoteFileService.java b/xueyi-api/xueyi-api-file/src/main/java/com/xueyi/file/api/feign/RemoteFileService.java index 579aa91b..82a9066b 100644 --- a/xueyi-api/xueyi-api-file/src/main/java/com/xueyi/file/api/feign/RemoteFileService.java +++ b/xueyi-api/xueyi-api-file/src/main/java/com/xueyi/file/api/feign/RemoteFileService.java @@ -6,9 +6,11 @@ import com.xueyi.file.api.domain.SysFile; import com.xueyi.file.api.feign.factory.RemoteFileFallbackFactory; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.http.MediaType; +import org.springframework.scheduling.annotation.Async; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.multipart.MultipartFile; @@ -41,7 +43,8 @@ public interface RemoteFileService { * @return 结果 */ @PostMapping(value = "/inner/uploadpdf", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - R> uploadPdf(@RequestPart(value = "file") MultipartFile file); + @Async + R> uploadPdf(@RequestPart(value = "file") MultipartFile file, @RequestParam (value = "fileUuid") String fileUuid); /** * 删除文件 diff --git a/xueyi-api/xueyi-api-file/src/main/java/com/xueyi/file/api/feign/factory/RemoteFileFallbackFactory.java b/xueyi-api/xueyi-api-file/src/main/java/com/xueyi/file/api/feign/factory/RemoteFileFallbackFactory.java index 01600a8a..d07f0584 100644 --- a/xueyi-api/xueyi-api-file/src/main/java/com/xueyi/file/api/feign/factory/RemoteFileFallbackFactory.java +++ b/xueyi-api/xueyi-api-file/src/main/java/com/xueyi/file/api/feign/factory/RemoteFileFallbackFactory.java @@ -34,7 +34,7 @@ public class RemoteFileFallbackFactory implements FallbackFactory> uploadPdf(MultipartFile file) { + public R> uploadPdf(MultipartFile file, String uuid) { return R.fail("上传文件失败:" + throwable.getMessage() ); } diff --git a/xueyi-common/xueyi-common-redis/src/main/java/com/xueyi/common/redis/utils/RedisUtil.java b/xueyi-common/xueyi-common-redis/src/main/java/com/xueyi/common/redis/utils/RedisUtil.java index 0181dad2..9655f21c 100644 --- a/xueyi-common/xueyi-common-redis/src/main/java/com/xueyi/common/redis/utils/RedisUtil.java +++ b/xueyi-common/xueyi-common-redis/src/main/java/com/xueyi/common/redis/utils/RedisUtil.java @@ -43,4 +43,16 @@ public class RedisUtil { public static Boolean existed(String key){ return redisTemplate.hasKey(key); } + + public static void setVal(String key, Serializable value) { + redisTemplate.opsForValue().set(key, value); + } + + public static void setVal(String key, Serializable value, int seconds) { + redisTemplate.opsForValue().set(key, value, seconds, TimeUnit.SECONDS); + } + + public static Serializable getVal(String key) { + return redisTemplate.opsForValue().get(key); + } } diff --git a/xueyi-modules/xueyi-file/src/main/java/com/xueyi/file/controller/SysFileController.java b/xueyi-modules/xueyi-file/src/main/java/com/xueyi/file/controller/SysFileController.java index 27af54a0..661a1f1b 100644 --- a/xueyi-modules/xueyi-file/src/main/java/com/xueyi/file/controller/SysFileController.java +++ b/xueyi-modules/xueyi-file/src/main/java/com/xueyi/file/controller/SysFileController.java @@ -2,11 +2,13 @@ package com.xueyi.file.controller; import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson2.JSONArray; import com.xueyi.common.core.constant.basic.SecurityConstants; import com.xueyi.common.core.utils.core.IdUtil; import com.xueyi.common.core.utils.file.FileUtil; import com.xueyi.common.core.web.result.AjaxResult; import com.xueyi.common.core.web.result.R; +import com.xueyi.common.redis.utils.RedisUtil; import com.xueyi.file.api.domain.DigitalmanLogFile; import com.xueyi.file.api.domain.SysFile; import com.xueyi.file.api.feign.RemoteFileManageService; @@ -99,7 +101,7 @@ public class SysFileController { * 文件上传 | 内部调用 */ @PostMapping("/inner/uploadpdf") - public R> uploadPdfInner(MultipartFile file) { + public R> uploadPdfInner(MultipartFile file, String fileUuid) { try { Long startTs = System.currentTimeMillis(); log.info("文件上传开始:{}; start ts:{}", file.getName(), startTs); @@ -130,8 +132,21 @@ public class SysFileController { log.info("上传第 {} 张图片完成。。。",(num-1)); }; long endTs = System.currentTimeMillis(); - log.info("上传图片结束。。。,用时:{} ms", (endTs-pdfTs)); + log.info("上传图片结束。。。,图片上传用时:{} ms,总用时:{} ms", (endTs-pdfTs), (endTs-startTs)); + JSONArray ja = new JSONArray(); + for (SysFile sf : results) { + String url = sf.getUrl(); + Long size = sf.getSize(); + + JSONObject jo = new JSONObject(); + jo.put("url", url); + jo.put("size", size); + ja.add(jo); + } + + RedisUtil.setVal("saas:upload:result:"+fileUuid, ja.toJSONString()); + RedisUtil.setVal("saas:upload:filename:"+fileUuid, file.getOriginalFilename()); return R.ok(results); } catch (Exception e) { log.error("上传文件失败", e); @@ -186,7 +201,7 @@ public class SysFileController { */ @PostMapping("/uploadpdf") public AjaxResult uploadPdf(MultipartFile file) { - R> R = uploadPdfInner(file); + R> R = uploadPdfInner(file, IdUtil.randomUUID()); return R.isOk() ? AjaxResult.success("上传成功!", R.getData()) : AjaxResult.error("上传失败!"); diff --git a/xueyi-modules/xueyi-system/src/main/java/com/xueyi/system/resource/controller/DmResourcesController.java b/xueyi-modules/xueyi-system/src/main/java/com/xueyi/system/resource/controller/DmResourcesController.java index e99a76d1..4f3cf1bf 100644 --- a/xueyi-modules/xueyi-system/src/main/java/com/xueyi/system/resource/controller/DmResourcesController.java +++ b/xueyi-modules/xueyi-system/src/main/java/com/xueyi/system/resource/controller/DmResourcesController.java @@ -4,6 +4,7 @@ import cn.hutool.core.text.CharSequenceUtil; import cn.hutool.core.util.ObjectUtil; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; +import com.xueyi.common.core.utils.core.IdUtil; import com.xueyi.common.core.utils.file.FileTypeUtil; import com.xueyi.common.core.utils.file.MimeTypeUtil; import com.xueyi.common.core.web.result.AjaxResult; @@ -11,8 +12,10 @@ import com.xueyi.common.core.web.result.R; import com.xueyi.common.core.web.validate.V_E; import com.xueyi.common.log.annotation.Log; import com.xueyi.common.log.enums.BusinessType; +import com.xueyi.common.redis.utils.RedisUtil; import com.xueyi.common.security.annotation.RequiresPermissions; import com.xueyi.common.web.entity.controller.BaseController; +import com.xueyi.file.api.domain.ByteArrayMultipartFile; import com.xueyi.file.api.domain.SysFile; import com.xueyi.file.api.feign.RemoteFileService; import com.xueyi.system.api.resource.domain.po.DmResourcesPo; @@ -35,10 +38,13 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; +import java.io.IOException; import java.io.InputStream; import java.io.Serializable; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; /** * 静态资源管理 业务处理 @@ -140,22 +146,127 @@ public class DmResourcesController extends BaseController byteArrays = null; + try { + byteArrays = new ArrayList<>(); + + for (MultipartFile part : multipartFiles) { + // 从每个分片的MultipartFile中读取数据并存储到byte数组中 + byte[] bytes = part.getBytes(); + byteArrays.add(bytes); + } + + // 合并所有分片的byte数组为一个byte数组 + int totalSize = byteArrays.stream().mapToInt(byteArray -> byteArray.length).sum(); + byte[] mergedBytes = new byte[totalSize]; + int currentIndex = 0; + for (byte[] bytes : byteArrays) { + System.arraycopy(bytes, 0, mergedBytes, currentIndex, bytes.length); + currentIndex += bytes.length; + } + + // 创建一个新的MultipartFile对象,代表合并后的文件 + return new ByteArrayMultipartFile(mergedBytes); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + /** * 头像上传 */ @PostMapping("/upload") @Log(title = "资源管理 - 上传资源", businessType = BusinessType.UPDATE) public AjaxResult upload(@RequestParam("file") MultipartFile file) { + + return executeUpload(file, FileTypeUtil.getExtension(file)); + } + + + @GetMapping("/uploadCallback") + @Log(title = "资源管理 - 上传资源回调", businessType = BusinessType.UPDATE) + public AjaxResult pdfUploadCallback(@RequestParam("uploadUuid") String uploadUuid) { + + String result = (String) RedisUtil.getVal("saas:upload:result:"+uploadUuid); + String fileName = (String) RedisUtil.getVal("saas:upload:filename:"+uploadUuid); + + JSONArray res = JSONArray.parseArray(result); + List jsons = res.stream().map(sf -> (JSONObject) sf).collect(Collectors.toList()); + + JSONArray ja = new JSONArray(); + for (JSONObject sf : jsons) { + String url = (String) sf.get("url"); + DmResourcesDto dto = new DmResourcesDto(); + dto.setName(fileName); + dto.setUrl(url); + dto.setType(DmResourcesPo.TYPE_PIC); + dto.setFileSize((Long) sf.get("size")); + dto.setFeature(""); + + iDmResourcesService.addOne(dto); + JSONObject jo = new JSONObject(); + jo.put(PARAM_RESOURCE_ID, dto.getId()); + jo.put(PARAM_URL, url); + jo.put(PARAM_TYPE, dto.getType()); + ja.add(jo); + } + + AjaxResult ajax = success(); + ajax.put(AjaxResult.RESULT_TAG, ja); + logger.info("上传文件成功,返回数据:" + ajax.toJson().toJSONString()); + + return ajax; + } + + public AjaxResult executeUpload(MultipartFile file, String extension) { if (!file.isEmpty()) { - String extension = FileTypeUtil.getExtension(file); - logger.info("文件类型:" + extension+",上传开始..."); + logger.info("文件类型:" + extension + ",上传到MINIO开始..."); if (!CharSequenceUtil.equalsAnyIgnoreCase(extension, MimeTypeUtil.EXCEPT_ALLOWED_EXTENSION)) { return error("文件格式不正确,请上传" + Arrays.toString(MimeTypeUtil.EXCEPT_ALLOWED_EXTENSION) + "格式"); } - if(MimeTypeUtil.PDF_EXTENSION.equalsIgnoreCase(extension)) { - R> fileResult = remoteFileService.uploadPdf(file); - if (ObjectUtil.isNull(fileResult) || ObjectUtil.isNull(fileResult.getData())) + if (MimeTypeUtil.PDF_EXTENSION.equalsIgnoreCase(extension)) { + remoteFileService.uploadPdf(file, IdUtil.randomUUID()); + /*if (ObjectUtil.isNull(fileResult) || ObjectUtil.isNull(fileResult.getData())) return error("文件服务异常,请联系管理员!"); JSONArray ja = new JSONArray(); for (SysFile sf : fileResult.getData()) { @@ -173,10 +284,10 @@ public class DmResourcesController extends BaseController fileResult = remoteFileService.upload(file); @@ -186,7 +297,7 @@ public class DmResourcesController extends BaseController> fileResult = remoteFileService.uploadPdf(file); + R> fileResult = remoteFileService.uploadPdf(file, IdUtil.randomUUID()); if (ObjectUtil.isNull(fileResult) || ObjectUtil.isNull(fileResult.getData())) return error("文件服务异常,请联系管理员!"); JSONArray ja = new JSONArray();