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



    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;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2.2.2 service层

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

    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);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152

    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);
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72

    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 感谢观看

  • 相关阅读:
    C++最佳实践之常用关键字
    二、链表(linked-list)
    【升职加薪秘籍】我在服务监控方面的实践(4)-日志监控
    VA01销售订单批导问题解决
    函数是否使用结构体C++引用情况说明
    STM32使用STM32CubeMX生成文件,并实现串口打印功能。
    卷起来了!熬夜学习阿里P8全彩版并发编程图册,涨薪就在眼前
    做室内装修设计需要什么资质,办理装修设计资质办理标准是怎样的
    Jenkins 使用 Description Setter
    引擎入门 | Unity UI简介–第1部分(10)
  • 原文地址:https://blog.csdn.net/pingzhuyan/article/details/133134934