根据返回的多层Json来进行创建文件,达到根据阶层创建,然后压缩成压缩包进行下载
临时接到一个需求说让根据按照下面的这个图片的结构来打包下载指定位置下的文件到指定位置!

实现思路:
1.把已经实现的树形结构的代码进行调用,拿到他的数据进行创建对应的文件夹
2.因为结构下方的文件没有特别直观的数据库中的关联关系,所以还需要对于管理关系进行梳理
3.创建好阶级文件,然后调用网上找的工具类打包成为rar压缩包,然后把路劲交给前端进行调用下载
调用数据,然后传递给创建文件方法进行实现:
/**
* 打包佐证成果文件,压缩成为压缩包!
*
* @param projectId
* @param departId
*/
@ApiOperation(value = "打包佐证成果文件", notes = "佐证与成果-打包佐证成果文件")
@RequestMapping("/exportZip")
public Result<?> exportZip(@RequestParam(name = "projectId", required = false) String projectId, @RequestParam(name = "departId", required = true) String departId) {
// 获取树形结构
Result<List<SelectTreeMoneyModel>> loadAllTreeRoot = this.loadAllTreeRoot(projectId, departId);
// 下载压缩文件,将获取到的树形结构,传递到实现类进行解析跟实现
String downloadZipFile = downloadZipFile(loadAllTreeRoot, "佐证跟成果", "/");
return Result.ok(downloadZipFile);
}
递归的创建子集文件夹,然后调用工具类进行压缩成为压缩包文件,注:删除文件必须捋清楚然后进行使用,其实不删除也只会在指定的位置生成一份,所以我这边没有进行使用!
/**
* 递归的创建子集文件夹
*
* @param data
* @param rootFile
*/
private void mkdirsChild(List<SelectTreeMoneyModel> data, File rootFile) {
for (SelectTreeMoneyModel datum : data) {
// 创建一个file实例对象,指向文件路径(存放照片的根目录)
File childs = new File(rootFile, datum.getTitle());
if (!childs.exists()) {
childs.mkdirs();
}
// 判断如果下面还有子节点,如果有则调用自身
if (!datum.isLeaf()) {
mkdirsChild(datum.getChildren(), childs);
}
// 如果下面没有子节点,则进行判断下面是否有附件,如果有附件则进行下载到指定的文件夹内。
List<ProjectResult> results = iProjectResultService.list(new LambdaQueryWrapper<ProjectResult>().eq(ProjectResult::getTypeId, datum.getKey()));
if (ObjectUtils.isNotEmpty(results)) {
for (ProjectResult result : results) {
List<ProjectTaskContent> projectTaskContents = projectTaskContentService.list(new LambdaQueryWrapper<ProjectTaskContent>().eq(ProjectTaskContent::getResultId, result.getId()));
for (ProjectTaskContent projectTaskContent : projectTaskContents) {
// 判断附件表不是空的,则进行下载文件到对应的文件夹下
if (ObjectUtils.isNotEmpty(projectTaskContents)) {
RestTemplate restTemplate = new RestTemplate();
// 配置文件进行读取
try {
ResponseEntity responseEntity = restTemplate.exchange(url + projectTaskContent.getFilePath(), HttpMethod.GET, null, byte[].class);
byte[] fileContent = (byte[]) responseEntity.getBody();
// 利用 File 对象,然后使用 getName() 方法获取文件名(不包括路径)。
File file = new File(projectTaskContent.getName());
String filenameWithoutPrefix = file.getName();
Files.write(Paths.get(childs + "\\" + filenameWithoutPrefix), fileContent);
} catch (IOException e) {
e.getMessage();
throw new RuntimeException(e);
}
}
}
}
}
}
}
/**
* 下载压缩文件
*
* @param data 数据集合【key:分类名称,value:照片信息集合(key:照片名称,value:照片下载路径)】
* @param fileStr 照片存放的文件路径
* @param zipFileStr 压缩文件的路径(加后缀名)
*/
public String downloadZipFile(Result<List<SelectTreeMoneyModel>> data, String fileStr, String zipFileStr) {
File rootFile = null;
String folderPath = null;
try {
// 遍历传递进来的数据,然后根据传入的数据进行创建文件夹
for (SelectTreeMoneyModel selectTreeMoneyModel : data.getResult()) {
// 创建一个file实例对象,指向文件路径(存放照片的根目录)
zipFileStr = folderUri + selectTreeMoneyModel.getTitle();
folderPath = selectTreeMoneyModel.getTitle();
rootFile = new File(zipFileUri + selectTreeMoneyModel.getTitle());
if (!rootFile.exists()) {
// 创建新文件夹,可以多层(mkdir()创建新文件夹,只能创建一层)
rootFile.mkdirs();
}
// 根据判断递归的创建文件夹,如果是false则有子集
if (!selectTreeMoneyModel.isLeaf()) {
mkdirsChild(selectTreeMoneyModel.getChildren(), rootFile);
}
}
// 创建文件输出流(zip流对象)【实际创建了zip文件,0kb】
FileOutputStream fos1 = new FileOutputStream(new File(zipFileStr + ".zip"));
// 压缩法
toZip1(rootFile, fos1, true);
//TODO 删除文件和压缩文件,要保证每次压缩只保存一份最新的存在。 因为是删除文件,所以要慎用
//delFolder(folderUri + folderPath);
//delFolder(zipFileStr);
} catch (IOException e) {
e.printStackTrace();
}
// 拼接返回的压缩包地址
String urlResult = url + folderPath + ".zip";
return urlResult;
}
/**
* 删除文件夹
*
* @param folderPath 文件夹完整绝对路径
*/
public static void delFolder(String folderPath) {
try {
// 删除目录下所有内容
delAllFile(folderPath);
File myFilePath = new File(folderPath);
//删除空文件夹
myFilePath.delete();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 删除指定文件夹下所有文件
*
* @param path 文件夹完整绝对路径
*/
public static boolean delAllFile(String path) {
boolean bea = false;
File file = new File(path);
if (!file.exists()) {
return bea;
}
if (!file.isDirectory()) {
return bea;
}
//
String[] tempList = file.list();
File temp;
if (tempList != null) {
for (String var : tempList) {
// separator 代替文件或文件夹路径的斜线或反斜线,防止跨平台出现错误
if (path.endsWith(File.separator)) {
temp = new File(path + var);
} else {
temp = new File(path + File.separator + var);
}
if (temp.isFile()) {
temp.delete();
}
if (temp.isDirectory()) {
//先删除文件夹里面的文件
delAllFile(path + "/" + var);
//再删除空文件夹
delFolder(path + "/" + var);
bea = true;
}
}
}
return bea;
}
/**
* 压缩的递归方法
*
* @param sourceFile 源文件
* @param zos zip输出流
* @param fileName 源文件的名称
* @param keepDirStructure 是否保留原来的目录结构,true:保留目录结构;
* false:所有文件跑到压缩包根目录下(注意:不保留目录结构可能会出现同名文件,会压缩失败)
*/
private void compress(File sourceFile, ZipOutputStream zos, String fileName, boolean keepDirStructure) throws IOException {
byte[] buf = new byte[2 * 1024];
// 判断是否是一个文件
if (sourceFile.isFile()) {
// 向zip输出流中添加一个zip实体,构造器中name为zip实体的文件的名字
zos.putNextEntry(new ZipEntry(fileName));
// 创建文件(即某张图片)的输入流
try (FileInputStream in = new FileInputStream(sourceFile)) {
int len;
// read方法:每调用一次就从FileInputStream流中读取一个字节,并返回下一个数据字节,若已到达末尾,就返回-1。
while ((len = in.read(buf, 0, buf.length)) != -1) {
zos.write(buf, 0, len);
}
// 实际写入到了zip输出流的zip实体中,还没写到文件中【zip文件时0kb,不能打开,因为流没有关闭】
zos.closeEntry();
} catch (IOException e) {
throw new IOException(e);
}
} else {
// 源文件时目录
// 获取该目录下所有文件和目录的绝对路径
File[] listFiles = sourceFile.listFiles();
// 空目录
if (listFiles == null || listFiles.length == 0) {
// 需要保留原来的文件结构时,需要对空文件夹进行处理
if (keepDirStructure) {
// 空文件夹的处理
zos.putNextEntry(new ZipEntry(fileName + "/"));
// 没有文件,不需要文件的copy
zos.closeEntry();
}
} else {
// 非空目录
for (File file : listFiles) {
if (keepDirStructure) {
// 注意:getName()仅得到最后一层的名字,不是路径,所以要加“/”,不然所有文件都跑到压缩包根目录下了
compress(file, zos, fileName + "/" + file.getName(), true);
} else {
compress(file, zos, file.getName(), false);
}
}
}
}
}
/**
* 压缩成ZIP 方法1:保留多级目录结构
*
* @param sourceFile 照片存放路径
* @param out 压缩文件输出流
* @param keepDirStructure 是否保留原来的目录结构,true:保留目录结构;
* false:所有文件跑到压缩包根目录下(注意:不保留目录结构可能会出现同名文件,会压缩失败)
*/
public void toZip1(File sourceFile, OutputStream out, boolean keepDirStructure) throws IOException {
long start = System.currentTimeMillis();
// 创建压缩输出流,java7的新语法:Try-with-resources,会确保异常抛出或者try代码块结束时close流【该流必须实现AutoCloseable类】(若是java7之前的版本,则不会生效)
try (ZipOutputStream zos = new ZipOutputStream(out)) {
// 压缩
compress(sourceFile, zos, sourceFile.getName(), keepDirStructure);
long end = System.currentTimeMillis();
System.out.println("压缩完成,耗时:" + (end - start) + " ms");
} catch (IOException e) {
throw new IOException(e);
}
}
最后的实现结果


总结: 主要还是要理清楚你的层级关系,
1.然后在递归的时候一定要递归到最底层,然后根据最底层的数据查找跟附件表有关系的ID进行查找,然后将有关系的文件下载到指定的文件夹下,
2.然后打包成为压缩包这种实现直接可以进行百度查找到适合自己的工具类,如果不是直接适用,可以进行修改工具类的方法进行适配。
根据返回的多层Json来进行创建文件,达到根据阶层创建,然后压缩成压缩包进行下载的更多相关文章
- java使用io创建文件与删除文件的工具类
java中对于文件的操作,是再常见不过了.以下代码是自己代码中所用到的工具类,仅供参考. import java.io.File; import java.io.IOException; /** * ...
- JAVA之旅(二十八)——File概述,创建,删除,判断文件存在,创建文件夹,判断是否为文件/文件夹,获取信息,文件列表,文件过滤
JAVA之旅(二十八)--File概述,创建,删除,判断文件存在,创建文件夹,判断是否为文件/文件夹,获取信息,文件列表,文件过滤 我们可以继续了,今天说下File 一.File概述 文件的操作是非常 ...
- JAVA 创建文件和文件夹,删除文件和文件夹的实用工具
package com.file; import java.io.File; import java.io.IOException; //创建新文件和目录 public class CCRDFile ...
- JAVA 创建文件和文件夹,删除文件和文件夹的实用工具
package com.file; import java.io.File; import java.io.IOException; //创建新文件和目录 public class CCRDFile ...
- 总结java创建文件夹的4种方法及其优缺点-JAVA IO基础总结第三篇
本文是Java IO总结系列篇的第3篇,前篇的访问地址如下: 总结java中创建并写文件的5种方式-JAVA IO基础总结第一篇 总结java从文件中读取数据的6种方法-JAVA IO基础总结第二篇 ...
- Linux 删除文件夹和创建文件的命令
删除文件夹实例:rm -rf /var/log/httpd/access将会删除/var/log/httpd/access目录以及其下所有文件.文件夹 删除文件使用实例: rm -f /var/log ...
- c# ftp创建文件(非上传文件)
c# ftp创建文件(非上传文件) 一.奇葩的故事: 今天项目中遇到这么个奇葩的问题,ftp文件传输完成后要在ftp目录下另一个文件夹下创建对应的空文件,听说是为了文件的完整性,既然这么说,那么就必 ...
- Ubuntu上使用过的命令,Linux常用命令,mount 硬盘挂载, ls 列表list命令,cp 复制copy命令,mkdir 创建文件夹 ,nano 编辑器,cat 文档合并,chmod 文件权限,ssh win10连接ubuntu服务器的步骤
man 帮助 > man ls # ubuntu的帮助 tar.gz 压缩解压 > tar -zcvf yzn.tar.gz /home/yzn # 压缩 > tar -zxvf y ...
- 返回值是JSON的阿贾克斯方法
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- [原创作品] 对获取多层json值的封装
今天篇头不废话了,交流加群:164858883 在我们接收后端返回的json数据的时候,在数据缺失的时候,如果直接接收会导致致命错误的发生.可能有些同学会说通常都会有,不用判断直接获取也行.之前我也是 ...
随机推荐
- 华企盾DSC发送白名单提示“解密发送失败”(被中转服务器判定为垃圾邮箱)
解决方法:用DebugView监控,发现含有550错误,说明中转服务器被判定为垃圾邮箱,换一个中转邮箱或者设置为无中转发送 还有一种可能:邮箱设置了收到邮箱后自动删除 DebugView中显示上图 ...
- 数字孪生技术与VR技术的结合会为我们带来什么?
数字孪生技术与虚拟现实(VR)技术的结合为我们打开了全新的可能性和机遇.这个强大的联合为各个领域带来了巨大的影响和创新. 首先,数字孪生技术与VR技术的结合可以为设计和规划过程提供更直观.身临其境的体 ...
- 使用C#如何监控选定文件夹中文件的变动情况?
目录 1.前言 2.效果 3.具体实现 页面设计 全部代码 FileSystemWatcher的介绍 FileSystemWatcher的构造函数 FileSystemWatche ...
- Centos7安装高版本BIND9.16.41(DNS服务器)
安装高版本BIND9.16.41或9.18.15 双数版本为稳定版如9.16.9.18 使用手册:https://bind9.readthedocs.io/en/v9_16_19/reference. ...
- 良心国产工具,比Xshell好用还免费!
使用或维护Linux系统的都知道,我们日常对服务器的操作,一般都会借助SSH工具远程登录到服务器之后进行操作.常用的SSH工具有不少,比如:Xshell.Putty.SSH Secure Shell ...
- elastic常用api
elasticsearch运维常用API 查看集群状态 查询集群状态命令: curl -XGET "http://ip:port/_cluster/health?pretty" # ...
- electron入门之通知Notification(二)
electron入门到入土,从渲染线程中创建新窗口.2022-03-21入门版本17.1.2 electron重要概念,只有一个主线程,其他都是渲染进程或者叫子线程,他们不能直接相互操作,可以通过ip ...
- JavaFX打包exe+Wind+Mac+Linux多平台分发等等
JavaFX打包exe+Wind+Mac+Linux多平台分发等等 由于此教程相对复杂,适合对java有一定掌握的同学操作,于是我又写了一篇用idea简单打包exe的教程,文章地址:https://b ...
- CSS3学习笔记-过渡
学习CSS3过渡(Transitions)是为了在元素状态之间创建平滑的动画效果.下面是一些关于CSS3过渡的学习笔记: 过渡基础语法: 使用transition属性来定义过渡效果. 通过指定过渡的属 ...
- 昇腾实战丨DVPP媒体数据处理视频解码问题案例
摘要:本期就分享几个关于DVPP视频解码问题的典型案例,并给出原因分析及解决方法 本文分享自华为云社区<DVPP媒体数据处理视频解码问题案例>,作者:昇腾CANN . DVPP(Digit ...