java.io.IOException:流在 Struts 2.5.26 和 Tiles 3.0.0

问题描述

将应用程序迁移到 Struts 2 和 Tiles 3.0.0 后,其中一个页面抛出以下异常

严重:servlet jsp 的 Servlet.service() 抛出异常 java.io.IOException:流关闭于 org.apache.jasper.runtime.JspWriterImpl.ensureOpen(JspWriterImpl.java:210) 在 org.apache.jasper.runtime.JspWriterImpl.flushBuffer(JspWriterImpl.java:115) 在 org.apache.jasper.runtime.PageContextImpl.release(PageContextImpl.java:194) 在 org.apache.jasper.runtime.JspFactoryImpl.internalReleasePageContext(JspFactoryImpl.java:126) 在 org.apache.jasper.runtime.JspFactoryImpl.releasePageContext(JspFactoryImpl.java:80) 在 org.apache.jsp.pages.common.baseLayout_jsp._jspService(baseLayout_jsp.java:178) 在 org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70) 在 javax.servlet.http.HttpServlet.service(HttpServlet.java:727) 在 org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432) 在 org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390) 在 org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334) 在 javax.servlet.http.HttpServlet.service(HttpServlet.java:727) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) 在 org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) 在 org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:

当我查看 baseLayout_jsp.java 的源代码时,我看到以下行抛出该异常

    finally {
          _jspxFactory.releasePageContext(_jspx_page_context);
        }

但是baseLayout.jsp只有html和tiles代码

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <%@ taglib uri="/WEB-INF/struts-tags.tld" prefix="s"%>
    <%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles" %>
    <s:property value="getText('label.version')"/>
    
    <html>
    <HEAD>
    <Meta http-equiv="X-UA-Compatible" content="IE=EmulateIE8" />
    <%@ page language="java" contentType="text/html; charset=ISO-8859-1"
        pageEncoding="ISO-8859-1"%>
    <Meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
    <Meta name="GENERATOR" content="IBM Software Development Platform">
    
    <TITLE><tiles:getAsstring name="title" ignore="true"/></TITLE>
    
        <link href="<s:url value='/css/styles.css'/>" type=text/css rel=styleSheet>
        <link href="<s:url value='/css/sor_styles.css'/>" type=text/css rel=styleSheet>
        <link href="<s:url value='/css/ucd_styles.css'/>" type=text/css rel=styleSheet>
        
        <script language="JavaScript" src="<s:url value='/js/common/app.js'/>"></script>
        <script language="JavaScript" src="<s:url value='/js/common/validations.js'/>"></script>
    </HEAD>
    
    <BODY>
    <TABLE  border="0" cellpadding="0" cellspacing="0" height="100%" width="100%">
        <TBODY>
            <TR>
                <TD height="66" colspan="2"><tiles:insertAttribute name="header" /><s:debug value="PAGE TESTING"/></TD>
            </TR>
            <TR>
    
                <TD width="100%" height="100%" valign="top">
                    <div id="mainBody">
                        <tiles:insertAttribute name="tabs" />
                        <tiles:insertAttribute name="here" />
                        <tiles:insertAttribute name="error_response" /> 
                        <tiles:insertAttribute name="body" />
                    </div>
                </TD>
            </TR>
        <TR>
        <TD colspan="2"><tiles:insertAttribute name="footer" /></TD>
        </TR>
        </TBODY>
    </TABLE>
    </BODY>
    </html>

知道为什么我会看到这个异常吗?我在那里进行了搜索,但示例显示大多数页面在遇到此异常时都使用了 Stream 编写器,但在我的情况下则不然。

解决方法

总结:

所提供示例中的 page 指令距离 JSP 文件的开头很远,这可能会触发响应的提交,从而导致尝试设置 Content-Type 标头时失败的响应。

将带有 pagecontentType 属性的 pageEncoding 指令放在 JSP 文件的第一行。

<%@ page contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ taglib uri="/WEB-INF/struts-tags.tld" prefix="s"%>
<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles" %>
<s:property value="getText('label.version')"/>

<!-- rest of the page -->
...

参考:

Apache Tomcat 7 根据 JSP Specification 2.2 支持 The mapping between the specifications and the respective Apache Tomcat versions

根据 JSP Specification 2.2 节 JSP.1.10.1 页面指令(重点是我的):

一个翻译单元(JSP 源文件和通过 include 指令包含的任何文件)可以包含多个 page 指令的实例,所有属性都将应用于整个翻译单元(即页面指​​令与位置无关)。 这种位置独立性的一个例外是在确定页面字符编码时使用 pageEncodingcontentType 属性;为此,它们应该出现在页面的开头(参见 JSP.4.1 部分)。

Jakarta Server Pages 3.0 规范中也有相同的声明。