(总目录)springboot - 实现zip文件上传并对zip文件解压, 包含上传oss

news2025/1/3 1:30:00

全文目录,一步到位

  • 1.本文概述
    • 1.1 本文简介
  • 2. 功能实现
    • 2.1 统一文件校验
    • 2.2 普通(多)文件上传[服务器]
      • 2.2.1 controller层
      • 2.2.2 service层
      • 2.2.3 业务impl实现类
      • 2.2.4 FileIOUtils工具包代码
    • 2.3 zip文件的解压
    • 2.4 图片文件的压缩
    • 2.5 oss文件后端上传
    • 2.6 oss文件前端上传
    • 2.7 后端工具测试
  • 3. 本文异常总结
    • 3.1 异常总结
      • 3.1.1 文件解压的时候报错解决
      • 3.1.2 读取文件 报 无权限访问
    • 3.2 oss上传异常
  • 4. 文章总结与预告
    • 4.1 本文总结
    • 4.2 下文预告


1.本文概述

1.1 本文简介

本文会包含

  • java 文件校验
  • 文件上传
  • 文件压缩
  • zip文件的解压
  • oss的文件上传
  • oss前端上传

2. 功能实现

文章像齿轮一样, 部分位置需要自己组装满足不同业务需求
需要哪个就加哪个 注意类型和位置即可 注释都是很全的
如果在使用中 遇到问题 欢迎评论区指正

2.1 统一文件校验

===> 传送门: MultipartFile 统一文件校验

2.2 普通(多)文件上传[服务器]

支持单/多文件同时上传 部分service方法 这个都随意 满足springboot标准即可

2.2.1 controller层

    /**
     * 普通文件上传
     * @param
     * @return
     */
    @ApiOperation("==> 普通文件上传 <===")
    @RequestMapping(value = "/fileUpload", method = RequestMethod.POST)
    public ResultResponse fileUpload(MultipartFile[] file, PageVo pageVo) {

        log.info("===> 普通文件上传 <===");

        ResultResponse result = ossAddService.fileUpload(file, pageVo.getSearchName());
        log.info("返回用户信息:{}", result);
        return result;
    }

2.2.2 service层

 ResultResponse fileUpload(MultipartFile[] file, String searchName);

2.2.3 业务impl实现类

 	@SneakyThrows
    @Override
    public ResultResponse fileUpload(MultipartFile[] file, String searchName) {

        //文件上传功能
        String str = FileIOUtils.fileUpload(file, searchName, false);

        return ResultResponse.ok().setData(str);
    }

2.2.4 FileIOUtils工具包代码

注意: 有报错的位置 注释掉即可 , 自己的业务代码

  • throw异常位置 换成 RuntimeException(“我是异常”) 即可
  • ZipUtil.unzip() 解压的方法 根据后缀名 是zip进行解压
    后面有介绍->2.3 不需要可以直接注释
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.IOUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Objects;
import java.util.UUID;

/**
 * 文件上传工具类
 *
 * @author pzy
 * @version 0.1.0
 * @description TODO
 */
@Slf4j
public class FileIOUtils {

    /**
     * 文件上传
     *
     * @param file             上传文件
     * @param uploadPath       上传文件路径
     * @param isRandomFileName 是否是随机的文件名 true:是  false:否
     * @return
     */
    @SneakyThrows
    public static String fileUpload(MultipartFile[] file, String uploadPath, boolean isRandomFileName) {
        //上传目录地址
        log.debug(uploadPath);

        //(最新修改)如果目录不存在,自动创建文件夹(修复)
        if (!FileIOUtils.createFile(1, new File(uploadPath), false)) {
            log.error("-------> 自动创建文件或文件夹失败!!! <--------");
        }

        //之后可以 优化  根据配置文件自动配置 mkdir-
        String suffix = null;
        String fileName = null;

        //  HashMap hashMap = new HashMap();

        FileOutputStream fileOutputStream = null;
        try {
            //遍历文件数组执行上传(多文件上传需要)
            for (MultipartFile multipartFile : file) {
                if (multipartFile != null) {
                    log.debug("开始上传文件.......");
                    //调用上传方法
                    suffix = Objects.requireNonNull(multipartFile.getOriginalFilename()).substring(multipartFile.getOriginalFilename().lastIndexOf(".")); //后缀名

                    //文件名 是随机 就uuid 不是随机就是原名
                    fileName = (isRandomFileName ? UUID.randomUUID() + suffix : multipartFile.getOriginalFilename());

                    fileOutputStream = new FileOutputStream(uploadPath + "/" + fileName);
                    IOUtils.copy(multipartFile.getInputStream(), fileOutputStream);
                    //file[i].transferTo(new File(uploadDir+"/"+fileName));
                    log.debug("上传" + uploadPath + "/" + fileName + "文件成功!");

                    /*不是随机文件上传 并且是 zip 解压*/
                    if (!isRandomFileName && Objects.equals(suffix, ".zip")) {
                        //解压文件夹
                        ZipUtil.unzip(uploadPath + "/" + fileName, uploadPath);
                    }


                }
            }
            log.debug("上传结束!所有文件上传文件至:" + uploadPath);
            System.out.printf("文件名->%s\n", fileName);

            return fileName;
        } catch (Exception e) {
            //打印错误堆栈信息
            e.printStackTrace();
            log.error("上传文件失败,请检查后重试!!!");

            throw new ThirdServiceException(ResponseEnum.T160004);
        } finally {
            if (fileOutputStream != null) {
                fileOutputStream.close();
            }
        }
    }

    /**
     * 判断文件是否存在,不存在就创建
     *
     * @param file
     */
    public static boolean createFile(int type, File file, Boolean flag) {
        if (type == 1) {
            if (!file.exists()) {
                return file.mkdirs();
            }
        }
//其他就是0 文件及目录创建(存在bug)
        if (file.exists()) {
            log.debug("文件及相关路径存在!!!");
        } else {
            log.info("文件不存在 ,创建文件以及文件夹 ...");
            //getParentFile() 获取上级目录(包含文件名时无法直接创建目录的)
            if (!file.getParentFile().exists()) {
                log.info("文件及其路径不存在, 创建路径文件!!!");
                //创建层级目录
                if (!file.getParentFile().mkdirs()) {
                    return false;
                }
            }
            if (flag) {
                try {
                    //上层目录创建文件
                    log.info("文件夹创建开启,在上层目录下创建文件夹");
                    if (file.createNewFile()) {
                        return false;
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return true;
    }

    /**
     * 文件删除回收
     *
     * @param path
     */
    public static boolean fileGCDelete(String path) {
        boolean flag = false;
        File file1 = new File(path);
        if (file1.exists()) {
            flag = file1.delete();
            try {
                do {
                    if (!flag) {
                        System.gc();    //回收资源
                        flag = file1.delete();
                    }
                } while (!flag);
            } catch (Exception e) {
                e.printStackTrace();
            }
            log.debug("路径存在" + flag);
        }
        return flag;
    }
}

2.3 zip文件的解压

文件压缩工具包 使用java.util.zip

import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * 解压文件工具类
 *
 * @author pzy
 * @version 0.1.0
 * @description TODO
 */
@Slf4j
public class ZipUtil {
    /**
     * 解压核心功能
     * @param zipFilePath 文件目标路径
     * @param destDir 文件解压后路径
     * @throws IOException
     */
    public static void unzip(String zipFilePath, String destDir) throws IOException {

        log.info("===>开启文件解压: {}",zipFilePath);
        File dir = new File(destDir);
        if (!dir.exists()) {
            boolean mkdirs = dir.mkdirs();
            if (!mkdirs) {
                log.error("多级文件夹创建失败===>{}",destDir);
            }
        }
        //windows下中文默认gbk 正常使用utf-8
        try (ZipInputStream zipIn = new ZipInputStream(new FileInputStream(zipFilePath), StandardCharsets.UTF_8)) {
            ZipEntry entry = zipIn.getNextEntry();
            while (entry != null) {
                String filePath = destDir + File.separator + entry.getName();
                if (!entry.isDirectory()) {
                    extractFile(zipIn, filePath);
                } else {
                    File dirToCreate = new File(filePath);
                    boolean mkdirs = dirToCreate.mkdirs();
                    if (!mkdirs) {
                        log.error("多级文件夹创建失败===>{}",filePath);
                    }

                }
                zipIn.closeEntry();
                entry = zipIn.getNextEntry();
            }
        }
    }

    /**
     * 提取文件
     * @param zipIn ZipInputStream
     * @param filePath 文件路径
     * @throws IOException
     */
    private static void extractFile(ZipInputStream zipIn, String filePath) throws IOException {
        try (FileOutputStream fos = new FileOutputStream(filePath)) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = zipIn.read(buffer)) != -1) {
                fos.write(buffer, 0, bytesRead);
            }
        }
    }
}

2.4 图片文件的压缩

===> 传送门: Thumbnails之上传图片后压缩处理

2.5 oss文件后端上传

===> 传送门1: oss存储对象 文件(视频)上传, 获取回调中的url, 官网地址

===> 传送门2: 后端oss存储(完整版) 及 解决删除本地文件显示被占用问题

2.6 oss文件前端上传

===> 传送门: oss前端文件上传, 优势及后端如何配合

2.7 后端工具测试

⇒ 传送门: Postman,ApiPost, Idea httpclient tools,ApiFox 替代swagger,零侵入 接口文档生成
在这里插入图片描述

3. 本文异常总结

3.1 异常总结

3.1.1 文件解压的时候报错解决

java.lang.IllegalArgumentException: MALFORMED 解决方法

  • 加charset(utf-8) 不行windows换gbk

3.1.2 读取文件 报 无权限访问

两种方法

  • 增加文件夹权限
  • 看看文件路径 是否正确 找没找到想读取的文件

3.2 oss上传异常

===> 传送门: oss报错修改指南

4. 文章总结与预告

4.1 本文总结

注意文件夹路径对应, 解压文件路径, 包括文件路径斜线问题 \\/
流用完记得关闭 判断是否为空 避免空指针

4.2 下文预告

无预告, 终篇



作者pingzhuyan 感谢观看

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1030965.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

传统企业如何实现数字化转型?

传统企业实现数字化转型是一个复杂且多方面的过程&#xff0c;涉及将数字技术和战略融入业务的各个方面&#xff0c;以推动创新、效率和竞争力。以下是传统企业实现数字化转型可以遵循的步骤和策略&#xff1a; 1.领导层的认可和愿景&#xff1a; 首先要确保最高领导层&#x…

SpringCloud Gateway搭建Gateway 微服务应用实例

&#x1f600;前言 本篇博文是关于SpringCloud Gateway搭建Gateway 微服务应用实例&#xff0c;希望你能够喜欢 &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文章可以帮助到大家&#xff0c;您…

前端JavaScript入门到精通,javascript核心进阶ES6语法、API、js高级等基础知识和实战 —— JS基础(三)

思维导图 一、循环-for 1.1 for 循环-基本使用 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport"…

scryptTS文档搜索功能上线!

在 scryptTS 文档中搜索 随着 scryptTS 文档的内容越来越丰富&#xff0c;从大量资料中快速定位感兴趣的部分变得越来越困难。 现在&#xff0c;你可以使用搜索功能&#xff0c;快速查找想了解的内容。

金蝶云星空与聚水潭对接集成物料查询连通商品上传(新)(物料主数据同步策略)

金蝶云星空与聚水潭对接集成物料查询连通商品上传&#xff08;新&#xff09;(物料主数据同步策略) 数据源系统:金蝶云星空 金蝶K/3Cloud结合当今先进管理理论和数十万家国内客户最佳应用实践&#xff0c;面向事业部制、多地点、多工厂等运营协同与管控型企业及集团公司&#x…

肖sir__项目环境之全流程__005

一、测试流程&#xff08;h模型&#xff09; 1、需求文档&#xff08;产品&#xff09; 需求文档&#xff08;软件需求规格说明书srs&#xff09; &#xff08;1&#xff09;如何分析需求 a、显示需求&#xff08;主流程、功能&#xff0c;业务&#xff09; b、隐性需求&#x…

java Spring Boot2.7实现一个简单的爬虫功能

首先 我们要在 pom.xml 中注入Jsoup 这是一个简单的java爬虫框架 <dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.14.1</version> </dependency>然后这里我们直接用main吧 做简单一点 我…

NSDT孪生场景编辑器系统介绍

一、产品背景 数字孪生的建设流程涉及建模、美术、程序、仿真等多种人才的协同作业&#xff0c;人力要求高&#xff0c;实施成本高&#xff0c;建设周期长。如何让小型团队甚至一个人就可以完成数字孪生的开发&#xff0c;是数字孪生工具链要解决的重要问题。考虑到数字孪生复杂…

Flask框架-2-[单聊]: flask-socketio实现websocket的功能,实现单对单聊天,flask实现单聊功能

一、概述和项目结构 在使用flask-socketio实现单聊时&#xff0c;需要将会话id(sid) 与用户进行绑定&#xff0c;通过emit(事件,消息,tosid) ,就可以把消息单独发送给某个用户了。 flask_websocket |--static |--js |--jquery-3.7.0.min.js |--socket.io_4.3.1.js |--template…

脑电相关临床试验及数据分析01

临床试验设计01–04 作为一个医疗器械公司的开发–>算法–>项目–>产品&#xff0c;还是想在这里记录一下工作。 直接开始吧 临床试验的设计&#xff0c;主要分为20个部分&#xff0c;分别是 封面 一、申办者信息 二、所有临床试验机构和研究者列表 三、临床试验的…

基础算法--位运算

位运算理解&#xff1a; n >> k&#xff1a;代表n右移k位 比如 000011 >> 1 000001 前面会补零&#xff08;所以第几位是从0开始计算&#xff09; n & 1&#xff1a;表示最后一位是否为1 比如&#xff1a;n 3 0011 而 1 0001 则3 & 1 0011 & 000…

本地Docker Registry远程连接,为你带来高效便捷的镜像管理体验!

Linux 本地 Docker Registry本地镜像仓库远程连接 文章目录 Linux 本地 Docker Registry本地镜像仓库远程连接1. 部署Docker Registry2. 本地测试推送镜像3. Linux 安装cpolar4. 配置Docker Registry公网访问地址5. 公网远程推送Docker Registry6. 固定Docker Registry公网地址…

多输入多输出 | MATLAB实现LSSVM最小二乘支持向量机多输入多输出

多输入多输出 | MATLAB实现LSSVM最小二乘支持向量机多输入多输出 目录 多输入多输出 | MATLAB实现LSSVM最小二乘支持向量机多输入多输出预测效果基本介绍程序设计往期精彩参考资料 预测效果 基本介绍 MATLAB实现LSSVM最小二乘支持向量机多输入多输出 1.data为数据集&#xff0c…

Python 判断三位水仙花数

"""判断是否为三位水仙花数知识点&#xff1a;0、水仙花满足条件&#xff1a;(1 ** 3) (5 ** 3) (3 ** 3) 1531、字符串索引&#xff0c;例如&#xff1a;name zhouhua name[0] z2、变量类型转换函数3、双目运算符幂**,例如&#xff1a;3 ** 2 3 * 3 94、…

【Tricks】关于如何防止edge浏览器偷取chrome浏览器的账号

《关于如何防止edge浏览器偷取chrome浏览器的账号》 前段时间edge自动更新了&#xff0c;我并没有太在意界面的问题。但是由于我使用同一个网站平台时&#xff0c;例如b站&#xff0c;甚至是邮箱&#xff0c;edge的账号和chrome的账号会自动同步&#xff0c;这就导致我很难短时…

Linux su sudo命令

1、su命令——切换用户 1.1、切换到root用户(需要密码) su - root 1.2、切换到其他用户&#xff0c;比如jackma&#xff08;无需密码&#xff09; su - jackma 2、sudo命令——给普通用户添加root权限 2.1、用法 切换到root用户&#xff0c;执行visudo命令&#xff0c;会自动…

Leetcode 951. 翻转等价二叉树

文章目录 题目代码&#xff08;9.22 首刷部分看解析&#xff09; 题目 Leetcode 951. 翻转等价二叉树 代码&#xff08;9.22 首刷部分看解析&#xff09; class Solution { public:bool flipEquiv(TreeNode* root1, TreeNode* root2) {if(!root1 && !root2)return tr…

AI也需要透明度?是的,需要

文章目录 什么是AI透明度为什么需要AI透明度AI透明度的弱点如何做好AI透明度推荐阅读 什么是AI透明度 AI透明度指的是人工智能&#xff08;AI&#xff09;系统的工作原理和决策过程能够被理解、解释和追踪的程度。它包括以下几个方面&#xff1a; 可解释性&#xff08;Explai…

安装nvm 切换不同nodejs版本号

1.下载nvm:NVM下载 - NVM中文网 2.卸载node&#xff08;没有安装的可以直接跳过&#xff09; 3.安装 nvm list available 查看可安装的node版本nvm install 12.16.0 安装指定版本node nvm ls 查看已安装的node版本nvm use 16.13.0 切换…

第二证券:个人开证券账户要开户费吗?

随着互联网和移动端东西的遍及&#xff0c;越来越多的人开端涉足股票投资&#xff0c;开立证券账户也成为一个热门话题。但是&#xff0c;许多初学者或许会有疑问&#xff0c;个人开证券账户是否需求支付开户费呢&#xff1f;这个问题的答案并不是那么简略&#xff0c;需求考虑…