Java 当响应包含文件时,将忽略页面导航/呈现响应阶段
JSF/Seam。我有一个页面,它接受用户通过表单提供的一些参数,然后(当用户单击页面上的按钮时),服务器生成一个文件,并在响应中发送该文件,这样用户就会收到另存为对话框的提示 以下是我遇到问题的场景:Java 当响应包含文件时,将忽略页面导航/呈现响应阶段,java,ajax,http,jsf,seam,Java,Ajax,Http,Jsf,Seam,JSF/Seam。我有一个页面,它接受用户通过表单提供的一些参数,然后(当用户单击页面上的按钮时),服务器生成一个文件,并在响应中发送该文件,这样用户就会收到另存为对话框的提示 以下是我遇到问题的场景: 如果用户最初输入无效输入,然后单击按钮,Seam将处理该请求,但会在流程验证阶段停止。然后,我的页面显示验证错误消息 接下来,如果用户随后输入正确的输入并单击按钮,Seam将调用我的操作处理程序,文件将在响应中生成并发送给用户-,但仍然显示验证错误消息 起初,我尝试了一些黑客手段来强制重新命名标
标签,但没有什么令人满意的我现在怀疑根本原因是,当我在响应中放置文件时,Seam没有进入渲染响应阶段。
这是我的按钮:
<h:commandButton value="#{messages.Reports_RunReportPDF}"
action="#{bean.generateReportPdf}"/>
下面是我的动作处理程序:
public String generateReportPdf() throws IOException {
FacesContext facesContext = FacesContext.getCurrentInstance();
HttpServletResponse response = (HttpServletResponse)facesContext.getExternalContext().getResponse();
ServletOutputStream servletOutputStream = response.getOutputStream();
// add this header to make browser prompt user with a save-as dialog
response.addHeader("Content-Disposition",
"attachment;filename=" + reportName + ".pdf");
response.setContentType(exportType.contentType());
try {
HashMap<String, Object> parameters = getReportParameters();
ReportContent content = createReport(parameters);
servletOutputStream.write(content.getContents());
servletOutputStream.flush();
servletOutputStream.close();
} catch (ReportingException e) {
e.printStackTrace();
return "fail";
}
return "success";
}
公共字符串generateReportPdf()引发IOException{
FacesContext FacesContext=FacesContext.getCurrentInstance();
HttpServletResponse=(HttpServletResponse)facesContext.getExternalContext().getResponse();
ServletOutputStream ServletOutputStream=response.getOutputStream();
//添加此标题可使浏览器提示用户显示另存为对话框
response.addHeader(“内容处置”,
“附件;文件名=“+reportName+”.pdf”);
response.setContentType(exportType.contentType());
试一试{
HashMap参数=getReportParameters();
ReportContent=createReport(参数);
write(content.getContents());
servletOutputStream.flush();
servletOutputStream.close();
}捕获(报告异常e){
e、 printStackTrace();
返回“失败”;
}
返回“成功”;
}
如果我注释掉添加文件的代码(只需返回“success”
),页面将遵循我正确设置的导航规则。但是对于文件,页面将与按下按钮之前保持完全相同
那么,如何在响应中返回一个文件,并使
标记重新提交呢?在写入后将其添加到您的方法中
//Skip the rest of JSF phases
FacesContext.getCurrentInstance().responseComplete();
您可能还希望在finally块中添加close,以便在发生异常时确保流正确关闭。
或者从Lombok添加注释,它会自动为您完成
更新
如果您在长时间运行的对话中,可以在重定向之前结束对话,因此验证消息将被删除
@End(beforeRedirect=true)
那么,如何在响应中返回一个文件,并使标记重新提交呢
对于单个HTTP请求,这是不可能的。每个请求只能返回一个响应。这不是JSF限制,这是HTTP限制
您可以使用JavaScript通过单击触发两个HTTP请求,但在您的特定情况下,这不会很好地工作,因为消息的JSF请求取决于PDF下载请求的结果。除了让servlet设置表示PDF状态的会话作用域托管的属性外,我看不到其他方法导出并引入一个ajax轮询,该轮询每隔一段时间请求此属性,并在属性不再为null时停止。
“单次HTTP请求不可能做到这一点。”
Gotcha。我可以看到ajax轮询解决方案是如何工作的,但这对我们来说不是一个理想的解决方案,所以看起来我必须从另一个角度来考虑这个问题。干杯。这句话最初在我的代码中-我删除它是为了看看效果如何。它不会影响我的messages标记的重新发布。