我正在使用 Jakarta Server Faces 和 PrimeFaces 12 开发一个 JavaWeb 项目。我正在尝试处理一个具有 4 个互相更新的 SelectOneMenu 的表单(第一个选定的元素更新第二个中可用的元素,第二个选定的元素第二个更新第三个,依此类推)。我使用了 Ajax,因此更改任何一个 selectOneMenu 的状态都会更新其余 selectOneMenu 的值。
表单的提交按钮处理整个表单,但我需要它而不是使用 Ajax 处理表单,因为此按钮还会下载根据 selectOneMenu 中所选值生成的报告。
如果我将代码 ajax = true 放入表单的提交按钮,它会处理但不会下载文件,但是,如果我禁用按钮的 Ajax,即使在所有 selectOneMenu 中选择了有效值,它们也会抛出错误表明值无效并且表单未完成。
我展示我正在使用的代码:
#{reportsBean.update_Area()}
<h:form id="form1">
<p:growl id="messages" allowDismiss="true"/>
<div class="row">
<div class="col col-sm-6">
<p:outputLabel for="areaInput"
styleClass="block"> Área </p:outputLabel> <br/>
<p:selectOneMenu value="#{reportsBean.area}"
id="areaInput"
requiredMessage="Área: Es necesario seleccionar una Facultad"
required="true" label="Área">
<f:selectItem itemLabel="(Seleccione un Área)" itemValue=""/>
<f:selectItems value="#{reportsBean.list_area}" var="a" itemValue="#{a}"
itemLabel="#{a}"/>
<p:ajax update="carrera plan_estudio asignatura"/>
</p:selectOneMenu>
</div>
<div class="col col-sm-6">
<p:outputPanel id="carrera">
#{reportsBean.updtate_carrera()}
<p:outputLabel for="carreraInput"
styleClass="block"> Carrera </p:outputLabel> <br/>
<p:selectOneMenu value="#{reportsBean.carrera}"
id="carreraInput"
requiredMessage="Carrera: Es necesario seleccionar una Carrera"
required="true" label="Carrera">
<f:selectItem itemLabel="(Seleccione una Carrera)" itemValue=""/>
<f:selectItems value="#{reportsBean.list_carrera}" var="c" itemValue="#{c}"
itemLabel="#{c}"/>
<p:ajax update="plan_estudio asignatura"/>
</p:selectOneMenu>
</p:outputPanel>
</div>
</div>
<br/>
<div class="row">
<div class="col col-sm-6">
<p:outputPanel id="plan_estudio">
#{reportsBean.update_plan_estudio()}
<p:outputLabel for="planEstudioInput"
styleClass="block"> Plan de Estudio </p:outputLabel> <br/>
<p:selectOneMenu id="planEstudioInput" value="#{reportsBean.plan_estudio}"
requiredMessage="Plan de Estudio: Es necesario seleccionar un Plan de Estudio"
required="true" label="Plan de Estudio">
<f:selectItem itemLabel="(Seleccione un Plan de Estudio)" itemValue=""/>
<f:selectItems value="#{reportsBean.list_plan_estudio}" var="pe" itemValue="#{pe}"
itemLabel="#{pe}"/>
<p:ajax update="asignatura"/>
</p:selectOneMenu>
</p:outputPanel>
</div>
<div class="col col-sm-6">
<p:outputPanel id="asignatura">
<p:outputLabel for="asignaturaInput"
styleClass="block"> Asignatura </p:outputLabel> <br/>
#{reportsBean.update_Asignaturas()}
<p:selectOneMenu value="#{reportsBean.asignatura_Ms13d}"
id="asignaturaInput"
requiredMessage="Asignatura: Es necesario seleccionar una Asignatura"
required="true" label="Asignatura">
<f:selectItem itemLabel="(Seleccione una Asignatura)" itemValue=""/>
<f:selectItems value="#{reportsBean.list_asignatura}" var="pe" itemValue="#{pe}"
itemLabel="#{pe}"/>
</p:selectOneMenu>
</p:outputPanel>
</div>
</div>
<br/>
<div style="float: right">
<p:commandButton title="PDF" style="margin-right: 10px" icon="pi pi-file-pdf"
styleClass="ui-button ui-button-secondary" ajax="false"
actionListener="#{reportsBean.print_rs4b_tipo1_PDF()}">
</p:commandButton>
<p:commandButton title="DOC" style="margin-right: 10px" icon="pi pi-file-word"
styleClass="ui-button ui-button-secondary" ajax="false"
actionListener="#{reportsBean.print_rs4b_tipo1_DOC()}">
</p:commandButton>
<p:commandButton title="RTF" style="margin-right: 10px" icon="pi pi-file"
styleClass="ui-button ui-button-secondary" ajax="false"
actionListener="#{reportsBean.print_rs4b_tipo1_RTF()}">
</p:commandButton>
</div>
<input type="hidden"
name="${_csrf.parameterName}"
value="${_csrf.token}"/>
</h:form>
这是表单的图像,一旦填写完毕,按下生成 PDF 按钮,表单值被删除,并显示每个 selectOneMenu 的错误消息。
我希望你能帮我解决这个问题。预先感谢
感谢@JasperdeVries 的回复。我给你完整的解决方案。
可以使用ajax来解决这种情况。可以使用primefaces的下载组件。使用 Primefaces
StreamedContent
类,可以获取生成报告的流,然后通过 p:filedownloader
发送到视图。
视图看起来像这样:
<h:form id="form1">
<p:growl id="messages" allowDismiss="true"/>
<div class="row">
<div class="col col-sm-3">
<p:outputLabel for="idSearch"
styleClass="block"> Identificación </p:outputLabel>
<p:inputMask
id="idSearch"
mask="99999999999"
requiredMessage="ERROR: Es necesario un valor para establecer la búsqueda"
validatorMessage="ERROR: Idemtificación no válida"
placeholder="Identificación" value="#{reportsBean.idEstudiante}"
required="true"
/>
</div>
<div class="col-sm-5">
<br/>
<p:commandButton title="PDF" style="margin-right: 10px" icon="pi pi-file-pdf"
styleClass="ui-button ui-button-secondary" ajax="true" update="form1"
actionListener="#{reportsBean.printCertCalifCursoAc('PDF')}">
<p:fileDownload value="#{reportsBean.file}"/>
</p:commandButton>
<p:commandButton title="DOCX" style="margin-right: 10px" icon="pi pi-file-word"
styleClass="ui-button ui-button-secondary" ajax="true" update="form1"
actionListener="#{reportsBean.printCertCalifCursoAc('DOCX')}">
<p:fileDownload value="#{reportsBean.file}"/>
</p:commandButton>
<p:commandButton title="RTF" style="margin-right: 10px" icon="pi pi-file"
styleClass="ui-button ui-button-secondary" ajax="true" update="form1"
actionListener="#{reportsBean.printCertCalifCursoAc('RTF')}">
<p:fileDownload value="#{reportsBean.file}"/>
</p:commandButton>
</div>
</div>
<input type="hidden"
name="${_csrf.parameterName}"
value="${_csrf.token}"/>
</h:form>
然后,在 bean 中,准备好处理文件的基础,定义
StreamedContent
对象,并通过函数将报告数据发送到报告处理器。
public void printCertCalifCursoAc(String type){
Map<String, Object> params = new java.util.HashMap<String, Object>();
params.put("id", idEstudiante);
String fileName = "Certificado de Calificaciones de Curso Académico - " + idEstudiante + "." + type.toLowerCase();
String jasperPath = URL + "ms19d.jasper";
FileType fileType = FileType.valueOf(type);
try {
file = reportUtil.processReport(params, jasperPath, fileName, fileType);
} catch (JRException | IOException e) {
throw new RuntimeException(e);
}
}
最后,考虑要处理的文件类型(本例中为 PDF、RTF 或 DOCX),处理文件。并且
StreamContent
被发送到Bean,然后发送到视图。
private StreamedContent getStreamedcontent(ByteArrayOutputStream outputStream, String fileName) throws IOException {
InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
SerializableSupplier<InputStream> supplier = () -> inputStream;
StreamedContent streamedContent = DefaultStreamedContent.builder()
.contentType("application/octet-stream")
.name(fileName)
.stream(supplier)
.build();
outputStream.flush();
outputStream.close();
inputStream.close();
return streamedContent;
}
public StreamedContent processReport(Map<String, Object> params, String jasperpath, String fileName, FileType fileType) throws IOException, JRException {
if (params == null) {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "ERROR: Debe seleccionar o introducir un valor", "Error"));
}
String relativeWebPath = FacesContext.getCurrentInstance().getExternalContext().getRealPath(jasperpath);
File file = new File(relativeWebPath);
Connection con = connection.getConnectionInstance("org.postgresql.Driver", "jdbc:postgresql://localhost:5432/SIGENU_EaD", "postgres", "postgres");
String filename = file.getPath();
JasperPrint print = JasperFillManager.fillReport(filename, params, con);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
switch (fileType) {
case PDF -> JasperExportManager.exportReportToPdfStream(print, outputStream);
case RTF -> {
JRRtfExporter exporter = new JRRtfExporter();
exporter.setParameter(JRExporterParameter.JASPER_PRINT, print);
exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, outputStream);
exporter.exportReport();
}
case DOCX -> {
JRDocxExporter exporter = new JRDocxExporter();
exporter.setParameter(JRExporterParameter.JASPER_PRINT, print);
exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, outputStream);
exporter.exportReport();
}
}
return getStreamedcontent(outputStream, fileName);
}