标签: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<BsOssUpload> bsOssUploadList = recurrenceService.getFileList(id); 10 for (Iterator<BsOssUpload> 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; } }
标签:class pack 标识 io操作 entry flush jsse ring gets
原文地址:https://www.cnblogs.com/sunzy-blog/p/13447835.html