当前位置: 首页 > wzjs >正文

网站建站客户需求表单公司旅游视频网站模板免费下载

网站建站客户需求表单,公司旅游视频网站模板免费下载,建设网站项目总结,论坛网站开发的目的和意义分片上传(Multipart Upload)是大文件上传的常用方案,可以解决大文件上传超时、网络不稳定等问题。以下是基于Spring Boot和Minio实现分片上传的完整方案。 1. 分片上传原理 初始化上传:创建分片上传任务,获取唯一上传…

分片上传(Multipart Upload)是大文件上传的常用方案,可以解决大文件上传超时、网络不稳定等问题。以下是基于Spring Boot和Minio实现分片上传的完整方案。

1. 分片上传原理

  1. 初始化上传:创建分片上传任务,获取唯一上传ID
  2. 上传分片:将文件分成多个分片依次上传
  3. 完成上传:所有分片上传完成后合并文件
  4. 取消上传:可中途取消并删除已上传分片

2. 工具类扩展

在原有MinioUtil基础上增加分片上传相关方法:

import io.minio.messages.Part;import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;@Component
public class MinioUtil {// ... 原有代码 ...// 保存上传ID的缓存private final Map<String, String> uploadIdCache = new ConcurrentHashMap<>();/*** 初始化分片上传* @param bucketName 存储桶名称* @param objectName 对象名称* @return 上传ID*/public String initMultiPartUpload(String bucketName, String objectName) throws Exception {String uploadId = minioClient.initiateMultipartUpload(InitiateMultipartUploadArgs.builder().bucket(bucketName).object(objectName).build()).uploadId();uploadIdCache.put(objectName, uploadId);return uploadId;}/*** 上传分片* @param bucketName 存储桶名称* @param objectName 对象名称* @param uploadId   上传ID* @param partNumber 分片序号(1-based)* @param inputStream 分片数据流* @param partSize   分片大小* @return 分片信息*/public Part uploadPart(String bucketName, String objectName, String uploadId,int partNumber, InputStream inputStream, long partSize) throws Exception {String etag = minioClient.uploadPart(UploadPartArgs.builder().bucket(bucketName).object(objectName).uploadId(uploadId).partNumber(partNumber).stream(inputStream, partSize, -1).build()).etag();return new Part(partNumber, etag);}/*** 完成分片上传* @param bucketName 存储桶名称* @param objectName 对象名称* @param uploadId   上传ID* @param parts      分片列表*/public void completeMultiPartUpload(String bucketName, String objectName, String uploadId, Part[] parts) throws Exception {minioClient.completeMultipartUpload(CompleteMultipartUploadArgs.builder().bucket(bucketName).object(objectName).uploadId(uploadId).parts(parts).build());uploadIdCache.remove(objectName);}/*** 取消分片上传* @param bucketName 存储桶名称* @param objectName 对象名称* @param uploadId   上传ID*/public void abortMultiPartUpload(String bucketName, String objectName, String uploadId) throws Exception {minioClient.abortMultipartUpload(AbortMultipartUploadArgs.builder().bucket(bucketName).object(objectName).uploadId(uploadId).build());uploadIdCache.remove(objectName);}/*** 获取上传ID(从缓存)* @param objectName 对象名称* @return 上传ID*/public String getUploadId(String objectName) {return uploadIdCache.get(objectName);}
}

3. 控制器实现

@RestController
@RequestMapping("/multipart")
public class MultipartUploadController {@Autowiredprivate MinioUtil minioUtil;@Value("${minio.bucketName}")private String bucketName;// 保存各分片上传进度private final Map<String, List<Part>> partProgressMap = new ConcurrentHashMap<>();/*** 初始化分片上传*/@PostMapping("/init")public ResponseEntity<?> initUpload(@RequestParam String fileName) {try {String uploadId = minioUtil.initMultiPartUpload(bucketName, fileName);partProgressMap.put(fileName, new ArrayList<>());return ResponseEntity.ok(Map.of("uploadId", uploadId,"code", 200,"message", "初始化成功"));} catch (Exception e) {return ResponseEntity.status(500).body(Map.of("code", 500,"message", "初始化失败: " + e.getMessage()));}}/*** 上传分片*/@PostMapping("/upload")public ResponseEntity<?> uploadPart(@RequestParam String fileName,@RequestParam String uploadId,@RequestParam int partNumber,@RequestParam MultipartFile file) {try {// 获取或创建分片列表List<Part> parts = partProgressMap.computeIfAbsent(fileName, k -> new ArrayList<>());// 上传分片Part part = minioUtil.uploadPart(bucketName, fileName, uploadId,partNumber, file.getInputStream(), file.getSize());// 保存分片信息parts.add(part);return ResponseEntity.ok(Map.of("code", 200,"message", "分片上传成功","partNumber", partNumber,"etag", part.etag()));} catch (Exception e) {return ResponseEntity.status(500).body(Map.of("code", 500,"message", "分片上传失败: " + e.getMessage()));}}/*** 完成分片上传*/@PostMapping("/complete")public ResponseEntity<?> completeUpload(@RequestParam String fileName,@RequestParam String uploadId) {try {List<Part> parts = partProgressMap.get(fileName);if (parts == null || parts.isEmpty()) {throw new RuntimeException("没有找到分片信息");}// 完成上传minioUtil.completeMultiPartUpload(bucketName, fileName, uploadId,parts.toArray(new Part[0]));// 清理缓存partProgressMap.remove(fileName);return ResponseEntity.ok(Map.of("code", 200,"message", "文件上传完成","fileName", fileName,"url", minioUtil.getFileUrl(bucketName, fileName)));} catch (Exception e) {return ResponseEntity.status(500).body(Map.of("code", 500,"message", "完成上传失败: " + e.getMessage()));}}/*** 取消上传*/@PostMapping("/abort")public ResponseEntity<?> abortUpload(@RequestParam String fileName,@RequestParam String uploadId) {try {minioUtil.abortMultiPartUpload(bucketName, fileName, uploadId);partProgressMap.remove(fileName);return ResponseEntity.ok(Map.of("code", 200,"message", "上传已取消"));} catch (Exception e) {return ResponseEntity.status(500).body(Map.of("code", 500,"message", "取消上传失败: " + e.getMessage()));}}
}

4. 前端实现示例

前端可以使用以下逻辑实现分片上传:

// 配置
const CHUNK_SIZE = 5 * 1024 * 1024; // 5MB分片大小async function uploadFile(file) {// 1. 初始化上传const initResponse = await fetch(`/multipart/init?fileName=${file.name}`);const initData = await initResponse.json();const uploadId = initData.uploadId;// 2. 分片上传const chunks = Math.ceil(file.size / CHUNK_SIZE);const parts = [];for (let i = 0; i < chunks; i++) {const start = i * CHUNK_SIZE;const end = Math.min(file.size, start + CHUNK_SIZE);const chunk = file.slice(start, end);const formData = new FormData();formData.append('file', chunk);formData.append('fileName', file.name);formData.append('uploadId', uploadId);formData.append('partNumber', i + 1);const uploadResponse = await fetch('/multipart/upload', {method: 'POST',body: formData});const uploadData = await uploadResponse.json();console.log(`分片 ${i + 1}/${chunks} 上传完成`, uploadData);}// 3. 完成上传const completeResponse = await fetch('/multipart/complete', {method: 'POST',headers: {'Content-Type': 'application/x-www-form-urlencoded',},body: `fileName=${encodeURIComponent(file.name)}&uploadId=${uploadId}`});const completeData = await completeResponse.json();console.log('文件上传完成', completeData);return completeData.url;
}

5. 断点续传实现

要实现断点续传功能,可以增加以下方法:

/*** 列出已上传的分片*/
@GetMapping("/listParts")
public ResponseEntity<?> listParts(@RequestParam String fileName,@RequestParam String uploadId) {try {List<Part> existingParts = minioUtil.listParts(bucketName, fileName, uploadId);return ResponseEntity.ok(Map.of("code", 200,"data", existingParts.stream().map(p -> Map.of("partNumber", p.partNumber(),"etag", p.etag())).collect(Collectors.toList())));} catch (Exception e) {return ResponseEntity.status(500).body(Map.of("code", 500,"message", "查询分片失败: " + e.getMessage()));}
}

然后在MinioUtil中添加:

/*** 列出已上传的分片*/
public List<Part> listParts(String bucketName, String objectName, String uploadId) throws Exception {return minioClient.listParts(ListPartsArgs.builder().bucket(bucketName).object(objectName).uploadId(uploadId).build()).result().partList();
}

前端可以首先查询已上传的分片,然后只上传缺失的分片:

async function resumeUpload(file, uploadId) {// 查询已上传的分片const partsResponse = await fetch(`/multipart/listParts?fileName=${file.name}&uploadId=${uploadId}`);const partsData = await partsResponse.json();const uploadedParts = new Set(partsData.data.map(p => p.partNumber));// 继续上传剩余分片const chunks = Math.ceil(file.size / CHUNK_SIZE);for (let i = 0; i < chunks; i++) {if (!uploadedParts.has(i + 1)) {// 上传缺失的分片...}}// 完成上传...
}

6. 注意事项

  1. 分片大小:建议设置为5MB-15MB,过小会增加请求次数,过大会增加失败风险
  2. 并发上传:可以并行上传多个分片以提高速度,但需要注意服务器压力
  3. 超时设置:为分片上传操作设置合理的超时时间
  4. 清理机制:实现定时任务清理未完成的分片上传,避免存储空间浪费
  5. 安全性:验证上传ID和分片序号,防止恶意请求

文章转载自:

http://uP3NcABv.nkcfh.cn
http://PVy8ibvi.nkcfh.cn
http://psGhiCNY.nkcfh.cn
http://qrHP2h0S.nkcfh.cn
http://jThZbs8M.nkcfh.cn
http://AvTH3wEI.nkcfh.cn
http://LvmENcf8.nkcfh.cn
http://LJkgrxWw.nkcfh.cn
http://ShQo7F6h.nkcfh.cn
http://5IBjCkfX.nkcfh.cn
http://bnJOIN6F.nkcfh.cn
http://DErgt4br.nkcfh.cn
http://CchBbGUr.nkcfh.cn
http://rLu0LwMg.nkcfh.cn
http://a4S60GL7.nkcfh.cn
http://3NZDYvLQ.nkcfh.cn
http://FRiZ1CLk.nkcfh.cn
http://EUWuZwqp.nkcfh.cn
http://Q8sR38A1.nkcfh.cn
http://DG5ir87T.nkcfh.cn
http://sb4cqqzF.nkcfh.cn
http://M0wLPf7S.nkcfh.cn
http://fO2NEWJW.nkcfh.cn
http://27nejIiN.nkcfh.cn
http://9BFdMxoz.nkcfh.cn
http://wJITgAGX.nkcfh.cn
http://ACNNRHUE.nkcfh.cn
http://jwg1rfo8.nkcfh.cn
http://DdYPhyXo.nkcfh.cn
http://uA2JUduf.nkcfh.cn
http://www.dtcms.com/wzjs/704629.html

相关文章:

  • wordpress站点预览wordpress确认窗口
  • 保定市住房保障和城乡建设局网站什么网站可以做高三英语试题
  • 网站每年的维护费最新网站建设视频
  • 张家港网站设计有吗公众号网站制作
  • 佛山做网站自主网站建站
  • 网站建设访问人群哈尔滨建设工程信息网站
  • 网站建设微分销企业网站建设费多少钱
  • 北京公司注册核名网站小程序模板平台有哪些
  • 个人网站如何做支付功能徐州建站模板公司
  • 网站建设主题的确定服务平台是什么意思
  • o2o网站设计vps 安装 wordpress
  • 网站后台不能修改电子商务网站设计代做
  • 网站建设费做什么会计科目诸暨企业网站建设
  • 如何在阿里云上建设网站长安汽车网址大全
  • 甘肃网站建站系统平台张家港江阴网站制作
  • 2017民非单位年检那个网站做vivo手机为什么建设网站
  • 一个优秀的网站如何查询网站点击量
  • 郑州企业网站seo外包公司怎么赚钱
  • 没网站做哪个广告联盟网店商品页面制作加工
  • 旅游网站首页设计什么是电子商务网站
  • 网站运营预期效果建设网站案例
  • php网站开发软件语言展会网站制作
  • 个人电脑做外网网站手机浏览器下载大全免费下载
  • 发布网站后备案成都百度关键词排名
  • 阜阳微网站建设多少钱品牌推广渠道
  • gta手机网站大全网站速成
  • wordpress重新安装优化外包哪里好
  • 个人可以做社区网站html电影网页设计实例代码
  • wordpress改为邮箱验证注册廊坊seo网络推广
  • 海鲜网站模板保定网站建设方案优化