JSF文件下载异常处理(如何防止视图重绘)
JSF file download exception handling (how to prevent view rerendering)
朋友们,美好的一天!
首先,我为我的英语感到抱歉。这是我的问题:
我是 JSF (2.0) 的新手,我正在尝试使用 BalusC 算法从托管 bean 下载文件。功能正常运行,"Save As..." 对话框出现在浏览器中。但是我不知道如何在没有视图 reload/redirect.
的情况下 return 文件下载错误消息(支持 bean 方法中的异常、数据库错误等)
我在视图上的隐藏按钮:
<h:form id="detailsDecisionMainForm">
<h:inputHidden id="docId" value="" />
<h:commandButton id="downloadAction" action="#{detailsDecisionGridBean.downloadForm()}" style="display: none;" />
</h:form>
我的托管 bean(我可以使用哪个范围?我试过请求和查看范围)方法:
public String downloadForm() {
log.fine("downloadForm call");
PdfService pdfService = new PdfServiceImpl();
ArmCommonService armCommonService = new ArmCommonServiceImpl();
String errorMessage = null;
try {
Long opUni = new Long(FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("detailsDecisionMainForm:docId"));
log.fine("Document opUni = " + opUni);
DocXML docXML = armCommonService.getDocXMLById(opUni);
if (docXML != null) {
File pdfFile = pdfService.getPdfReport(docXML.getXml(), docXML.getType());
if (pdfFile != null) {
DownloadUtils.exportPdf(pdfFile);
} else {
log.log(Level.SEVERE, "downloadForm error: pdf generation error");
errorMessage = "PDF-document generation error.";
}
} else {
log.log(Level.SEVERE, "downloadForm error: xml not found");
errorMessage = "XML-document not found.";
}
} catch (Exception ex) {
log.log(Level.SEVERE, "downloadForm exception: " + ex.getMessage());
errorMessage = "File download exception.";
}
if (errorMessage != null) {
FacesContext.getCurrentInstance().addMessage("detailsDecisionMainForm:downloadAction", new FacesMessage(errorMessage));
}
return null;
}
DownloadUtils.exportPdf() 程序正常工作:
public static void exportPdf(File file) throws IOException {
InputStream fileIS = null;
try {
log.fine("exportPdf call");
fileIS = new FileInputStream(file);
FacesContext fc = FacesContext.getCurrentInstance();
ExternalContext ec = fc.getExternalContext();
ec.responseReset();
ec.setResponseContentType(APPLICATION_PDF_UTF_8);
byte[] buffer = ByteStreams.toByteArray(fileIS);
ec.setResponseContentLength(buffer.length);
ec.setResponseHeader(HttpHeaders.CONTENT_DISPOSITION, String.format(CONTENT_DISPOSITION_VALUE, new String(file.getName().getBytes(StandardCharsets.UTF_8))));
ec.getResponseOutputStream().write(buffer);
fc.responseComplete();
} catch (Exception ex) {
log.log(Level.SEVERE, "exportPdf exception: " + ex.getMessage());
} finally {
if (fileIS != null) {
fileIS.close();
log.fine("exportPdf inputstream file closed");
}
}
}
如何防止在 downloadForm() 之后重新呈现视图 error/exception?以及如何显示带有消息文本的 javascript alert()(将来 - jQuery.messager 带有错误文本的面板)?
谢谢!
为了防止重新加载整个页面,您必须在 ajax 之前提交表单。但是,为了能够下载文件,您必须关闭 ajax。这并不能很好地结合在一起。
最好的办法是将操作分成两个请求。首先发送一个 ajax 请求,在服务器端的临时位置创建文件。当失败时,您可以按照通常的方式显示面孔消息。成功后,您可以通过条件呈现的 JavaScript 提交隐藏的非 ajax 命令按钮来自动触发第二个请求。然后,第二个请求可以将已经成功创建的文件从临时位置流式传输到响应。
之前已经提出并回答了类似的问题:. But this involves PrimeFaces and OmniFaces。以下是标准的 JSF 方法:
<h:form id="form">
...
<h:commandButton value="Export" action="#{bean.export}">
<f:ajax ... render="result" />
</h:commandButton>
<h:panelGroup id="result">
<h:messages />
<h:commandButton id="download" action="#{bean.download}"
style="display:none" />
<h:outputScript rendered="#{not facesContext.validationFailed}">
document.getElementById("form:download").onclick();
</h:outputScript>
</h:panelGroup>
</h:form>
并使用此 @ViewScoped
bean(逻辑基于您现有的逻辑)。基本上,只需在导出操作 (ajax) 期间获取 File
作为实例变量,然后在下载操作(非 ajax)期间将其流式传输。
private File pdfFile;
public void export() {
try {
pdfFile = pdfService.getPdfReport(...);
} catch (Exception e) {
context.addMessage(...);
}
}
public void download() throws IOException {
DownloadUtils.exportPdf(pdfFile);
}
另请参阅:
- How to invoke a JSF managed bean on a HTML DOM event using native JavaScript?
- Store PDF for a limited time on app server and make it available for download
朋友们,美好的一天!
首先,我为我的英语感到抱歉。这是我的问题:
我是 JSF (2.0) 的新手,我正在尝试使用 BalusC 算法从托管 bean 下载文件。功能正常运行,"Save As..." 对话框出现在浏览器中。但是我不知道如何在没有视图 reload/redirect.
的情况下 return 文件下载错误消息(支持 bean 方法中的异常、数据库错误等)我在视图上的隐藏按钮:
<h:form id="detailsDecisionMainForm">
<h:inputHidden id="docId" value="" />
<h:commandButton id="downloadAction" action="#{detailsDecisionGridBean.downloadForm()}" style="display: none;" />
</h:form>
我的托管 bean(我可以使用哪个范围?我试过请求和查看范围)方法:
public String downloadForm() {
log.fine("downloadForm call");
PdfService pdfService = new PdfServiceImpl();
ArmCommonService armCommonService = new ArmCommonServiceImpl();
String errorMessage = null;
try {
Long opUni = new Long(FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("detailsDecisionMainForm:docId"));
log.fine("Document opUni = " + opUni);
DocXML docXML = armCommonService.getDocXMLById(opUni);
if (docXML != null) {
File pdfFile = pdfService.getPdfReport(docXML.getXml(), docXML.getType());
if (pdfFile != null) {
DownloadUtils.exportPdf(pdfFile);
} else {
log.log(Level.SEVERE, "downloadForm error: pdf generation error");
errorMessage = "PDF-document generation error.";
}
} else {
log.log(Level.SEVERE, "downloadForm error: xml not found");
errorMessage = "XML-document not found.";
}
} catch (Exception ex) {
log.log(Level.SEVERE, "downloadForm exception: " + ex.getMessage());
errorMessage = "File download exception.";
}
if (errorMessage != null) {
FacesContext.getCurrentInstance().addMessage("detailsDecisionMainForm:downloadAction", new FacesMessage(errorMessage));
}
return null;
}
DownloadUtils.exportPdf() 程序正常工作:
public static void exportPdf(File file) throws IOException {
InputStream fileIS = null;
try {
log.fine("exportPdf call");
fileIS = new FileInputStream(file);
FacesContext fc = FacesContext.getCurrentInstance();
ExternalContext ec = fc.getExternalContext();
ec.responseReset();
ec.setResponseContentType(APPLICATION_PDF_UTF_8);
byte[] buffer = ByteStreams.toByteArray(fileIS);
ec.setResponseContentLength(buffer.length);
ec.setResponseHeader(HttpHeaders.CONTENT_DISPOSITION, String.format(CONTENT_DISPOSITION_VALUE, new String(file.getName().getBytes(StandardCharsets.UTF_8))));
ec.getResponseOutputStream().write(buffer);
fc.responseComplete();
} catch (Exception ex) {
log.log(Level.SEVERE, "exportPdf exception: " + ex.getMessage());
} finally {
if (fileIS != null) {
fileIS.close();
log.fine("exportPdf inputstream file closed");
}
}
}
如何防止在 downloadForm() 之后重新呈现视图 error/exception?以及如何显示带有消息文本的 javascript alert()(将来 - jQuery.messager 带有错误文本的面板)?
谢谢!
为了防止重新加载整个页面,您必须在 ajax 之前提交表单。但是,为了能够下载文件,您必须关闭 ajax。这并不能很好地结合在一起。
最好的办法是将操作分成两个请求。首先发送一个 ajax 请求,在服务器端的临时位置创建文件。当失败时,您可以按照通常的方式显示面孔消息。成功后,您可以通过条件呈现的 JavaScript 提交隐藏的非 ajax 命令按钮来自动触发第二个请求。然后,第二个请求可以将已经成功创建的文件从临时位置流式传输到响应。
之前已经提出并回答了类似的问题:
<h:form id="form">
...
<h:commandButton value="Export" action="#{bean.export}">
<f:ajax ... render="result" />
</h:commandButton>
<h:panelGroup id="result">
<h:messages />
<h:commandButton id="download" action="#{bean.download}"
style="display:none" />
<h:outputScript rendered="#{not facesContext.validationFailed}">
document.getElementById("form:download").onclick();
</h:outputScript>
</h:panelGroup>
</h:form>
并使用此 @ViewScoped
bean(逻辑基于您现有的逻辑)。基本上,只需在导出操作 (ajax) 期间获取 File
作为实例变量,然后在下载操作(非 ajax)期间将其流式传输。
private File pdfFile;
public void export() {
try {
pdfFile = pdfService.getPdfReport(...);
} catch (Exception e) {
context.addMessage(...);
}
}
public void download() throws IOException {
DownloadUtils.exportPdf(pdfFile);
}
另请参阅:
- How to invoke a JSF managed bean on a HTML DOM event using native JavaScript?
- Store PDF for a limited time on app server and make it available for download