下载https文件并打包成ZIP

2021-01-14 07:14

阅读:591

标签:class   pack   标识   io操作   entry   flush   jsse   ring   gets   

首先Controller层代码

 1 @RequestMapping(value = "downloadZipFile")
 2     @OptionsLog(optDesc = "打包影印件下载", optType = "返现日志")
 3     public void downloadZipFile(HttpServletResponse response, String id) throws IOException {
 4         String zipName = "myfile.zip";
 5         response.setContentType("APPLICATION/OCTET-STREAM");
 6         response.setHeader("Content-Disposition", "attachment; filename=" + zipName);
 7         ZipOutputStream out = new ZipOutputStream(response.getOutputStream());
 8         try {
 9             List bsOssUploadList = recurrenceService.getFileList(id);
10             for (Iterator it = bsOssUploadList.iterator(); it.hasNext(); ) {
11                 BsOssUpload file = it.next();
12                 ZipUtils.doZip(file.getFileName(), file.getFileUrl(), out);
13                 response.flushBuffer();
14             }
15         } catch (Exception e) {
16             e.printStackTrace();
17         } finally {
18             out.close();
19         }
20     }
ZipEntry是zip下面的文件条目,你可以比作外面系统的File类似。
后面的参数就是在zip目录下的相对位置。
所以这里有一点比较重要的就是当你遍历文件夹的时候你的ZipEntry的参数的改变规律。

写不好的话会使整个文件目录混乱(如果文件层级较低那就不碍事)。
而putNextEntry(ZipEntry z)的意思就是我下面io操作(写入)都是在z这个文件条目下进行的。
zipoutputstream流和其他的output流不一样的地方就是BufferedOutputStream不能嵌套它。
也就是它不能套缓存流用。对于文件夹下包含文件夹需要特殊考虑。判断它是不是文件夹。

文件夹的话要遍历他的子节点文件。用递归思想。已在代码中给出注释。还有文件要注意相对绝对路径。
package com.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.*;
import java.io.DataInputStream;
import java.io.File;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @author 孙正扬
 * @date 2020-08-04 17:21:22
 */
public class ZipUtils {

    private static Logger logger = LoggerFactory.getLogger(ZipUtils.class);

    /**
     * 获取https路径的文件打包成zip文件
     *
     * @param httpUrl
     * @param out
     */
    public static void doZip(String fileName, String httpUrl, ZipOutputStream out) {
        InputStream in = null;
        File file = null;
        try {

            if (httpUrl.startsWith("https://")) {
                /**
                 * 设置忽略ssl证书
                 */
                SSLContext sslcontext = null;
                sslcontext = SSLContext.getInstance("SSL", "SunJSSE");
                sslcontext.init(null, new TrustManager[]{new X509TrustUtiil()}, new java.security.SecureRandom());
                HostnameVerifier ignoreHostnameVerifier = new myHostnameVerifier();
                URL url = new URL(httpUrl);
                HttpsURLConnection.setDefaultHostnameVerifier(ignoreHostnameVerifier);
                HttpsURLConnection.setDefaultSSLSocketFactory(sslcontext.getSocketFactory());
                HttpsURLConnection urlCon = (HttpsURLConnection) url.openConnection();
                urlCon.setConnectTimeout(6000);
                urlCon.setReadTimeout(6000);
                int code = urlCon.getResponseCode();
                if (code != HttpURLConnection.HTTP_OK) {
                    try {
                        throw new Exception("文件读取失败");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                /**
                 * ZipEntry是zip下面的文件条目,你可以比作外面系统的File类似。
                 * 后面的参数就是在zip目录下的相对位置。所以这里有一点比较重要的就是当你遍历文件夹的时候你的ZipEntry的参数的改变规律。
                 * 写不好的话会使整个文件目录混乱(如果文件层级较低那就不碍事)。
                 * 而putNextEntry(ZipEntry z)的意思就是我下面io操作(写入)都是在z这个文件条目下进行的。
                 */
                String[] zips = httpUrl.split("/");
                String[] lastName = httpUrl.split("\\.");
                ZipEntry entry = new ZipEntry(fileName == null ? zips[zips.length - 1] : fileName + "." + lastName[lastName.length - 1]);
                /**
                 * zipoutputstream流和其他的output流不一样的地方就是BufferedOutputStream不能嵌套它。也就是它不能套缓存流用。
                 * 对于文件夹下包含文件夹需要特殊考虑。判断它是不是文件夹。
                 * 文件夹的话要遍历他的子节点文件。用递归思想。已在代码中给出注释。还有文件要注意相对绝对路径。
                 */
                out.putNextEntry(entry);
                byte[] buffer = new byte[2048];
                // 读文件流
                in = new DataInputStream(urlCon.getInputStream());
                int len = 0;
                while ((len = in.read(buffer)) > 0) {
                    out.write(buffer, 0, len);
                    out.flush();
                }
                out.closeEntry();
                in.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                /**out流在最外层关闭,如果循环的话提前关闭会直接报错*/
                if (null != in) {
                    in.close();
                }
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
    }
}

/**
 * [强制]在实现的HostnameVerifier子类中,
 * 需要使用verify函数效验服务器主机名的合法性,否则会导致恶意程序利用中间人攻击绕过主机名效验。
 * 说明:
 * 在握手期间,如果URL的主机名和服务器的标识主机名不匹配,
 * 则验证机制可以回调此接口实现程序来确定是否应该允许此连接,
 * 如果回调内实现不恰当,默认接受所有域名,则有安全风险
 */
class myHostnameVerifier implements HostnameVerifier {
    @Override
    public boolean verify(String s, SSLSession sslSession) {
        return true;
    }
}

 

 
 

下载https文件并打包成ZIP

标签:class   pack   标识   io操作   entry   flush   jsse   ring   gets   

原文地址:https://www.cnblogs.com/sunzy-blog/p/13447835.html


评论


亲,登录后才可以留言!