简体   繁体   English

servlet输出流响应中出现问题

[英]Problem in response from servlet output stream

In my Java Based Web application, I am trying to write some files in a ZIP file and I want to prompt the user to download/cancel/save. 在基于Java的Web应用程序中,我试图将一些文件写入ZIP文件,并且要提示用户下载/取消/保存。 The time when the download dialog box opens and if I click on cancel, after then if I try to access any links in my application then the dialog box opens again. 下载对话框打开的时间,如果单击“取消”,则此后如果尝试访问应用程序中的任何链接,则对话框将再次打开。 Here's my code snippet. 这是我的代码段。

private void sendResponse(byte[] buf, File tempFile) throws IOException {
    long length = tempFile.length();
    HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();
    String disposition = "attachment; fileName=search_download.zip";
    ServletOutputStream servletOutputStream = null;
    InputStream in = null; 
    try {
        if (buf != null) {
            in = new BufferedInputStream(new FileInputStream(tempFile));
            servletOutputStream = response.getOutputStream();
            response.setContentType("application/zip");
            response.setHeader("Content-Disposition", disposition);
            while ((in != null) && ((length = in.read(buf)) != -1)) {
                servletOutputStream.write(buf, 0, (int) length);
            }
        }
    } finally {
        if (servletOutputStream != null) {
            servletOutputStream.close();
        }
        if (in != null) {
            in.close();
        }
        if (tempFile != null) {
            tempFile.delete();
        }
    }
    context.responseComplete();
}

Also once I click on save/Open, its working as expected. 同样,一旦我单击“保存/打开”,它就会按预期工作。 I hope the problem in clearing the response object. 我希望在清除响应对象时出现问题。 Please help me in providing some solutions. 请帮助我提供一些解决方案。

EDIT downloadSelected Method 编辑下载选择的方法

      public void downloadSelected() throws IOException {

    List<NodeRef> list = init();
    StringBuffer errors = new StringBuffer("");
    ZipOutputStream out = null;

    File tempFile = null;
    byte[] buf = null;
    try {
        if (list != null && list.size() > 0) {
            tempFile = TempFileProvider.createTempFile(TEMP_FILE_PREFIX, TEMP_FILE_SUFFIX_ZIP);
            out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(tempFile)));
            buf = writeIntoZip(list,out);
            sendResponse(buf,tempFile);
        } else {
            errors.append("No Items Selected for Download");
            this.errorMessage = errors.toString();
        }
    } 
    catch(IOException e) {
        System.out.println("Cancelled");
    }       
}

Write into Zip method: 写入Zip方法:

private byte[] writeIntoZip(List<NodeRef> list,ZipOutputStream out) throws IOException {
    String downloadUrl = "";
    InputStream bis = null;
    Node node = null;
    String nodeName = "";
    byte[] buf = null;
    Map<String,Integer> contents = new HashMap<String, Integer>();
    ContentReader reader = null;
    for (NodeRef nodeRef : list) {
        try {
            node = new Node(nodeRef);
            nodeName = node.getName();
            reader = Repository.getServiceRegistry(FacesContext.getCurrentInstance()).getContentService().getReader(nodeRef, ContentModel.PROP_CONTENT);
            bis = new BufferedInputStream(reader.getContentInputStream());
            if (bis != null) {
                contents = setFiles(contents,nodeName);
                nodeName = getUniqueFileName(contents, nodeName);
                buf = new byte[4 * 1024];
                buf = writeOutputStream(bis).toByteArray();
                out.putNextEntry(new ZipEntry(nodeName));
                out.write(buf);
            }
        } catch (Exception e) {
            e.printStackTrace();
            if(out != null) {
                out.close();
            }
        }
    }
    if(out != null) {
        out.close();
    }
    return buf;
}

Thanks, Jeya 谢谢Jeya

I'm admittedly not sure of the root cause of this problem. 我承认我不确定这个问题的根本原因。 This behaviour is not explainable based on the code posted as far. 根据迄今为止发布的代码,无法解释此行为。 An SSCCE would definitely help more. SSCCE肯定会提供更多帮助。 But I spot several potential causes of this problem. 但是我发现了这个问题的几种潜在原因。 Perhaps fixing one or all of them will fix the concrete problem. 也许修复其中一个或全部将解决具体问题。

  1. You've assigned JSF's FacesContext as a property of the bean. 您已将JSF的FacesContext分配为bean的属性。 This is bad and definitely if it's a bean with a broader scope than the request scope. 这是不好的 ,如果它的作用域比请求作用域更广,那肯定是不好的 It should always be obtained inside the local method scope by FacesContext#getCurrentInstance() . 应该始终通过FacesContext#getCurrentInstance()在本地方法范围内获取它。 It's returns namely a thread local variable and should never be shared among other requests. 它的返回值即是线程局部变量,不应在其他请求之间共享。 Perhaps you've put the bean in the session scope and a dangling response object of the previous request with the headers already set will be reused. 也许您已将bean置于会话范围内,并且先前请求的悬挂response对象(已设置标头)将被重用。

  2. You are not catching the IOException on close() methods. 您没有在close()方法上捕获IOException If the client cancels the download, then the servletOutputStream.close() will throw an IOException indicating that the client has aborted the response. 如果客户端取消下载,则servletOutputStream.close()将抛出IOException指示客户端已中止响应。 In your case, the in won't be closed anymore and the tempFile won't be deleted anymore and the JSF response won't be completed anymore. 在您的情况下,将不再关闭in ,并且不再删除tempFile ,并且将不再完成JSF响应。 You should also catch the close() and log/ignore the exception so that you can ensure that the finally finishes its job. 您还应该捕获close()并记录/忽略异常,以确保finally完成工作。 Perhaps the presence of tempFile has consequences for your future POST actions. 也许tempFile的存在会对您将来的POST操作产生影响。

  3. You are using <h:commandLink> instead of <h:outputLink> or <h:link> or plain <a> for page-to-page navigation. 您正在使用<h:commandLink>而不是<h:outputLink><h:link>或普通<a>进行页面间导航。 This uses POST instead of GET which is bad for user experience and SEO. 这使用POST而不是GET,这利于用户体验和SEO。 You should use GET links instead of POST links. 您应该使用GET链接而不是POST链接。 See also When should I use h:outputLink instead of h:commandLink? 另请参见何时应使用h:outputLink代替h:commandLink?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM