web上传zip大文件,java服务接收并解压ZIP文件
目录
一、背景
二、知识点
三、代码实现
1、依赖
2、web 代码
3、 java服务端
一、背景
公司产品小伙伴画了原型后,需要上传到服务器上供开发查看;由于文件数量很多,100M左右差不多要传30分钟,这期间在替换文件导致原型无法正常查看,耽误开发小伙伴时间;随后建议他们将文件压缩为zip压缩包,基本上传也就30秒左右;但是产品小伙伴不会linux命令,也担心他们将服务器弄的“一塌糊涂”,所以就想着做个简单的zip文件上传并自动解压的简单功能。
二、知识点
- 大文件上传
SpringBoot 项目上传默认单个文件1M,一次上传请求大小10M,上传的文件超过了这个限制就会报错。
如果上传的文件不是特别大,或者在内网上传,那么就直接修改这个配置即可,web端和服务端开发都会比较简单(本文就是采用这个方式)。但是缺点就是上传时间可能比较长,如果设置了超时,会存在上传超时。
application.yml 配置:
spring:servlet:multipart:# 配置 -1 为无限制max-file-size: 100MBmax-request-size: 100MB
如果上传的文件特别大,并且希望快速上传,可以使用百度的 WebUploader JS 插件对文件进行分片上传,服务端顺序写入到文件中。这个功能可以后续写篇博文。
- zip文件保存
Spring 框架做文件上传,都是封装到 MultipartFile 对象中的。保存到文件最简单的就是使用 MultipartFile.transferTo(file) 方法。
当然也可以自己拿到文件流读取然后写入到zip文件中,注意,一定要用Zip流操作,用普通的流写的zip不可用。
- 解压zip文件
使用 zip4j 工具包,解压超级简单,2行代码就搞定了。
- Jquery ajax 上传文件
不使用 form 表单上传,而是使用 ajax 上传,就不用做两个页面了。ajax 上传文件就需要使用内置的 FormData 对象来作为数据体对象,完成文件的上传。
三、代码实现
1、依赖
<!-- spring boot 父包 -->
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.2.RELEASE</version><relativePath/>
</parent><!-- 项目依赖 --><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>net.lingala.zip4j</groupId><artifactId>zip4j</artifactId><version>2.9.1</version></dependency></dependencies>
application.yml 配置见上方。
2、web 代码
index.html 代码,省略不重要的标签,节约篇幅
<!-- Bootstrap 和 treeview CSS 文件 -->
<link rel="stylesheet" href="libs/bootstrap.min.css">
<link rel="stylesheet" href="libs/bootstrap-treeview.min.css">
<!-- body -->
<div class="container"><h2>原型部署工具</h2><div>说明:1、选择要部署的路径;2、选择部署的zip文件;3、点击部署</div><br><br><div class="row"><div class="col-md-8"><div><div class="form-group"><label for="tree">部署路径</label><div id="tree"></div></div><div class="form-group"><label for="file">zip文件</label><input type="file" id="file" accept=".zip" required><p class="help-block">仅支持zip文件,且不超过100MB</p></div><button type="button" class="btn btn-default" id="bt" disabled="disabled" onclick="deploy()">提交</button></div></div></div>
</div>
<!-- js 依赖 -->
<script src="libs/jquery-3.6.0.min.js"></script>
<script src="libs/bootstrap.min.js"></script>
<script src="libs/bootstrap-treeview.min.js"></script>
<script src="index.js"></script>
index.js 简略版
var $tree = $('#tree');
var $file = $('#file');
// 用于校验的字段
var deployPath;
var filename;
// 加载可部署的目录树
$.ajax({url: "deploy/path/tree",type: "get",success: function (data) {$tree.treeview({data: [data],onNodeSelected: function (event, data) { // 选择树节点事件deployPath = data.path;$("button").removeAttr("disabled");}});},error: function (err) {console.error(err);alert("加载部署路径 tree 错误");}
});$file.on("change", function () { // 文件选择事件filename = $file.val();
});
// 上传文件
function deploy() {// 校验字段省略// 使用 ajax 上传文件,需要用 FormData 对象var formData = new FormData();formData.append("path", deployPath);formData.append("file", $file[0].files[0]); // 要上传的文件$.ajax({url: "deploy/upload",type: "post",data: formData,contentType: false,processData: false,success: function (data) {console.log("部署完成");},error: function (err) {console.error(err);}});
}
3、 java服务端代码
Controller 代码(省略部分不重要的代码)
package com.chc.yx.deploy.web;import com.chc.yx.deploy.bean.PathResult;
import com.chc.yx.deploy.bean.UploadFile;
import net.lingala.zip4j.ZipFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Stream;/*** 部署控制器** @author chc* @date 2021/12/31* @since 1.0*/
@RestController
@RequestMapping("/deploy")
public class DeployController implements InitializingBean {private Logger log = LoggerFactory.getLogger(getClass());// 部署基础路径,只能部署在这个目录及其子目录下@Value("${deploy.basePath}")private String basePath;// 解压的编码:解决linux中文乱码@Value("${deploy.charset}")private String charset;/*** 读取指定目录下的所有子目录路径名称*/@GetMapping("/path/tree")public ResponseEntity<PathResult> pathTree() {Path path = Paths.get(basePath);// ...省略代码:递归扫描basePath路径下的子目录,以对应的层级封装到PathResult中,供treeview显示可以部署的路径...return ResponseEntity.ok(pathResult);}/*** 上传文件* @param UploadFile 自定义的参数类*/@PostMapping("/upload")public ResponseEntity upload(UploadFile uploadFile) {// 部署的路径String path = uploadFile.getPath();MultipartFile file = uploadFile.getFile();// zip文件名称String originalFilename = file.getOriginalFilename();log.info("部署信息:path = {}, name = {}", path, originalFilename);Path zipFilePath = Paths.get(path, originalFilename);// ... 省略代码:删除历史同名 zip 文件 ...try {// 使用 MultipartFile.transferTo 保存zip文件file.transferTo(zipFilePath);log.info("保存{}成功", originalFilename);} catch (IOException e) {log.error("保存" + zipFilePath + "错误", e);return ResponseEntity.status(500).body("保存" + zipFilePath + "错误");}// 删除非压缩文件String targetFilename=originalFilename.substring(0,originalFilename.length()-4);Path filePath = Paths.get(path, targetFilename);if (Files.exists(filePath)) {AtomicBoolean result = new AtomicBoolean(true);deleteDirectoryAll(filePath, result);log.info("删除{}下的文件结果:{}", targetFilename, result.get());}// 使用 zip4j 解压:首先指定 zip 文件try (ZipFile zipFile = new ZipFile(zipFilePath.toString())) {// 指定编码集,主要是解决linux系统上中文乱码zipFile.setCharset(Charset.forName(charset));// 指定要解压到的目录下,并解压zipFile.extractAll(filePath.getParent().toString());log.info("解压{}成功", originalFilename);} catch (IOException e) {log.error("解压zip错误", e);return ResponseEntity.status(500).body("解压zip文件错误");}// 删除zip文件try {Files.delete(zipFilePath);} catch (IOException e) {log.info("删除{}成功", originalFilename);}log.info("部署完成");return ResponseEntity.ok("success");}/*** 递归删除目录和下面的文件————java api删除目录的话,目录必须是空的才能删除*/private void deleteDirectoryAll(Path path, final AtomicBoolean result) {try (Stream<Path> stream = Files.list(path)) {stream.forEach(p -> {if (Files.isDirectory(p)) {deleteDirectoryAll(p, result);}try {Files.delete(p);} catch (IOException e) {log.error("删除文件错误", e);result.set(false);}});} catch (IOException e) {log.error("list path error", e);result.set(false);}}}
上面Controller中提供了两个配置参数:
1、deploy.basePath 用于指定可以部署的根目录
2、deploy.charset 用于指定解码的字符集,主要是用于解决 linux 系统上中文文件名的乱码问题的;在linux上如果使用 UTF-8 解码存在中文乱码,则可以使用 CP936 编码。
web上传zip大文件,java服务接收并解压ZIP文件相关推荐
- python解压zip文件_Python中最快解压zip文件的方法
假设现在的上下文(LCTT 译注:context,计算机术语,此处意为业务情景)是这样的:一个 zip 文件被上传到一个Web 服务中,然后 Python 需要解压这个 zip 文件然后分析和处理其中 ...
- linux解压7z文件,Linux 下压缩与解压.zip和.rar及.7z文件
对于Window下的常见压缩文件.zip和.rar,Linux也有相应的方法来解压它们: 1)对于.zip linux下提供了zip和unzip程序,zip是压缩程序,unzip是解压程序.它们的参数 ...
- linux解压z格式文件夹,使用7zip解决解压zip格式文件名乱码, 最简单的解决解压z...
使用7zip解决解压zip格式文件名乱码, 最简单的解决解压z 由于中文文件名与英文文件名编码的差异,很容易造成在Linux系统使用unzip命令解压zip格式的压缩包时造成中文文件名乱码. 最简单的 ...
- php 解压rar文件怎么打开方式,php 解压rar文件
对于zip文件网上的例子很多,rar文件解压php没有直接支持,可以用pecl 然后扔到php的 ext目录下. 打开php.ini. 加一行 extension=php_rar.dll 重启web服 ...
- linux解压zip覆盖目录,linux下压缩与解压(zip、unzip、tar)详解
最近经常在linux上进行打包压缩解压,从网上收集整理并结合自己的常用的,跟大家分享一下下,废话不多说,进入正题. 1.zip 压缩 如果是直接压缩几个文件,那就可以直接使用命令 zip newfil ...
- java csv文件tozip后损坏_java上传并下载以及解压zip文件有时会报文件被损坏错误分析以及解决...
情景描述: 1.将本地数据备份成zip文件: 2.将备份的zip文件通过sftp上传到文件服务器: 3.将文件服务器上的zip文件下载到运行服务器: 4.将下载的zip文件解压到本地(文件大小超过50 ...
- web上传整个文件夹
在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 先说下要求: PC端全平台支持,要求支持Windows,Mac,Linux 支持所 ...
- 【Web技术】959- JavaScript 如何在线解压 ZIP 文件?
相信大家对 ZIP 文件都不会陌生,当你要打开本地的 ZIP 文件时,你就需要先安装支持解压 ZIP 文件的解压软件.但如果预解压的 ZIP 文件在服务器上,我们应该如何处理呢? 最简单的一种方案就是 ...
- Java 压缩与解压zip文件
一.压缩文件大致可以分为三种:ZIP.JAR.GZ. 压缩流 在日常中经常会使用到像WinRAR或WinZIP这样的压缩文件,通过这些软件可以把一个很大的文件进行压缩以方便传输. 在JAVA中,为了减 ...
最新文章
- Eureka 注册中心/服务发现框架
- Spring Cloud Alibaba教程:使用Nacos作为服务注册中心
- Loj #3111. 「SDOI2019」染色
- sql查询成绩最高分_sql查询各科成绩前三名----详述过程,思路清晰不烧脑!
- ECCV 2020 亮点摘要(下)
- scrapy中自定义过滤规则以及start_urls不进过滤器的问题
- 很多人都忽视了账号基建重要性
- linux i o端口编程,linux 操作 I/O 端口
- Ubuntu10.10下ftp的安装配置
- Spring Cloud 2020 年路线图
- 常见计算机蓝屏代码,常见电脑蓝屏代码大全
- oracle 索引是否失效,oracle 索引失效的原因
- 大数据面试题及答案-汇总版
- Qt界面程序的可视化设计
- 3D建模京东商品3D展示怎么做?
- 微信大面积封杀使用wetool微信账户 用了就封号!
- 成吉思汗陵举行戊戌年成吉思汗嗣火祭祀
- php动态创建菜单,php创建无限级树型菜单
- LinuxC—标准IO与文件IO学习笔记
- 第十二章 Spring Cloud Config 统一配置中心详解