环境:Struts2.3.20 + Internet Exploer 11

程式:连结到专案内档案的超连结
例如 <a href="file/template.xls">范本</a> 连结到 src/main/webapp/file 下的 template.xls

问题:用IE点选档案「连结>开启 (Excel/Word档)」时,error log会列印出大量错误讯息
(可以正常下载并开启档案,使用者侧感受不到错误,但背后的log会记录错误)
(选「储存」或「另存新档」选项都没问题,只有「开启」的选项会出现错误)
(Firefox和Chrome不会发生这个问题,只有IE会)

错误讯息:
 Could not find action or result: /project/file/
 There is no Action mapped for action name file/. - [unknown location]
    at com.opensymphony.xwork2.DefaultActionProxy.prepare(DefaultActionProxy.java:185)
    at org.apache.struts2.impl.StrutsActionProxy.prepare(StrutsActionProxy.java:64)
    (以下省略)

 

看起来就是他把超连结当成struts2的action去解读了,所以找不到mapping
但很神奇的就是要在IE+开启的情况下才会发生,而且他会执行很多次 (出现好几个同样的长串错误讯息)

师傅说大概是IE的bug ... IE你可不可以问题不要那么多!!!
理论上是个换浏览器就能解决的问题,但好无奈实际上大部分User都还是用IE 
他们根本不知道也不想知道"浏览器"是虾米碗糕,无论怎样宣导都不想换掉习惯的工具

解决方法:用downloadAction取代档案的直接连结
一个既然你一定得把它当action那就做个action给你辨识吧的概念

jsp 里改成连结到action,档名当参数传进去
<s:a action="download_downloadSystemFile"><s:param name="fileName">template.xls</s:param>范本</s:a>

DownloadAction.java 写个对应的function

//import省略
public class DownloadAction extends ActionSupport {

    private InputStream inputStream;
    private String fileName;

    public String downloadSystemFile(){
        try{
            fileName=fileName;
            inputStream=this.getClass().getResourceAsStream("../../../../../file/"+fileName);
        }catch(Exception e){
            log.error("error",e);
        }
        return "file";
    }

   //inputStream和fileName的getter/setter省略
}

说明一下,那个 "../../../../../file/" 是相对路径,假设package是aaa.bbb.ccc
class档位于 project\target\classes\aaa\bbb\ccc
file档位于 project\src\main\webapp\file,相对路径就会变成这样

然后return 的 "file" 对应,要去 struts.xml 加一个result type,重点是要设定成stream result
<result name="file" type="stream">
 <param name="contentDisposition">attachment;filename="${fileName}"</param>
</result>

如果确定是某种档案可以再加 param
例如指定用Excel开启 <param name="contentType">application/vnd.ms-excel</param>

这样改使用者不会感受到有变化,而背后log不会再出现那个错误讯息 (虽然感觉工程有点大)


2016-06-20更新

虽然上面那个问题解决了,可是发现用IE6/8下载会出现另一个错误… …
观察使用者的错误log发现一直以来常出现的这个错误只有在使用者用 IE6/8下载系统档案的时候会出现

com.opensymphony.xwork2.util.logging.commons.CommonsLogger.error(CommonsLogger.java:42) Exception occurred during processing request: ServletException including path 'layout.jsp'.
org.apache.tiles.impl.CannotRenderException: ServletException including path '/layout.jsp'.
    at org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:692)
    at org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:644)
(中略)
Caused by: org.apache.tiles.util.TilesIOException: ServletException including path '/layout.jsp'.
    at org.apache.tiles.servlet.context.ServletUtil.wrapServletException(ServletUtil.java:241)
    at org.apache.tiles.servlet.context.ServletTilesRequestContext.include(ServletTilesRequestContext.java:262)

(中略)
Caused by: java.lang.IllegalStateException: getOutputStream() has already been called for this response
    at org.apache.catalina.connector.Response.getWriter(Response.java:564)
    at org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:212)

其中那个 'layout.jsp' 是tiles的layout档
自己电脑没有IE6/8没办法测试,只知道IE11和chrome/FF一切正常
也不清楚使用者端有没有下载成功、或有没有看见什么错误,目前无解

相关文章