Sfoglia il codice sorgente

fix upload pdf file

tags/B.2.2.0.6_20231012_base
yk 2 anni fa
parent
commit
600fd38fc6
6 ha cambiato i file con 224 aggiunte e 16 eliminazioni
  1. +68
    -0
      xueyi-api/xueyi-api-file/src/main/java/com/xueyi/file/api/domain/ByteArrayMultipartFile.java
  2. +4
    -1
      xueyi-api/xueyi-api-file/src/main/java/com/xueyi/file/api/feign/RemoteFileService.java
  3. +1
    -1
      xueyi-api/xueyi-api-file/src/main/java/com/xueyi/file/api/feign/factory/RemoteFileFallbackFactory.java
  4. +12
    -0
      xueyi-common/xueyi-common-redis/src/main/java/com/xueyi/common/redis/utils/RedisUtil.java
  5. +18
    -3
      xueyi-modules/xueyi-file/src/main/java/com/xueyi/file/controller/SysFileController.java
  6. +121
    -11
      xueyi-modules/xueyi-system/src/main/java/com/xueyi/system/resource/controller/DmResourcesController.java

+ 68
- 0
xueyi-api/xueyi-api-file/src/main/java/com/xueyi/file/api/domain/ByteArrayMultipartFile.java Vedi File

@@ -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 {
// 实现此方法根据需要
}
}


+ 4
- 1
xueyi-api/xueyi-api-file/src/main/java/com/xueyi/file/api/feign/RemoteFileService.java Vedi File

@@ -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<List<SysFile>> uploadPdf(@RequestPart(value = "file") MultipartFile file);
@Async
R<List<SysFile>> uploadPdf(@RequestPart(value = "file") MultipartFile file, @RequestParam (value = "fileUuid") String fileUuid);

/**
* 删除文件


+ 1
- 1
xueyi-api/xueyi-api-file/src/main/java/com/xueyi/file/api/feign/factory/RemoteFileFallbackFactory.java Vedi File

@@ -34,7 +34,7 @@ public class RemoteFileFallbackFactory implements FallbackFactory<RemoteFileServ
}

@Override
public R<List<SysFile>> uploadPdf(MultipartFile file) {
public R<List<SysFile>> uploadPdf(MultipartFile file, String uuid) {
return R.fail("上传文件失败:" + throwable.getMessage() );
}



+ 12
- 0
xueyi-common/xueyi-common-redis/src/main/java/com/xueyi/common/redis/utils/RedisUtil.java Vedi File

@@ -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);
}
}

+ 18
- 3
xueyi-modules/xueyi-file/src/main/java/com/xueyi/file/controller/SysFileController.java Vedi File

@@ -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<List<SysFile>> uploadPdfInner(MultipartFile file) {
public R<List<SysFile>> 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<List<SysFile>> R = uploadPdfInner(file);
R<List<SysFile>> R = uploadPdfInner(file, IdUtil.randomUUID());
return R.isOk()
? AjaxResult.success("上传成功!", R.getData())
: AjaxResult.error("上传失败!");


+ 121
- 11
xueyi-modules/xueyi-system/src/main/java/com/xueyi/system/resource/controller/DmResourcesController.java Vedi File

@@ -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<DmResourcesQuery, DmRe
private static final String PARAM_URL = "url";

private static final String PARAM_TYPE = "type";


private MultipartFile[] completedChunks; // 用于跟踪已上传完毕的块

@PostMapping("/chunk")
public AjaxResult uploadChunk(
@RequestParam("file") MultipartFile file,
@RequestParam("index") int chunkIndex,
@RequestParam("totalChunks") int totalChunks
) throws IOException {
if (completedChunks == null) {
completedChunks = new MultipartFile[totalChunks];
}

logger.info("第{}/{}块上传成功", chunkIndex, totalChunks);

completedChunks[chunkIndex] = file; // 标记当前块已上传完毕

// 如果所有块都上传完毕,开始合并
if (allChunksUploaded(completedChunks)) {
logger.info("所有块上传完毕,开始合并...");
String extension = FileTypeUtil.getExtension(file);
return executeUpload(mergeChunks(completedChunks), extension);
}
logger.info("上传完毕");

return AjaxResult.error("上传文件异常,请联系管理员!");
}

private boolean allChunksUploaded(MultipartFile[] completedChunks) {
for (MultipartFile completed : completedChunks) {
if (null == completed) {
return false; // 如果有任何一个块没有上传完毕,返回false
}
}
return true; // 所有块都上传完毕
}

private MultipartFile mergeChunks(MultipartFile[] multipartFiles) {
List<byte[]> 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<JSONObject> 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<List<SysFile>> 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<DmResourcesQuery, DmRe
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());
ajax.put(AjaxResult.MSG_TAG, "文件后台上传处理中...");
logger.info("异步上传文件...");
return ajax;
} else {
R<SysFile> fileResult = remoteFileService.upload(file);
@@ -186,7 +297,7 @@ public class DmResourcesController extends BaseController<DmResourcesQuery, DmRe
DmResourcesDto dto = new DmResourcesDto();
dto.setName(file.getOriginalFilename());
dto.setUrl(url);
if (CharSequenceUtil.equalsAnyIgnoreCase(extension, MimeTypeUtil.IMAGE_EXTENSION) ) {
if (CharSequenceUtil.equalsAnyIgnoreCase(extension, MimeTypeUtil.IMAGE_EXTENSION)) {
dto.setType(DmResourcesPo.TYPE_PIC);
}
if (CharSequenceUtil.equalsAnyIgnoreCase(extension, MimeTypeUtil.VIDEO_EXTENSION)) {
@@ -206,7 +317,6 @@ public class DmResourcesController extends BaseController<DmResourcesQuery, DmRe
logger.info("上传文件成功,返回数据:" + ajax.toJson().toJSONString());
return ajax;
}

}
return error("上传文件异常,请联系管理员!");
}
@@ -223,7 +333,7 @@ public class DmResourcesController extends BaseController<DmResourcesQuery, DmRe
) {
return error("文件格式不正确,请上传" + Arrays.toString(MimeTypeUtil.IMAGE_EXTENSION) + Arrays.toString(MimeTypeUtil.IMAGE_EXTENSION) + "格式");
}
R<List<SysFile>> fileResult = remoteFileService.uploadPdf(file);
R<List<SysFile>> fileResult = remoteFileService.uploadPdf(file, IdUtil.randomUUID());
if (ObjectUtil.isNull(fileResult) || ObjectUtil.isNull(fileResult.getData()))
return error("文件服务异常,请联系管理员!");
JSONArray ja = new JSONArray();


Caricamento…
Annulla
Salva