目录

一、背景

二、知识点

三、代码实现

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文件相关推荐

  1. python解压zip文件_Python中最快解压zip文件的方法

    假设现在的上下文(LCTT 译注:context,计算机术语,此处意为业务情景)是这样的:一个 zip 文件被上传到一个Web 服务中,然后 Python 需要解压这个 zip 文件然后分析和处理其中 ...

  2. linux解压7z文件,Linux 下压缩与解压.zip和.rar及.7z文件

    对于Window下的常见压缩文件.zip和.rar,Linux也有相应的方法来解压它们: 1)对于.zip linux下提供了zip和unzip程序,zip是压缩程序,unzip是解压程序.它们的参数 ...

  3. linux解压z格式文件夹,使用7zip解决解压zip格式文件名乱码, 最简单的解决解压z...

    使用7zip解决解压zip格式文件名乱码, 最简单的解决解压z 由于中文文件名与英文文件名编码的差异,很容易造成在Linux系统使用unzip命令解压zip格式的压缩包时造成中文文件名乱码. 最简单的 ...

  4. php 解压rar文件怎么打开方式,php 解压rar文件

    对于zip文件网上的例子很多,rar文件解压php没有直接支持,可以用pecl 然后扔到php的 ext目录下. 打开php.ini. 加一行 extension=php_rar.dll 重启web服 ...

  5. linux解压zip覆盖目录,linux下压缩与解压(zip、unzip、tar)详解

    最近经常在linux上进行打包压缩解压,从网上收集整理并结合自己的常用的,跟大家分享一下下,废话不多说,进入正题. 1.zip 压缩 如果是直接压缩几个文件,那就可以直接使用命令 zip newfil ...

  6. java csv文件tozip后损坏_java上传并下载以及解压zip文件有时会报文件被损坏错误分析以及解决...

    情景描述: 1.将本地数据备份成zip文件: 2.将备份的zip文件通过sftp上传到文件服务器: 3.将文件服务器上的zip文件下载到运行服务器: 4.将下载的zip文件解压到本地(文件大小超过50 ...

  7. web上传整个文件夹

    在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 先说下要求: PC端全平台支持,要求支持Windows,Mac,Linux 支持所 ...

  8. 【Web技术】959- JavaScript 如何在线解压 ZIP 文件?

    相信大家对 ZIP 文件都不会陌生,当你要打开本地的 ZIP 文件时,你就需要先安装支持解压 ZIP 文件的解压软件.但如果预解压的 ZIP 文件在服务器上,我们应该如何处理呢? 最简单的一种方案就是 ...

  9. Java 压缩与解压zip文件

    一.压缩文件大致可以分为三种:ZIP.JAR.GZ. 压缩流 在日常中经常会使用到像WinRAR或WinZIP这样的压缩文件,通过这些软件可以把一个很大的文件进行压缩以方便传输. 在JAVA中,为了减 ...

最新文章

  1. Eureka 注册中心/服务发现框架
  2. Spring Cloud Alibaba教程:使用Nacos作为服务注册中心
  3. Loj #3111. 「SDOI2019」染色
  4. sql查询成绩最高分_sql查询各科成绩前三名----详述过程,思路清晰不烧脑!
  5. ECCV 2020 亮点摘要(下)
  6. scrapy中自定义过滤规则以及start_urls不进过滤器的问题
  7. 很多人都忽视了账号基建重要性
  8. linux i o端口编程,linux 操作 I/O 端口
  9. Ubuntu10.10下ftp的安装配置
  10. Spring Cloud 2020 年路线图
  11. 常见计算机蓝屏代码,常见电脑蓝屏代码大全
  12. oracle 索引是否失效,oracle 索引失效的原因
  13. 大数据面试题及答案-汇总版
  14. Qt界面程序的可视化设计
  15. 3D建模京东商品3D展示怎么做?
  16. 微信大面积封杀使用wetool微信账户 用了就封号!
  17. 成吉思汗陵举行戊戌年成吉思汗嗣火祭祀
  18. php动态创建菜单,php创建无限级树型菜单
  19. LinuxC—标准IO与文件IO学习笔记
  20. 第十二章 Spring Cloud Config 统一配置中心详解

热门文章

  1. 项目如何简单的使用pass平台部署服务
  2. python下载英雄联盟皮肤
  3. 【单片机】裁决三人表决器的设计与制作
  4. R语言特征提取与特征选择
  5. mysql数据库,mysql数据库监控介绍
  6. CSS图像填充文字(镂空文字效果 / 文字镂空效果)
  7. 在高温环境下依靠金属还原反应提纯金属铀的方法
  8. ubantu-20.04.3安装OTRS
  9. gzip,deflate,zlib辨析
  10. windows下如何down git上的代码