经过一段时间的编码,我终于成功地完成了这项工作。Primefaces 不包含此功能,因此我必须稍微覆盖默认行为。
首先,我创建了自定义 PDFExporter 以跳过页脚打印:
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import org.primefaces.component.datatable.DataTable;
import org.primefaces.component.export.PDFExporter;
import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.PdfPTable;
public class CustomPDFExporter extends PDFExporter {
@Override
protected void addColumnFacets(DataTable table, PdfPTable pdfTable,
ColumnType columnType) {
if (columnType == ColumnType.HEADER) {
super.addColumnFacets(table, pdfTable, columnType);
}
}
@Override
protected void writePDFToResponse(ExternalContext externalContext,
ByteArrayOutputStream baos, String fileName) throws IOException,
DocumentException {
FacesContext.getCurrentInstance().getExternalContext().getSessionMap()
.put("reportBytes", baos.toByteArray());
FacesContext.getCurrentInstance().getExternalContext().getSessionMap()
.put("reportName", fileName);
}
}
如您所见,报表数据是在会话中添加的。
现在DataExporter
应该重写 Primefaces:
import java.io.IOException;
import javax.el.ELContext;
import javax.el.MethodExpression;
import javax.el.ValueExpression;
import javax.faces.FacesException;
import javax.faces.component.StateHolder;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.event.ActionListener;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.primefaces.component.datatable.DataTable;
import org.primefaces.component.export.CSVExporter;
import org.primefaces.component.export.Exporter;
import org.primefaces.component.export.ExporterType;
import org.primefaces.component.export.XMLExporter;
import org.primefaces.context.RequestContext;
import asw.iis.common.ui.beans.DatatableBackingBean;
public class CustomDataExporter implements ActionListener, StateHolder {
private ValueExpression target;
private ValueExpression type;
private ValueExpression fileName;
private ValueExpression encoding;
private MethodExpression preProcessor;
private MethodExpression postProcessor;
private DatatableBackingBean<?> datatableBB;
public CustomDataExporter() {}
public CustomDataExporter(ValueExpression target, ValueExpression type, ValueExpression fileName, ValueExpression encoding,
MethodExpression preProcessor, MethodExpression postProcessor, DatatableBackingBean<?> datatableBB) {
this.target = target;
this.type = type;
this.fileName = fileName;
this.encoding = encoding;
this.preProcessor = preProcessor;
this.postProcessor = postProcessor;
this.datatableBB = datatableBB;
}
public void processAction(ActionEvent event) {
FacesContext context = FacesContext.getCurrentInstance();
try {
datatableBB.stampaPreProcess();
ELContext elContext = context.getELContext();
String tableId = (String) target.getValue(elContext);
String exportAs = (String) type.getValue(elContext);
String outputFileName = (String) fileName.getValue(elContext);
String encodingType = "UTF-8";
if(encoding != null) {
encodingType = (String) encoding.getValue(elContext);
}
try {
Exporter exporter;
ExporterType exporterType = ExporterType.valueOf(exportAs.toUpperCase());
switch(exporterType) {
case XLS:
exporter = new ExcelExporter();
break;
case PDF:
exporter = new CustomPDFExporter();
break;
case CSV:
exporter = new CSVExporter();
break;
case XML:
exporter = new XMLExporter();
break;
default:
exporter = new CustomPDFExporter();
break;
}
UIComponent component = event.getComponent().findComponent(tableId);
if(component == null) {
throw new FacesException("Cannot find component \"" + tableId + "\" in view.");
}
if(!(component instanceof DataTable)) {
throw new FacesException("Unsupported datasource target:\"" + component.getClass().getName() + "\", exporter must target a PrimeFaces DataTable.");
}
DataTable table = (DataTable) component;
exporter.export(context, table, outputFileName, false, false, encodingType, preProcessor, postProcessor);
if ("pdf".equals(exportAs)) {
String path = ((ServletContext)(FacesContext.getCurrentInstance().getExternalContext().getContext())).getContextPath();
RequestContext.getCurrentInstance().execute("window.open('" + path + "/report.pdf', '_blank', 'dependent=yes, menubar=no, toolbar=no')");
} else {
context.responseComplete();
}
}
catch (IOException e) {
throw new FacesException(e);
}
}
finally {
((HttpServletRequest) context.getExternalContext().getRequest()).removeAttribute("vrstaStampe");
datatableBB.stampaPostProcess();
}
}
public boolean isTransient() {
return false;
}
public void setTransient(boolean value) {
}
public void restoreState(FacesContext context, Object state) {
Object values[] = (Object[]) state;
target = (ValueExpression) values[0];
type = (ValueExpression) values[1];
fileName = (ValueExpression) values[2];
preProcessor = (MethodExpression) values[3];
postProcessor = (MethodExpression) values[4];
encoding = (ValueExpression) values[5];
datatableBB = (DatatableBackingBean<?>) values[6];
}
public Object saveState(FacesContext context) {
Object values[] = new Object[7];
values[0] = target;
values[1] = type;
values[2] = fileName;
values[3] = preProcessor;
values[4] = postProcessor;
values[5] = encoding;
values[6] = datatableBB;
return ((Object[]) values);
}
}
这里的主要工作是实例化CustomPDFExporter
,并在报告类型为PDF时打开新窗口。
现在我编写了简单Servlet
的方法来处理这个请求并打印报告数据:
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/report.pdf")
public class PdfReportServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
byte[] b = (byte[]) req.getSession().getAttribute("reportBytes");
if (b == null) {
b = new byte[0];
}
resp.setContentType("application/pdf");
resp.setContentLength(b.length);
resp.getOutputStream().write(b);
req.getSession().removeAttribute("reportBytes");
}
}
这将配置 HTTP 标头,并将报告字节打印到输出流。它还从会话中删除报告字节。
最后,当我从动态创建的菜单按钮处理这个打印时,我在代码中添加了这个动作监听器:
MenuItem item = ...;
ELContext el = FacesContext.getCurrentInstance().getELContext();
ExpressionFactory ef = FacesContext.getCurrentInstance().getApplication().getExpressionFactory();
ValueExpression typeEL = ef.createValueExpression(el, "#{startBean.reportType}", String.class);
ValueExpression fileEL = ef.createValueExpression(el, datasource, String.class);
ValueExpression targetEL = ef.createValueExpression(el, ":" + datatableId + ":datatableForm:datatable", String.class);
ValueExpression encodingEL = ef.createValueExpression(el, "ISO-8859-2", String.class);
CustomDataExporter de = new CustomDataExporter(targetEL, typeEL, fileEL, encodingEL, null, null, this);
item.setAjax(true);
item.addActionListener(de);