Struts2 下載點取消報異常最終解決辦法


在我們做struts2文件下載的時候,經常會遇到這種問題:點“打開/保存”一切正常,但當我們點擊“取消”時,卻報一堆的異常,非常讓人頭疼,錯誤如下(每個人的錯誤估計不太一樣,以我的為例):

2011-5-19 10:30:23 org.apache.catalina.core.ApplicationDispatcher invoke  
嚴重: Servlet.service() for servlet jsp threw exception  
java.lang.IllegalStateException: getOutputStream() has already been called for this response  
    at org.apache.catalina.connector.Response.getWriter(Response.java:611)  
    at org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:198)  
    at javax.servlet.ServletResponseWrapper.getWriter(ServletResponseWrapper.java:112)  
    at javax.servlet.ServletResponseWrapper.getWriter(ServletResponseWrapper.java:112)  
    at org.apache.jasper.runtime.JspWriterImpl.initOut(JspWriterImpl.java:125)  
    at org.apache.jasper.runtime.JspWriterImpl.flushBuffer(JspWriterImpl.java:118)  
    at org.apache.jasper.runtime.PageContextImpl.release(PageContextImpl.java:180)  
    at org.apache.jasper.runtime.JspFactoryImpl.internalReleasePageContext(JspFactoryImpl.java:118)  
    at org.apache.jasper.runtime.JspFactoryImpl.releasePageContext(JspFactoryImpl.java:77)  
    at org.apache.jsp.layout.adminlayout_jsp._jspService(adminlayout_jsp.java:204)  
    at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)  
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)  
    at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:377)  
    at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:313)  
    at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:260)  
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)  
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)  
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)  
    at org.apache.struts2.dispatcher.FilterDispatcher.doFilter(FilterDispatcher.java:389)  
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)  
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)  
    at com.opensymphony.module.sitemesh.filter.PageFilter.doFilter(PageFilter.java:39)  
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)  
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)  
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:646)  
    at org.apache.catalina.core.ApplicationDispatcher.doInclude(ApplicationDispatcher.java:551)  
    at org.apache.catalina.core.ApplicationDispatcher.include(ApplicationDispatcher.java:488)  
    at com.opensymphony.module.sitemesh.filter.PageFilter.writeDecorator(PageFilter.java:173)  
    at com.opensymphony.module.sitemesh.filter.PageFilter.applyDecorator(PageFilter.java:158)  
    at com.opensymphony.module.sitemesh.filter.PageFilter.doFilter(PageFilter.java:62)  
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)  
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)  
    at org.apache.struts2.dispatcher.ActionContextCleanUp.doFilter(ActionContextCleanUp.java:102)  
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)  
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)  
    at org.tuckey.web.filters.urlrewrite.RuleChain.handleRewrite(RuleChain.java:164)  
    at org.tuckey.web.filters.urlrewrite.RuleChain.doRules(RuleChain.java:141)  
    at org.tuckey.web.filters.urlrewrite.UrlRewriter.processRequest(UrlRewriter.java:90)  
    at org.tuckey.web.filters.urlrewrite.UrlRewriteFilter.doFilter(UrlRewriteFilter.java:417)  
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)  
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)  
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)  
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)  
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)  
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)  
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)  
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)  
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:857)  
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)  
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)  
    at java.lang.Thread.run(Thread.java:619)  

異常原因分析:
[stream對應的類是org.apache.struts2.dispatcher.StreamResult,該類的處理過程如下:

  • 配置其中result標簽下的各個參數
  • 從服務器中獲取輸入流,并同時與客戶端建立輸出流(服務器與客戶端鏈接通過Socket進行連接)
  • 當點擊“保存”或“打開”時,開始傳輸數據。如果點擊“取消”,關閉所有的流

這里要注意的是,但是實際發現Socket并沒有斷開!并且流也沒有關閉!這一點非常重要!
所以在JSP容器通過Response獲取輸出流之前,前面的流并沒有關閉,所以會造成該異常的報出。
我在CSDN上搜了一個人的解決方法,他是這么解決的:

<package name="default" extends="json-default" namespace="/">   
  <!-- 定義全局Result -->  
  <global-results>  
     <result name="client-abort-exception">/null.jsp</result>  
  </global-results>  
</package>  
  
<package name="main" extends="default" namespace="/">  
 <action name="download" class="fileAction" method="download">   
    <exception-mapping result="client-abort-exception" exception="org.apache.catalina.connector.ClientAbortException"></exception-mapping>  
    <param name="savePath">/upload/download</param>  
    <!-- 文件下載配置結果類型為stream的結果 -->  
    <result name="download" type="stream">  
      <param name="inputName">targetFile</param>   
      <!-- 指定保存還是直接打開要下載的文件默認為:直接打開,這里配置保存 -->  
      <param name="contentDisposition">attachment;filename="${downloadFileName}"</param>  
      <!-- 指定下載文件的緩存大小 -->  
      <param name="bufferSize">4096</param>  
    </result>  
 </action>  
</package>  

也就是說,如果拋出了ClientAbortException異常,那就跳轉到“null.jsp”這個頁面,這個頁面中什么內容都沒有。雖然這種方法暫時可行,但是當遇到其他異常的時候,也就是非ClientAbortException之后,這個方法就不可行了。我之前也是參照這種方法配置,但昨天我重新啟動應用的時候,點擊“取消”居然還報錯,錯誤就是上面的一堆“java.lang.IllegalStateException”,而且這種方法也是一種逃避的方法,也就是置之不理。這并不可取,解決問題就要解決徹底明了,逃避是沒用的,經過網上大師們的分析測試,最終解決辦法如下:

  • 下載一個插件struts2-sunspoter-stream-1.0.jar(附件中有下載)
  • 將附件解壓獲取struts2-sunspoter-stream-1.0.jar,并復制在/WEB-INF/lib下
  • 在原有的struts.xml的基礎上進行相應的配置,配置如下:
<package name="main" extends="default" namespace="/">  
<!-- 添加如下內容 -->  
<result-types>  
<result-type  name="streamx" class="com.sunspoter.lib.web.struts2.dispatcher.StreamResultX"/>  
</result-types>  
  
  <action name="download" class="fileAction" method="download">  
    <param name="savePath">/upload/download</param>  
    <!-- 文件下載配置結果類型為streamx -->   
    <result name="download" type="streamx">  
      <param name="inputName">targetFile</param>   
      <!-- 指定保存還是直接打開要下載的文件默認為:直接打開,這里配置保存 -->  
      <param name="contentDisposition">attachment;filename="${downloadFileName}"</param>  
      <!-- 指定下載文件的緩存大小 -->  
      <param name="bufferSize">4096</param>  
    </result>  
  </action>  
</package>  

在這種方式下,只需添加一個result-type,將原有的result中type改為“streamx”,其他一律不變,在這種情況下,點擊“取消”的同時也關閉了流,不會再報出該異常。
如果出現log4j的警告,比如:

21:23:44,676  WARN StreamResult:45 - StreamResultX Warn : socket write error  

出現該警告說明正確執行,該警告說明,Socket非正常中斷,但是流確實已經關閉,自此再也不用看到上面出現的討厭異常結果。


PS:struts2-sunspoter-stream-1.0.jar

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,908評論 6 541
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,324評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,018評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,675評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,417評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,783評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,779評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,960評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,522評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,267評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,471評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,009評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,698評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,099評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,386評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,204評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,436評論 2 378

推薦閱讀更多精彩內容