Jsp 在JSF1.2中,从bean定义区域设置会导致getOutputStream中出现IllegalStateException
我试图了解这是如何发生的,以及如何解决它。 我有一个jsf请求bean,带有如下所示的jsp页面:(摘要) 最后,当会话启动时,调用此方法(向客户端发送文件) 我得到一个调用Jsp 在JSF1.2中,从bean定义区域设置会导致getOutputStream中出现IllegalStateException,jsp,jsf,servlets,Jsp,Jsf,Servlets,我试图了解这是如何发生的,以及如何解决它。 我有一个jsf请求bean,带有如下所示的jsp页面:(摘要) 最后,当会话启动时,调用此方法(向客户端发送文件) 我得到一个调用response.getOutputStream() 我不明白的是,如果未定义locale=“#{drcBean.userLocale}”,则不会发生这种情况。(也就是说,我省略了视图的locale标记,问题就消失了) 另一个证据是,我最终收到的文件是提到的JSP页面,我认为这意味着一个新页面以某种方式被发送,并中止了文件
response.getOutputStream()
我不明白的是,如果未定义locale=“#{drcBean.userLocale}”
,则不会发生这种情况。(也就是说,我省略了视图的locale
标记,问题就消失了)
- 另一个证据是,我最终收到的文件是提到的JSP页面,我认为这意味着一个新页面以某种方式被发送,并中止了文件发送。但是这与
语言环境有什么关系呢
- 另外,如果我使用
而不是使用backingbean作为值,它也可以正常工作
<%@ page import="uk.co.farwell.MyBean" %>
<f:view locale="en">
<%
MyBean bean = (DossierBean) pageContext.findAttribute ("bean");
bean.sendFile(response);
%>
</f:view>
我有一个非法的辩论例外。如果这是您遇到的错误,那么请尝试直接使用Servlet
public final class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
byte[] config = "foobar".getBytes();
resp.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
resp.setContentType("application/rtf");
resp.setContentLength(config.length());
resp.getOutputStream().write(config.getBytes());
resp.getOutputStream().flush();
resp.getOutputStream().close();
}
}
或类似的。这比使用jsp下载文件更可靠。这个问题的真正解决方案是在加载jsp页面之前发送文件。 为此,我注册了一个phaselistener,并在JSP页面之前发送了该文件
public class DrcPhaseListener implements PhaseListener {
@Override
public void afterPhase(PhaseEvent pe) {
..... send file here ....
}
问题是,正如我所怀疑的,JSP页面已经开始向响应发送日期,当我试图从bean发送文件时,为时已晚。
上面的修复程序将强制在页面尚未开始加载的阶段发送文件,因此响应中没有写入任何内容。您需要在操作方法的末尾调用,以防止JSF导航到页面(默认为提交表单的页面)
IllegalStateException的消息是什么?org.apache.myfaces.application.jsp.ViewResponseWrapper.getOutputStream(ViewResponseWrapper.java:115)上的java.lang.IllegalStateException听起来像JSF impl bug(但我从未见过)。您正在使用哪个impl和版本?尝试升级。Mojarra 1.2目前为1.2_15,相当成熟。MyFace 1.2.7。我认为问题源于这样一个事实,即在locale中使用EL表达式会导致它向响应写入一些内容,然后您无法再发送文件。通常,如果在调用getOutputStream()之前已经向响应发送了一些内容,那么您会得到一个IllegalArgumentException,但是有一条消息“getOutputStream已经被调用用于此响应”,但是您根本没有收到任何消息?非常感谢您的回答,但我认为我已经找到了解决此问题的真正答案。下面是详细信息。这气味很重。你到底是怎么要求这份文件的?通过提交表单并在bean的操作方法中调用它,对吗?这个黑客就是说,你在一个附加到JSP的getter方法中做这件事,而这个方法又是错误的。@BalusC实际上,bean是请求作用域,每个请求的“状态”都由URL参数决定。文件传输仅由URL参数的值决定,因此无需加载任何JSP页面。甚至“提交”按钮也会使用新的URL参数创建新请求。更有意义?那么,通过提交表单?好的,我发布了一个答案。问题是,在调用sendFile()之前,页面已经开始向响应发送数据,因此调用
responseComplete()
为时已晚,为什么会发生这种情况?这只有在使用某种getter方法hack而不是commandbutton/link操作调用它时才能解释。这几乎可以肯定是我脸上的一只虫子。
<%@ page import="uk.co.farwell.MyBean" %>
<f:view locale="en">
<%
MyBean bean = (DossierBean) pageContext.findAttribute ("bean");
bean.sendFile(response);
%>
</f:view>
public void sendFile(HttpServletResponse response) throws Exception {
byte[] config = "foobar".getBytes();
String clientFileName = "iphone.mobileconfig";
BufferedInputStream input = null;
BufferedOutputStream output = null;
ByteArrayInputStream bais = new ByteArrayInputStream(config);
input = new BufferedInputStream(bais);
response.reset();
response.setContentType("application/x-apple-aspen-config");
response.setHeader("Content-Disposition", "attachment; filename=\"" + clientFileName + "\"");
response.setContentLength((int) config.length);
output = new BufferedOutputStream(response.getOutputStream(), 1024);
byte[] buffer = new byte[1024];
int length;
while ((length = input.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
output.flush();
}
public final class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
byte[] config = "foobar".getBytes();
resp.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
resp.setContentType("application/rtf");
resp.setContentLength(config.length());
resp.getOutputStream().write(config.getBytes());
resp.getOutputStream().flush();
resp.getOutputStream().close();
}
}
public class DrcPhaseListener implements PhaseListener {
@Override
public void afterPhase(PhaseEvent pe) {
..... send file here ....
}
public void download() {
sendFile();
FacesContext.getCurrentInstance().responseComplete();
}