|
@@ -16,56 +16,46 @@
|
|
|
*/
|
|
|
package org.springblade.resource.endpoint;
|
|
|
|
|
|
-import cn.hutool.core.util.StrUtil;
|
|
|
+import com.aliyun.oss.model.*;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
|
import io.swagger.annotations.Api;
|
|
|
import lombok.AllArgsConstructor;
|
|
|
import lombok.SneakyThrows;
|
|
|
import org.apache.commons.fileupload.disk.DiskFileItem;
|
|
|
import org.apache.commons.io.FileUtils;
|
|
|
+import org.apache.commons.lang.StringUtils;
|
|
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
|
|
import org.springblade.common.constant.CommonConstant;
|
|
|
-import org.springblade.common.utils.SnowFlakeUtil;
|
|
|
+import org.springblade.core.cache.utils.CacheUtil;
|
|
|
import org.springblade.core.oss.model.BladeFile;
|
|
|
-import org.springblade.core.oss.model.OssFile;
|
|
|
import org.springblade.core.secure.annotation.PreAuth;
|
|
|
import org.springblade.core.tenant.annotation.NonDS;
|
|
|
import org.springblade.core.tool.api.R;
|
|
|
import org.springblade.core.tool.constant.RoleConstant;
|
|
|
-import org.springblade.core.tool.utils.FileUtil;
|
|
|
-import org.springblade.core.tool.utils.Func;
|
|
|
import org.springblade.core.tool.utils.ObjectUtil;
|
|
|
import org.springblade.resource.builder.oss.OssBuilder;
|
|
|
-import org.springblade.resource.entity.Attach;
|
|
|
import org.springblade.resource.entity.LargeFile;
|
|
|
import org.springblade.resource.feign.CommonFileClient;
|
|
|
-import org.springblade.resource.service.IAttachService;
|
|
|
import org.springblade.resource.service.ILargeFileService;
|
|
|
-import org.springblade.resource.service.IOssService;
|
|
|
import org.springblade.resource.vo.MultipartFileParam;
|
|
|
import org.springblade.resource.vo.NewBladeFile;
|
|
|
import org.springblade.system.cache.ParamCache;
|
|
|
import org.springframework.beans.BeanUtils;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.data.redis.core.StringRedisTemplate;
|
|
|
import org.springframework.http.MediaType;
|
|
|
import org.springframework.util.DigestUtils;
|
|
|
import org.springframework.web.bind.annotation.*;
|
|
|
import org.springframework.web.multipart.MultipartFile;
|
|
|
import org.springframework.web.multipart.commons.CommonsMultipartFile;
|
|
|
|
|
|
-import javax.imageio.ImageIO;
|
|
|
-import javax.servlet.http.HttpServletRequest;
|
|
|
-import javax.servlet.http.HttpServletResponse;
|
|
|
-import java.awt.*;
|
|
|
-import java.awt.image.BufferedImage;
|
|
|
import java.io.*;
|
|
|
import java.lang.reflect.Method;
|
|
|
import java.nio.MappedByteBuffer;
|
|
|
-import java.nio.channels.FileChannel;
|
|
|
import java.security.AccessController;
|
|
|
import java.security.PrivilegedAction;
|
|
|
-import java.util.ArrayList;
|
|
|
+import java.util.*;
|
|
|
import java.util.List;
|
|
|
-import java.util.Objects;
|
|
|
import java.util.concurrent.locks.Lock;
|
|
|
import java.util.concurrent.locks.ReentrantLock;
|
|
|
|
|
@@ -89,13 +79,16 @@ public class LargeFileEndpoint {
|
|
|
private final ILargeFileService iLargeFileService;
|
|
|
|
|
|
private final Lock lock = new ReentrantLock();
|
|
|
- /**
|
|
|
- * 附件表服务
|
|
|
- */
|
|
|
- private final IAttachService attachService;
|
|
|
|
|
|
private final CommonFileClient commonFileClient;
|
|
|
|
|
|
+ @Autowired
|
|
|
+ StringRedisTemplate RedisTemplate;
|
|
|
+
|
|
|
+ private final String bucketName ="bladex-chongqing-info";
|
|
|
+
|
|
|
+ private final String endpoint ="http://oss-cn-hangzhou.aliyuncs.com";
|
|
|
+
|
|
|
/**
|
|
|
* 创建存储桶
|
|
|
*
|
|
@@ -123,6 +116,115 @@ public class LargeFileEndpoint {
|
|
|
ossBuilder.template().removeBucket(bucketName);
|
|
|
return R.success("删除成功");
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @return
|
|
|
+ * @throws Exception
|
|
|
+ * **/
|
|
|
+ @SneakyThrows
|
|
|
+ @PostMapping("/upload-file1234")
|
|
|
+ public R uploadByfile123(@RequestParam(value = "file",required=false) MultipartFile file,
|
|
|
+ @RequestParam(value = "identifier",required=false) String identifier,
|
|
|
+ @RequestParam(value = "chunkNumber",required=false) Integer chunkNumber,
|
|
|
+ @RequestParam(value = "chunkSize",required=false) Integer chunkSize,
|
|
|
+ @RequestParam(value = "currentChunkSize",required=false) String currentChunkSize,
|
|
|
+ @RequestParam(value = "filename",required=false) String filename,
|
|
|
+ @RequestParam(value = "relativePath",required=false) String relativePath,
|
|
|
+ @RequestParam(value = "totalChunks",required=false) Integer totalChunks,
|
|
|
+ @RequestParam(value = "totalSize",required=false) String totalSize,
|
|
|
+ @RequestParam(value = "objectType",required=false) String objectType){
|
|
|
+
|
|
|
+ // 文件上传
|
|
|
+ String taskKey ="upload/20221220/"+ filename;
|
|
|
+ UmsAdminLoginLogDO param =new UmsAdminLoginLogDO();
|
|
|
+ if (file == null && totalChunks >=0 && StringUtils.isNotEmpty(identifier)) {
|
|
|
+ // 请求阿里云oss获取分片唯一ID
|
|
|
+ String ossSlicesId = this.getUploadId(taskKey);
|
|
|
+ RedisTemplate.opsForValue().set(identifier,ossSlicesId);
|
|
|
+ return R.fail("没有文件");
|
|
|
+ }
|
|
|
+
|
|
|
+ String uploadId = RedisTemplate.opsForValue().get(identifier);
|
|
|
+
|
|
|
+ UmsAdminLoginLogDO redisParam = (UmsAdminLoginLogDO) CacheUtil.get("oss","PartETag",uploadId);
|
|
|
+ if (redisParam !=null) {
|
|
|
+ param.setPartETags(redisParam.getPartETags());
|
|
|
+ }
|
|
|
+
|
|
|
+ Map<Integer, PartETag> partETags = param.getPartETags();
|
|
|
+
|
|
|
+ UploadPartRequest request = new UploadPartRequest();
|
|
|
+ request.setInputStream(file.getInputStream());
|
|
|
+ request.setBucketName(bucketName);
|
|
|
+ request.setPartNumber(chunkNumber);
|
|
|
+ request.setPartSize(Long.parseLong(currentChunkSize));
|
|
|
+ request.setKey(filename);
|
|
|
+ request.setMd5Digest(identifier);
|
|
|
+ request.setUploadId(uploadId);
|
|
|
+
|
|
|
+ try {
|
|
|
+ UploadPartResult uploadPartResult = ossBuilder.template().uploadPart(request);
|
|
|
+ PartETag partETag = uploadPartResult.getPartETag();
|
|
|
+ partETags.put(chunkNumber, partETag);
|
|
|
+ //分片编号等于总片数的时候合并文件,如果符合条件则合并文件,否则继续等待
|
|
|
+ if (chunkNumber == totalChunks) {
|
|
|
+ //合并文件,注意:partETags必须是所有分片的所以必须存入redis,然后取出放入集合
|
|
|
+ String url = this.completePartUploadFile(filename, uploadId,
|
|
|
+ new ArrayList<>(partETags.values()));
|
|
|
+ //oss地址返回后存入并清除redis
|
|
|
+ RedisTemplate.delete(uploadId);
|
|
|
+ return R.data(url);
|
|
|
+ }else {
|
|
|
+ RedisTemplate.opsForHash().putAll(uploadId, partETags);
|
|
|
+ CacheUtil.put("oss","PartETag",uploadId, param);
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+
|
|
|
+ return R.data("");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 分块上传完成获取结果
|
|
|
+ */
|
|
|
+ public String completePartUploadFile(String fileKey, String uploadId, List<PartETag> partETags) {
|
|
|
+ CompleteMultipartUploadRequest request = new CompleteMultipartUploadRequest(bucketName, fileKey, uploadId,
|
|
|
+ partETags);
|
|
|
+ ossBuilder.template().completeMultipartUpload(request);
|
|
|
+ String downLoadUrl = getDownloadUrl(fileKey, bucketName);
|
|
|
+ return downLoadUrl;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取bucket文件的下载链接
|
|
|
+ *
|
|
|
+ * @param pathFile 首字母不带/的路径和文件
|
|
|
+ * @param bucketName
|
|
|
+ * @return 上报返回null, 成功返回地址
|
|
|
+ */
|
|
|
+ public String getDownloadUrl(String pathFile, String bucketName) {
|
|
|
+ if (bucketName == null || "".equals(bucketName)) {
|
|
|
+ bucketName = bucketName;
|
|
|
+ }
|
|
|
+ StringBuffer url = new StringBuffer();
|
|
|
+ url.append("http://").append(bucketName).append(endpoint).append("/");
|
|
|
+ if (pathFile != null && !"".equals(pathFile)) {
|
|
|
+ url.append(pathFile);
|
|
|
+ }
|
|
|
+ return url.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ public String getUploadId(String fileKey) {
|
|
|
+ InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, fileKey);
|
|
|
+ // 初始化分片
|
|
|
+ InitiateMultipartUploadResult unrest = ossBuilder.template().initiateMultipartUpload(request);
|
|
|
+ // 返回uploadId,它是分片上传事件的唯一标识,您可以根据这个ID来发起相关的操作,如取消分片上传、查询分片上传等。
|
|
|
+ String uploadId = unrest.getUploadId();
|
|
|
+ return uploadId;
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* @return
|
|
|
* @throws Exception
|
|
@@ -206,13 +308,8 @@ public class LargeFileEndpoint {
|
|
|
String tempFileName = param.getIdentifier() + fileName.substring(fileName.lastIndexOf(".")) + "."+param.getChunkNumber();
|
|
|
// 获取文件路径
|
|
|
/**Windows文件路径要加在哪个盘**/
|
|
|
-// String filePath = "D:/www/wwwroot/Users/hongchuangyanfa/Desktop/Desktop/ceshi";
|
|
|
String filePath =ParamCache.getValue(CommonConstant.SYS_LOCAL_URL)+"largeFile/";
|
|
|
- // 创建文件夹
|
|
|
-// getAbsoluteFile(filePath, fileName);
|
|
|
-// new File(filePath, fileName);
|
|
|
- // 创建临时文件
|
|
|
-// File tempFile = new File(filePath, tempFileName);
|
|
|
+
|
|
|
File tempFile = buildUploadFile(tempFileName);
|
|
|
param.getFile().transferTo(tempFile);
|
|
|
|
|
@@ -220,25 +317,8 @@ public class LargeFileEndpoint {
|
|
|
* 以上意思是把每个分片都保存成本地一个文件,如 测试.mp4.1 最后合并
|
|
|
* ===================================================
|
|
|
* 以下注释是把分片存到一个文件,持续写入,感觉不太保险**/
|
|
|
-// //第一步 获取RandomAccessFile,随机访问文件类的对象
|
|
|
-// RandomAccessFile raf = new RandomAccessFile(tempFile,"rw");
|
|
|
-// //第二步 调用RandomAccessFile的getChannel()方法,打开文件通道 FileChannel
|
|
|
-// FileChannel fileChannel = raf.getChannel();
|
|
|
-// //第三步 获取当前是第几个分块,计算文件的最后偏移量
|
|
|
-// long offset = (param.getChunkNumber() - 1) * param.getChunkSize();
|
|
|
-// //第四步 获取当前文件分块的字节数组,用于获取文件字节长度
|
|
|
-// byte[] fileData = param.getFile().getBytes();
|
|
|
-// //第五步 使用文件通道FileChannel类的 map()方法创建直接字节缓冲器 MappedByteBuffer
|
|
|
-// MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, offset, fileData.length);
|
|
|
-// //第六步 将分块的字节数组放入到当前位置的缓冲区内 mappedByteBuffer.put(byte[] b)
|
|
|
-// mappedByteBuffer.put(fileData);
|
|
|
-// //第七步 释放缓冲区
|
|
|
-// freeMappedByteBuffer(mappedByteBuffer);
|
|
|
-// fileChannel.close();
|
|
|
-// raf.close();
|
|
|
- //第八步,保存分片信息
|
|
|
- LargeFile largeFile = new LargeFile();
|
|
|
|
|
|
+ LargeFile largeFile = new LargeFile();
|
|
|
largeFile.setFileKey(param.getIdentifier());
|
|
|
largeFile.setName(tempFileName);
|
|
|
largeFile.setPath(filePath+fileName);
|
|
@@ -301,7 +381,6 @@ public class LargeFileEndpoint {
|
|
|
result.setSuccess(true);
|
|
|
result.setMsg("上传成功!");
|
|
|
result.setData(newBladeFile);
|
|
|
-// result.setData(new BladeFile());
|
|
|
result.setCode(200);
|
|
|
return result;
|
|
|
}
|