下載https檔案並打包成ZIP
阿新 • • 發佈:2020-08-06
首先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; } }