麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 學院 > 開發設計 > 正文

Web項目將word打包zip并提供下載

2019-11-14 15:40:12
字體:
來源:轉載
供稿:網友

      該博客記錄java Web項目將Word打包zip并提供下載功能的實現和其中遇到的坑,方便后續自己的查看的參照。
      項目架構背景: JQuery + Bootstarp + SPRingMvc

1. 后臺處理的java 方法

      實現思路:首先將所有的word生成到uploadword目錄下面,然后指定被壓縮的文件夾為uploadword,并將生成的zip指定到uploadzip文件夾(在配置目錄路徑的時候記得注意幾種不同的服務器路徑寫法),當時也考慮過在同一個文件夾下面生成word ,然后壓縮為一個 zip,但很可惜壓縮出來的文件,總是莫名奇妙的迭代了很多相同的壓縮包,可能是將生成的壓縮包,也作為了文件不斷循環在壓縮,所以果斷分開文件夾。在將文件循環壓縮入壓縮包中后,刪除原uploadword文件夾中的文件,所以當程序正確執行完后,服務器中的uploadword這個文件夾都是清空的(畢竟這個功能是權限比較大的管理員進行的操作,有且只有一個超級管理員,現在還沒有考慮多用戶同時并發生成壓縮包的情況)

     根據 word 模版生成 word 文書的方法,我已經在前面的博客中總結過,可以看 java動態生成復雜word文件
壓縮方法上代碼:

1 /**  2 * @Description: 生成zip包 3 * @param: web請求對象,web返回對象,web后端返回到前端的map 4 * @return: TODO (返回類型和參數描述) 5 */ 6 public void createZip(HttpServletRequest req,HttpServletResponse res,Map<String, Object> retmap) { 7 try { 8 //從配置文件獲取生成壓縮包的文件夾路徑,生成唯一的壓縮包名稱 9 String zippath = getUploadpath("uploadzip");10 String zipFileName = Functions.now("yyyy-MM-dd-HH-mm-ss") + ".zip";11 String zipFilePath = zippath + zipFileName;12 13 //生成壓縮文件,并寫入壓縮流中14 File zipFile = new File(zipFilePath);15 ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile));16 17 //從配置文件獲取待壓縮的的文件夾路徑,并生成文件夾,準備好讀入流,等待進行讀入文件進行壓縮18 String filepath = getUploadpath("uploadword");19 File file = new File(filepath);20 InputStream input = null;21 22 // 壓縮包中文件zip的名稱為23 zipOut.setComment(file.getName());24 25 //循環讀入uploadword文件夾中文件,寫入壓縮流中,最后刪除對應的文件26 if (file.isDirectory()) {27 File[] files = file.listFiles();28 for (int i = 0; i < files.length; ++i) {29 30 input = new FileInputStream(files[i]);31 zipOut.putNextEntry(new ZipEntry(file.getName()+ File.separator + files[i].getName()));32 33 int temp = 0;34 while ((temp = input.read()) != -1) {35 zipOut.write(temp);36 }37 input.close();38 files[i].delete();39 }40 }41 //關閉壓縮流,并將壓縮文件夾路徑,壓縮文件名稱,當前服務器類型【tomcat,weblogic】返回給前端用于跳轉下載頁面時進行傳參42 zipOut.close();43 retmap.put("zippath", zipFilePath);44 retmap.put("zipFileName", zipFileName);45 retmap.put("serverName", ServerDetector.getServerId().toUpperCase());46 retmap.put("success", true);47 } catch (Exception e) {48 e.printStackTrace();49 }50 }51 52 /** 53 * @Description: 獲取配置文件上傳路徑(為了可維護性高,路徑會配置在配置文件中,然后在代碼中進行讀,這樣會減少后邊維護人員的痛苦)54 */55 public String getUploadpath(String param) {56 Properties prop = new Properties();57 String url = this.getClass().getResource("").getPath().replaceAll("%20", " ");58 String path = url.substring(0, url.indexOf("WEB-INF")) + "WEB-INF/Config.properties";59 try {60 prop.load(new FileInputStream(path));61 } catch (Exception e) {62 e.printStackTrace();63 }64 String content = prop.getProperty(param).trim();65 return content;66 }
View Code

2. Sping MVC框架實現下載遇到的“坑” 

    可能以前做過這功能朋友的會產生疑問,為什么要跳轉到前端的下載頁面去,不直接在后端生成下載流,放入HttpServletResponse對象,返回給前端直接彈出下載框。當時我也是這樣想的,但事實總是很殘酷。
原來實現的代碼是這樣的:

1 /**  2 * @Description: 實現壓縮包下載 3 * @param: TODO (入參描述)壓縮文件夾的路徑,生成的壓縮文件的名稱 4 * @return: TODO (返回類型和參數描述) 5 */ 6 public void downFile(HttpServletResponse response, String zippath, String zipFileName) { 7 try { 8  9 String path = zippath + zipFileName;10 File file = new File(path);11 if (file.exists()) {12 InputStream ins = new FileInputStream(path);13 BufferedInputStream bins = new BufferedInputStream(ins);// 放到緩沖流里面14 15 OutputStream outs = response.getOutputStream();// 獲取文件輸出IO流16 BufferedOutputStream bouts = new BufferedOutputStream(outs);17 18 response.reset();19 response.setContentType("application/x-download");// 設置response內容的類型20 response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(str, "GBK"));// 設置頭部信息21 int bytesRead = 0;22 byte[] buffer = new byte[8192];23 24 while ((bytesRead = bins.read(buffer, 0, 8192)) != -1) {25 bouts.write(buffer, 0, bytesRead);26 }27 bouts.flush();28 ins.close();29 bins.close();30 outs.close();31 bouts.close();32 } else {33 response.sendRedirect("/error.jsp");34 }35 } catch (Exception e) {36 e.printStackTrace();37 }38 }
View Code

    加入后臺這段代碼后,并沒有達到我想要的效果,可能是我對Spring Mvc理解的不夠,還請各位看官賜教。

3. 生成zip包成功,在前端跳轉下載頁面

    既然后端不能直接返回下載流,并彈出下載框,在前端接受返回的下載所需(zippath,zipFileName,serverName)的關鍵參數,跳轉到下載JSP頁面。

相應跳轉(跳轉方式多種多樣,這里采用表單提交到download.jsp頁面):

var theParam = {};theParam.zippath = data.zippath;theParam.zipFileName =data.zipFileName;Param.serverName =data.serverName;var formStr = "<form action='..../download.jsp' method='post' id='form' style='display:none'>";$.each(theParam, function(key, value) {formStr += "<input type='hidden' name='" + key + "' value='" + value + "'/>";});formStr += "</form>";$("body").append(formStr);$("#form").submit();

下載頁面:

<%@page import="java.io.OutputStream"%><%@page import="java.net.URLEncoder"%><%@page import="java.io.FileInputStream"%><%@page import="cn.nxcc.nxwb.utils.ServerDetector"%><%@page language="java" contentType="application/x-msdownload" pageEncoding="UTF-8"%><%try {//關于文件下載時采用文件流輸出的方式處理://加上response.reset(),并且所有的%>后面不要換行,包括最后一個;response.reset();//可以加也可以不加response.setContentType("application/x-download");String filedownload = request.getParameter("zippath");String filedisplay = request.getParameter("zipFileName");response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filedisplay, "UTF-8"));OutputStream outp = response.getOutputStream();FileInputStream in = new FileInputStream(filedownload);byte[] b = new byte[1024];int i = 0;while ((i = in.read(b)) > 0) {outp.write(b, 0, i);}outp.flush();outp.close();in.close();//Tomcat 需要添加這兩局來避免 getOutputStream() 方法,已被調用的異常,weblogic做特殊判斷if(request.getParameter("serverName").equals("TOMCAT")){out.clear();out = pageContext.pushBody();}} catch (Exception e) {e.printStackTrace();}%>
View Code

4. 流在不同web容器的妥善處理

    剛開始程序在tomcat 上跑時,總出現報錯:
org.apache.jasper.JasperException: java.lang.IllegalStateException: getOutputStream() has already been called for this response

    百度一番,發現Body()的作用是保存當前的out對象,并更新PageContext中Page范圍內Out對象。JSP容器在處理完成請求后會調用releasePageConter方法釋放所有的
PageContestObject,并且同時調用getWriter方法。由于getWriter方法與在JSP頁面中使用流相關的getOutputStream方法沖突,解決方法也很簡單,重新生成PageContext中Page范圍內Out對象。
在代碼最后添加 :
out.clear();
out = pageContext.pushBody();

    好了,自己本地測試不會報錯了,將項目打包到weblogic,出現報錯:
Servlet failed with Exception java.lang.IllegalStateException: Response already committed at weblogic.servlet.internal.ServletResponseImpl.objectIfCommitted(ServletResponseImpl.java:1602) ......
    雖然不影響功能的使用,還是看著不爽,百度一番,發現是自己添加的上兩句的的原因(tomcat 和 weblogic 容器的差異性,應該是weblogic并不會調用releasePageConter方法釋放所有的PageContestObject)

    這就是下載頁面出現這幾行代碼的原因:

//Tomcat 需要添加這兩局來避免 getOutputStream() 方法,已被調用的異常,weblogic做特殊判斷if(request.getParameter("serverName").equals("TOMCAT")){out.clear();out = pageContext.pushBody();}

     如果能判斷是在哪個web容器中,然后進行特殊判斷就好了,同樣是百度一番,發現 portal-kernel.jar中的類ServerDetector.java 能完美判斷多達10種以上的容器類型,但我又不想將這個jar 引入到項目中(俺就用一個類,引一個jar,太虧了),然后Jd-Gui反編譯,單獨拉出這個類,修改修改添加到我的項目中。

上代碼(修改完的代碼,不依賴任何類,可以拿來直接用):

 1 /**  2 * @ClassName: ServerDetector  3 * @Description: 判斷 Web 容器類型  4 */  5 public class ServerDetector{  6 private static ServerDetector _instance = new ServerDetector();  7 private String _serverId;  8 private Boolean _geronimo;  9 private Boolean _glassfish; 10 private Boolean _jBoss; 11 private Boolean _jetty; 12 private Boolean _jonas; 13 private Boolean _oc4j; 14 private Boolean _resin; 15 private Boolean _tomcat; 16 private Boolean _webLogic; 17 private Boolean _webSphere; 18  19 public static final String GERONIMO_ID = "geronimo"; 20 public static final String GLASSFISH_ID = "glassfish"; 21 public static final String JBOSS_ID = "jboss"; 22 public static final String JETTY_ID = "jetty"; 23 public static final String JONAS_ID = "jonas"; 24 public static final String OC4J_ID = "oc4j"; 25 public static final String RESIN_ID = "resin"; 26 public static final String TOMCAT_ID = "tomcat"; 27 public static final String WEBLOGIC_ID = "weblogic"; 28 public static final String WEBSPHERE_ID = "websphere"; 29  30 public static String getServerId() { 31 ServerDetector sd = _instance; 32 if (sd._serverId == null) { 33 if (isGeronimo()) { 34 sd._serverId = "geronimo"; 35 } else if (isGlassfish()) { 36 sd._serverId = "glassfish"; 37 } else if (isJBoss()) { 38 sd._serverId = "jboss"; 39 } else if (isJOnAS()) { 40 sd._serverId = "jonas"; 41 } else if (isOC4J()) { 42 sd._serverId = "oc4j"; 43 } else if (isResin()) { 44 sd._serverId = "resin"; 45 } else if (isWebLogic()) { 46 sd._serverId = "weblogic"; 47 } else if (isWebSphere()) { 48 sd._serverId = "websphere"; 49 } 50 if (isJetty()) { 51 if (sd._serverId == null) { 52 sd._serverId = "jetty"; 53 } else { 54 sd._serverId += "-jetty"; 55 } 56 } else if (isTomcat()) { 57 if (sd._serverId == null) { 58 sd._serverId = "tomcat"; 59 } else { 60 sd._serverId += "-tomcat"; 61 } 62 } 63 if (sd._serverId == null) { 64 throw new RuntimeException("Server is not supported"); 65 } 66 } 67 return sd._serverId; 68 } 69  70 public static boolean isGeronimo() { 71 ServerDetector sd = _instance; 72 if (sd._geronimo == null) { 73 sd._geronimo = _detect("/org/apache/geronimo/system/main/Daemon.class"); 74 } 75 return sd._geronimo.booleanValue(); 76 } 77  78 public static boolean isGlassfish() { 79 ServerDetector sd = _instance; 80 if (sd._glassfish == null) { 81 String value = System.getProperty("com.sun.aas.instanceRoot"); 82 if (value != null) { 83 sd._glassfish = Boolean.TRUE; 84 } else { 85 sd._glassfish = Boolean.FALSE; 86 } 87 } 88 return sd._glassfish.booleanValue(); 89 } 90  91 public static boolean isJBoss() { 92 ServerDetector sd = _instance; 93 if (sd._jBoss == null) { 94 sd._jBoss = _detect("/org/jboss/Main.class"); 95 } 96 return sd._jBoss.booleanValue(); 97 } 98  99 public static boolean isJetty() {100 ServerDetector sd = _instance;101 if (sd._jetty == null) {102 sd._jetty = _detect("/org/mortbay/jetty/Server.class");103 }104 return sd._jetty.booleanValue();105 }106 107 public static boolean isJOnAS() {108 ServerDetector sd = _instance;109 if (sd._jonas == null) {110 sd._jonas = _detect("/org/objectweb/jonas/server/Server.class");111 }112 return sd._jonas.booleanValue();113 }114 115 public static boolean isOC4J() {116 ServerDetector sd = _instance;117 if (sd._oc4j == null) {118 sd._oc4j = _detect("Oracle.oc4j.util.ClassUtils");119 }120 return sd._oc4j.booleanValue();121 }122 123 public static boolean isResin() {124 ServerDetector sd = _instance;125 if (sd._resin == null) {126 sd._resin = _detect("/com/caucho/server/resin/Resin.class");127 }128 return sd._resin.booleanValue();129 }130 131 public static boolean isSupportsComet() {132 return false;133 }134 135 public static boolean isTomcat() {136 ServerDetector sd = _instance;137 if (sd._tomcat == null) {138 sd._tomcat = _detect("/org/apache/catalina/startup/Bootstrap.class");139 }140 if (sd._tomcat == null) {141 sd._tomcat = _detect("/org/apache/catalina/startup/Embedded.class");142 }143 return sd._tomcat.booleanValue();144 }145 146 public static boolean isWebLogic() {147 ServerDetector sd = _instance;148 if (sd._webLogic == null) {149 sd._webLogic = _detect("/weblogic/Server.class");150 }151 return sd._webLogic.booleanValue();152 }153 154 public static boolean isWebSphere() {155 ServerDetector sd = _instance;156 if (sd._webSphere == null) {157 sd._webSphere = _detect("/com/ibm/websphere/product/VersionInfo.class");158 }159 return sd._webSphere.booleanValue();160 }161 162 private static Boolean _detect(String className) {163 try {164 ClassLoader.getSystemClassLoader().loadClass(className);165 return Boolean.TRUE;166 } catch (ClassNotFoundException cnfe) {167 ServerDetector sd = _instance;168 169 Class<?> c = sd.getClass();170 if (c.getResource(className) != null) {171 return Boolean.TRUE;172 }173 }174 return Boolean.FALSE;175 }176 }
View Code

    OK ,到此完美解決了 Spring MVC 中zip包下載、避開后端直接寫入前端下載流、妥善解決各web容器的差異性。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 91精品国产乱码久久久久久久久 | 日本免费a∨ | 国内免费视频成人精品 | 国产精品久久久久久久久久三级 | 黄色电影免费网址 | 亚洲最黄视频 | 国产精品一区2区3区 | 久久影院午夜 | 九九热在线精品视频 | 午夜视频在线观看免费视频 | 蜜桃成品人免费视频 | 精品国产乱码一区二区三区四区 | 天天夜干 | 日本在线视频免费 | 日日摸夜夜骑 | 一级黄色片在线看 | 久久国产精品一区 | 把娇妻调教成暴露狂 | 国产又白又嫩又紧又爽18p | 国产亚洲精品成人a | 久久亚洲网 | 亚洲午夜影院在线观看 | 在线免费黄色网 | 色婷婷a | 久久91亚洲人成电影网站 | 狠狠操夜夜爱 | 精品国产一区二区三区四区阿崩 | 日日噜噜噜夜夜狠狠久久蜜桃 | h久久| 免费国产一级淫片 | 91福利社在线 | 二区三区在线观看 | 成人在线视频精品 | av在线播放地址 | 91专区在线观看 | 蜜桃91丨九色丨蝌蚪91桃色 | 黄色免费不卡视频 | 毛片在线免费观看完整版 | 欧美成人一区二区三区电影 | 国产精品免费久久久久久 | fc2国产成人免费视频 |