Java 来自servlet输出流的响应出现问题

Java 来自servlet输出流的响应出现问题,java,jsf,servlets,download,Java,Jsf,Servlets,Download,在我基于Java的Web应用程序中,我试图在ZIP文件中写入一些文件,并希望提示用户下载/取消/保存。“下载”对话框打开的时间,如果我单击“取消”,然后如果我尝试访问应用程序中的任何链接,该对话框将再次打开。这是我的代码片段 private void sendResponse(byte[] buf, File tempFile) throws IOException { long length = tempFile.length(); HttpServletResponse re

在我基于Java的Web应用程序中,我试图在ZIP文件中写入一些文件,并希望提示用户下载/取消/保存。“下载”对话框打开的时间,如果我单击“取消”,然后如果我尝试访问应用程序中的任何链接,该对话框将再次打开。这是我的代码片段

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();
}
此外,一旦我单击“保存/打开”,它将按预期工作。我希望问题在于清除响应对象。请帮我提供一些解决方案

编辑 下载选定的方法

      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");
    }       
}
public void downloadSelected()引发IOException{
List=init();
StringBuffer错误=新的StringBuffer(“”);
ZipOutputStream out=null;
File tempFile=null;
字节[]buf=null;
试一试{
if(list!=null&&list.size()>0){
tempFile=TempFileProvider.createTempFile(TEMP_FILE_前缀,TEMP_FILE_后缀_ZIP);
out=new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(tempFile));
buf=writeIntoZip(列表,输出);
sendResponse(buf,tempFile);
}否则{
错误。追加(“未选择要下载的项目”);
this.errorMessage=errors.toString();
}
} 
捕获(IOE异常){
系统输出打印项次(“取消”);
}       
}
写入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;
}
private byte[]writeIntoZip(列表列表,ZipoutStream out)抛出IOException{
字符串downloadUrl=“”;
InputStream bis=null;
Node=null;
字符串nodeName=“”;
字节[]buf=null;
映射内容=新的HashMap();
ContentReader=null;
用于(NodeRef NodeRef:list){
试一试{
节点=新节点(nodeRef);
nodeName=node.getName();
reader=Repository.getServiceRegistry(FacesContext.getCurrentInstance()).getContentService().getReader(nodeRef,ContentModel.PROP\u CONTENT);
bis=新的BufferedInputStream(reader.getContentInputStream());
如果(bis!=null){
contents=setFiles(contents,nodeName);
nodeName=getUniqueFileName(内容,nodeName);
buf=新字节[4*1024];
buf=writeOutputStream(bis).toByteArray();
out.putNextEntry(新ZipEntry(nodeName));
out.write(buf);
}
}捕获(例外e){
e、 printStackTrace();
if(out!=null){
out.close();
}
}
}
if(out!=null){
out.close();
}
返回buf;
}
谢谢,
Jeya

我不确定这个问题的根本原因。根据目前发布的代码,无法解释这种行为。安肯定会帮上更大的忙。但我发现了这个问题的几个潜在原因。也许解决一个或全部问题就能解决具体问题

  • 您已经将JSF的
    FacesContext
    指定为bean的属性。这是不好的,如果它是一个范围比请求范围更广的bean,那么肯定是这样。它应该始终通过
    FacesContext#getCurrentInstance()
    在本地方法范围内获得。它返回一个线程局部变量,不应该在其他请求之间共享。可能您已经将bean放在会话范围中,并且将重用前面请求的悬空
    响应
    对象,该对象的头已经设置好

  • 您没有捕获
    close()
    方法上的
    IOException
    。如果客户端取消下载,则
    servletOutputStream.close()
    将抛出一个
    IOException
    ,指示客户端已中止响应。在您的情况下,
    中的
    将不再被关闭,
    tempFile
    将不再被删除,JSF响应将不再完成。您还应该捕获
    close()
    并记录/忽略异常,以便确保
    最终完成其工作。可能存在
    tempFile
    会对您将来的POST操作产生影响

  • 您使用的是
    而不是
    或普通


  • 非常感谢你的建议,巴卢斯。你帮了我很多次,现在也是。谢谢。我也尝试过你提到的选项。我在finally方法中毫无例外地调试了代码,并确保managebean作用域是request。我已经编辑了全部代码以供参考。请让我知道我犯了什么错误。