在jsf 1.2中,从bean定义语言环境会导致getOutputStream中出现IllegalStateException

时间:2011-04-04 09:49:57

标签: jsp jsf servlets

我试图了解这是如何发生以及如何解决的。 我有一个带有jsp页面的jsf请求bean,如下所示:(汇总)

<f:view locale="#{drcBean.userLocale}">
</f:view>

支持bean代码:

public Locale getUserLocale() {
    return new Locale("en");
}

最后,当会话启动时,会调用此方法(将文件发送到客户端)

private void sendFile()
{
        byte[] config = ...;
        String clientFileName = "iphone.mobileconfig";

        // Prepare.
        FacesContext facesContext = FacesContext.getCurrentInstance();
        ExternalContext externalContext = facesContext.getExternalContext();
        HttpServletResponse response = (HttpServletResponse) externalContext.getResponse();

        // File file = new File(getFilePath(), getFileName());

        BufferedInputStream input = null;
        BufferedOutputStream output = null;

        try {
            // Open file.
            ByteArrayInputStream bais = new ByteArrayInputStream(config);
            input = new BufferedInputStream(bais);

            // Init servlet response.
            response.reset();
            response.setContentType("application/x-apple-aspen-config");
            response.setHeader("Content-Disposition", "attachment; filename=\"" + clientFileName
                    + "\"");
            response.setContentLength((int) config.length);

            // if (logger.isTraceEnabled()) {
            // logger.trace("Writing XML Script:" + new String(scriptDataByteArray));
            // }


            output = new BufferedOutputStream(response.getOutputStream(), DEFAULT_BUFFER_SIZE);

            // Write file contents to response.
            byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
            int length;
            while ((length = input.read(buffer)) > 0) {
                output.write(buffer, 0, length);
            }

            // Finalize task.
            output.flush();
        } catch

我收到IllegalStateException个异常,呼叫response.getOutputStream() 我没有得到的是,如果未定义locale="#{drcBean.userLocale}",则不会发生这种情况。 (意思是,我省略了视图的locale标签,问题就消失了)

  • 还有一个证据表明,我最终收到的文件是提到的JSP页面,在我看来,这意味着以某种方式发送了新页面并中止了文件发送。但是这与locale有什么关系呢?

  • 此外,如果我使用<f:view locale="en">而不是使用支持bean作为值,它可以正常工作。

3 个答案:

答案 0 :(得分:0)

如果您尝试将文件下载给用户,为什么还要对区域设置感到困扰?

无论如何,我不知道你为什么会得到IllegalArgumentException。当您尝试使用已经写入的OutputStream时,通常会发生这种情况。

如果我使用以下jsp:

<%@ page import="uk.co.farwell.MyBean" %>

<f:view locale="en">
<%
MyBean bean = (DossierBean) pageContext.findAttribute ("bean");

bean.sendFile(response);
%>
</f:view>

在bean中使用以下代码:

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();
}

我得到一个IllegalArgumentException。如果这是你得到的错误,那么直接尝试使用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下载文件更可靠。

答案 1 :(得分:0)

此问题的真正解决方案是在加载JSP页面之前发送文件。 为此,我注册了一个phaselistener并在JSP页面之前发送了该文件。

public class DrcPhaseListener implements PhaseListener {

    @Override
    public void afterPhase(PhaseEvent pe) { 
              ..... send file here ....
        }

问题是,我怀疑,JSP页面已经开始向响应发送日期,当我尝试从bean发送文件时为时已晚。 上面的修复将强制文件在页面尚未开始加载的阶段发送,因此没有任何内容写入响应。

答案 2 :(得分:0)

您需要在操作方法的末尾调用FacesContext#responseComplete()以防止JSF导航到某个页面(默认为提交表单的页面)。

public void download() {
    sendFile();
    FacesContext.getCurrentInstance().responseComplete();
}