vue java 实现大地图切片上传

embedded/2025/3/31 11:15:20/

在这里插入图片描述

文章目录

  • 一、项目背景
  • 二、页面
  • 三、代码
    • 1.前端
    • 2.mock-i18n.js文件
    • 3.xx.js文件定义方法
    • 4.配置文件 application.properties
    • 5.后端方法
  • 四、易错点
    • 易错点1:前端要进行分片切割,然后再分片上传
    • 易错点2:后端配置文件要配置。
    • 易错点3:个人感觉最好分片大小别太大。
    • 易错点4:上传途中最好加个“遮罩”或者进度条,比如显示“正在上传中......”会更友好。
    • 易错点5:如果项目采用nginx,记得修改nginx.conf。
  • 五、补充点

一、项目背景

技术:vue+Arco Design+java

介绍:页面上传mapShow.zip压缩包,只允许上传压缩包,且上传有格式校验,然后文件大小在600M或者上G的压缩包,像这种上传是不可能直接一整个包上传的,浏览器也不支持,同时这样做也不友好。

解决方案:采用分片技术,即把一个打压缩包切割成每个10M大小的分片,然后上传到指定目录下,最后再把所有分片文件进行合并成mapShow.zip压缩包,最后再解压mapShow.zip文件到指定目录下即可。

二、页面

在这里插入图片描述

三、代码

1.前端

java"><div class="param"><a-spin style="width: 70%"><div class="param-title"><div class="param-title-text">{{ $t("OfflineMapPathSetting") }}:</div></div><div class="param-content"><divclass="parent"style="display: flex; align-items: center; gap: 20px"><div><span class="label">{{ $t("Import") }}:</span></div><a-input class="div" v-model="fileName" disabled /><a-upload@change="onChange":auto-upload="false":show-file-list="false"><template #upload-button><svg-loaderclass="frameIcon"name="import-file"></svg-loader></template></a-upload></div></div></a-spin>
</div>const onChange = async (fileList) => {files.value = [];const lastUploadedFile = fileList[fileList.length - 1];fileName.value = lastUploadedFile.name;const allowedExtensions = /(.zip)$/i;if (!allowedExtensions.exec(lastUploadedFile.name)) {Message.error(t("invalidCerFileType2"));return;}uploadeLoading.value = true;if (fileList.length > 0) {const lastUploadedFile = fileList[fileList.length - 1];const chunkSize = 10 * 1024 * 1024;const totalChunks = Math.ceil(lastUploadedFile.file.size / chunkSize);for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) {const start = chunkIndex * chunkSize;const end = Math.min(start + chunkSize, lastUploadedFile.file.size);const chunk = lastUploadedFile.file.slice(start, end);const formData = new FormData();formData.append("file", chunk);formData.append("fileId", "mapShow");formData.append("chunkIndex", chunkIndex);formData.append("totalChunks", totalChunks);await importOfflineMapFunction(formData);}progress.value = 100;uploadeLoading.value = false;Message.success(t("LoadMap"));}
};const importOfflineMapFunction = async (formData) => {await importOfflineMap(formData).then((response) => {commonResponse({response,onSuccess: () => {},});});
};

2.mock-i18n.js文件

java">"invalidCerFileType2": "无效的文件类型,文件后缀必须是.zip等格式"

3.xx.js文件定义方法

java">export const importOfflineMap = (data) => {return $http({url: `/api/systemParam/importOfflineMap`,method: Method.POST,headers: {'Content-Type': 'multipart/form-data','X-Requested-With': 'XMLHttpRequest'},data,timeout: 300000})
}

4.配置文件 application.properties

java">spring.servlet.multipart.max-file-size=600MB
spring.servlet.multipart.max-request-size=2GB

5.后端方法

java">private static String OFFLINE_MAP_TEMPORARY_PATH = "\\..\\temporary\\";
private static String OFFLINE_MAP_TARGET_PATH = "\\..\\nginx\\html\\mapShow\\";@Operation(summary = "导入离线地图")
@PostMapping(value = "/importOfflineMap")
public ResponseModel importOfflineMap(@RequestParam("file") MultipartFile file,@RequestParam("fileId") String fileId,@RequestParam("chunkIndex") int chunkIndex,@RequestParam("totalChunks") int totalChunks) {return systemParamUserControl.importOfflineMap(file, fileId, chunkIndex, totalChunks);
}public ResponseModel importOfflineMap(MultipartFile file, String fileId, int chunkIndex, int totalChunks) {try {String userDir = System.getProperty("user.dir");logger.info("importOfflineMap-user.dir:{}", userDir);String offlineMapTemporaryPath = userDir + OFFLINE_MAP_TEMPORARY_PATH;File uploadFile = new File(offlineMapTemporaryPath);if (!uploadFile.exists()) {uploadFile.mkdirs();}String chunkFileName = offlineMapTemporaryPath + fileId + ".part" + chunkIndex;file.transferTo(new File(chunkFileName));if (chunkIndex == totalChunks - 1) {String offlineMapTargetPath = userDir + OFFLINE_MAP_TARGET_PATH;mergeFile(fileId, totalChunks, offlineMapTemporaryPath, offlineMapTargetPath);}} catch (IOException e) {logger.error("importOfflineMap-IOException:{}", e);}return ResponseModel.ofSuccess();}private void mergeFile(String fileId, int totalChunks, String offlineMapTemporaryPath, String offlineMapTargetPath) {// 创建最终文件File outputFile = new File(offlineMapTemporaryPath + fileId + ".zip");try {FileOutputStream fos = new FileOutputStream(outputFile);for (int i = 0; i < totalChunks; i++) {Path chunkPath = Paths.get(offlineMapTemporaryPath + fileId + ".part" + i);Files.copy(chunkPath, fos);Files.delete(chunkPath);}unzip(outputFile, offlineMapTargetPath);} catch (Exception e) {logger.error("mergeFile-Exception:{}", e);}}private void unzip(File zipFile, String destDir) throws IOException {byte[] buffer = new byte[1024];try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile))) {ZipEntry zipEntry = zis.getNextEntry();while (zipEntry != null) {File newFile = new File(destDir, zipEntry.getName());if (zipEntry.isDirectory()) {newFile.mkdirs();} else {// Create directories for nested filesnew File(newFile.getParent()).mkdirs();try (FileOutputStream fos = new FileOutputStream(newFile)) {int len;while ((len = zis.read(buffer)) > 0) {fos.write(buffer, 0, len);}}}zipEntry = zis.getNextEntry();}zis.closeEntry();}zipFile.delete();}

四、易错点

易错点1:前端要进行分片切割,然后再分片上传

易错点2:后端配置文件要配置。

后端配置文件要配置,不然默认浏览器只支持5M或者1M,当上传10M分片文件时会报错,无法调通接口,执行流程就卡在前端了,压根调不通后端上传接口。

java">spring.servlet.multipart.max-file-size=600MB
spring.servlet.multipart.max-request-size=2GB

易错点3:个人感觉最好分片大小别太大。

易错点4:上传途中最好加个“遮罩”或者进度条,比如显示“正在上传中…”会更友好。

易错点5:如果项目采用nginx,记得修改nginx.conf。

如果项目采用nginx,记得修改nginx.conf,配置上传切片大小、超时时间等等参数设置,否则也会上传失败。

五、补充点

网上还有网友说道使用什么“断点续传”的功能,这个我目前未验证,不清楚如何,其他博主可自行验证然后分享结论看是否可行。


http://www.ppmy.cn/embedded/176551.html

相关文章

如何在百度搜索上删除与自己名字相关的资料

个人信息的网络足迹如同一张无形的网&#xff0c;将我们与世界的每一个角落紧密相连。然而&#xff0c;当某些与自己名字相关的资料不再希望被公众轻易检索到时&#xff0c;如何在百度搜索中有效“隐身”&#xff0c;成为了一个亟待解决的问题。面对复杂多变的网络环境&#xf…

蓝桥杯,冬奥大抽奖

在日常的网页开发中&#xff0c;抽奖功能是一种常见的交互设计&#xff0c;它可以增加用户的参与感和趣味性。今天&#xff0c;我将分享一个简单的抽奖转盘实现&#xff0c;它使用了HTML、CSS和JavaScript&#xff0c;非常适合初学者学习和理解前端开发的基本概念。 一、项目背…

中间件框架漏洞攻略

中间件&#xff08;英语&#xff1a;Middleware&#xff09;是提供系统软件和应⽤软件之间连接的软件&#xff0c;以便于软件各部件之间的沟通。 中间件处在操作系统和更⾼⼀级应⽤程序之间。他充当的功能是&#xff1a;将应⽤程序运⾏环境与操作系统隔离&#xff0c;从⽽实…

Unity Animation的其中一种运用方式

Animation是Unity的旧的动画系统&#xff0c;先说目的&#xff0c;其使用是为了在UI中播放动效&#xff0c;并且在动效播放结束后接自定义事件而设计的 设计的关键点在于&#xff0c;这个脚本不是通过Animation直接播放动画片段&#xff0c;而是通过修改AnimationState的nor…

从零构建大语言模型全栈开发指南:第一部分:数学与理论基础-1.2.2Transformer的突破性设计:自注意力机制与位置编码

👉 点击关注不迷路 👉 点击关注不迷路 👉 点击关注不迷路 文章大纲 1.2.2 Transformer的突破性设计:自注意力机制与位置编码1. 自注意力机制:全局依赖建模的数学革命1.1 自注意力机制的核心原理1.2 多头注意力:多视角特征融合2. `位置编码:序列顺序的数学表达`2.1 绝…

《Python全栈开发》第12课:RESTful API设计 - 构建现代化接口

🌟 课程目标 理解REST设计原则掌握Flask-RESTful开发实现JWT认证接口构建标准化API文档一、REST是什么?(餐厅点餐系统比喻) 1.1 REST核心原则 #mermaid-svg-0rLbveAhUdJCLKTy {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;…

【机器学习】--二分类

开始迷信&#xff1a; """* _oo0oo_* o8888888o* 88" . "88* (| -_- |)* 0\ /0* ___/---\___* …

回归任务训练--MNIST全连接神经网络(Mnist_NN)

import torch import numpy as np import logging from torch.utils.data import TensorDataset, DataLoader from torch.utils.data import DataLoader# 配置日志 logging.basicConfig(levellogging.INFO, format%(asctime)s - %(levelname)s - %(message)s)# 定义 loss_batch…