在JasperReport開發,主要會分成五個部分:
- Get data source: 傳入List of value object,並建立JRBeanCollectionDataSource
- Read Jasper File: 讀取.jasper file
- Generate JasperPrint: 讀取report input stream並建立JasperPrint物件
- Set response content type and header: 根據user要輸出的格式,指定content type and header
- Export Report: 根據user要輸出的格式,用相對應的API進行報表輸出
其實每份報表都不外乎這五大步驟,這邊我建立一個ReportWrapper class,如下
package gov.fdc.nig.report;
import gov.fdc.nig.enumeration.ExportFormatEnum;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRExporter;
import net.sf.jasperreports.engine.JRExporterParameter;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.export.JRCsvExporter;
import net.sf.jasperreports.engine.export.JRPdfExporter;
import net.sf.jasperreports.engine.util.JRLoader;
/**
* Report Wrapper Class
*
* @author albert
*
*/
public class ReportWrapper {
private transient JRDataSource dataSource;
private final static String JASPER_CLASSPATH = "..\\..\\..\\..\\report\\templates\\";
private transient InputStream reportStream;
private transient JasperPrint print;
/**
* Set report data source
*
* @param data
* List of value object
*/
private void setDataSource(final List data) {
dataSource = new JRBeanCollectionDataSource(data);
}
/**
* Get report input stream
*/
private void getReportInputStream(final String fileName) {
reportStream = getClass().getResourceAsStream(
JASPER_CLASSPATH.concat(fileName.concat(".jasper")));
}
/**
* generate JasperPrint
*
* @param params parameters
* @throws JRException
*/
public void generateJasperPrint(final Map params)
throws JRException {
final JasperReport report = (JasperReport) JRLoader
.loadObject(reportStream);
print = JasperFillManager.fillReport(report, params, dataSource);
}
/**
* Set content type and header
*
* @param fileName is File name
* @param response is HttpServletResponse
* @param exportEnum is ExportFormatEnum
*/
public void setResponse(final String fileName,
final HttpServletResponse response,
final ExportFormatEnum exportEnum) {
response.setCharacterEncoding("UTF-8");
if ("pdf".equals(exportEnum.getValue())) {
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment;filename=\""
.concat(fileName).concat(".pdf\""));
} else if ("csv".equals(exportEnum.getValue())) {
response.setContentType("application/octet-stream;charset=UTF-8");
response.setHeader("Content-Disposition", "attachment;filename="
.concat(fileName).concat(".csv"));
}
}
/**
* Export report
*
* @param exportEnum is ExportFormatEnum
* @param outputStream is OutputStream
* @throws JRException
* @throws IOException
*/
public void exportReport(final ExportFormatEnum exportEnum,
final OutputStream outputStream) throws JRException, IOException {
if ("pdf".equals(exportEnum.getValue())) {
final JRExporter pdfExporter = new JRPdfExporter();
pdfExporter.setParameter(JRExporterParameter.JASPER_PRINT, print);
pdfExporter.setParameter(JRExporterParameter.OUTPUT_STREAM, outputStream);
pdfExporter.exportReport();
} else if ("csv".equals(exportEnum.getValue())) {
// byte-order marker (BOM)
final byte bomByteArr[] = { (byte) 0xEF, (byte) 0xBB, (byte) 0xBF };
// insert BOM byte array into outputStream
outputStream.write(bomByteArr);
final JRExporter csvExporter = new JRCsvExporter();
csvExporter.setParameter(JRExporterParameter.JASPER_PRINT, print);
csvExporter.setParameter(JRExporterParameter.OUTPUT_STREAM, outputStream);
csvExporter.exportReport();
}
outputStream.flush();
}
/**
* do export report based on the parameters
*
* @param data is List of VO
* @param fileName is file name
* @param params is parameters
* @param response is HttpServletResponse
* @param exportEnum is ExportFormatEnum
* @param outputStream is OutputStream
* @throws JRException
* @throws IOException
*/
public void execute(final List data, final String fileName,
final Map params,
final HttpServletResponse response,
final ExportFormatEnum exportEnum, final OutputStream outputStream)
throws JRException, IOException {
setDataSource(data);
getReportInputStream(fileName);
generateJasperPrint(params);
setResponse(fileName, response, exportEnum);
exportReport(exportEnum, outputStream);
if (reportStream != null) {
reportStream.close();
}
}
}
未來我們在Contoller的processF7Key,只要建立ReportWrapper class,並將相對應的參數給execute method即可,請參考底下的程式片段
/**
* Will be executed as user click Print button
*
* @param formBean
* NIG135DataBean
* @param session
* NIG135DataBean
* @return JSONObject
* @throws IllegalAccessException
* @throws InvocationTargetException
* @throws IOException
*/
private @ResponseBody
void processF7Key(final NIG135DataBean formBean,
final HttpServletResponse response, final HttpSession session)
throws IllegalAccessException, InvocationTargetException,
IOException {
String jasperXMLFileName = "NIG135P1";
OutputStream outputStream = response.getOutputStream();
try {
if ("135".equals(formBean.getReportOption())) {
Map params = new HashMap();
params.put("rejectPeriod", formBean.doPrintForNIG135P1(covertToNIG135P1ReportBean(formBean));
if ("1".equals(formBean.getReportType())) {
// export csv file
if (ExportFormatEnum.CSV.getValue().equals(
formBean.getExportFormat())) {
new ReportWrapper().execute(data,
jasperXMLFileName, params, response,
ExportFormatEnum.CSV, outputStream);
}
// export pdf file
else if (ExportFormatEnum.PDF.getValue().equals(
formBean.getExportFormat())) {
new ReportWrapper().execute(data,
jasperXMLFileName, params, response,
ExportFormatEnum.PDF, outputStream);
}
}
}
}catch(Exception e){
//............
}
}
nig.nig135w.js
function nig135wFormF7(){
$("#fn").val("7");
$("#nig135wForm").attr("target", "_self");
$("#nig135wForm").attr("action", "/nig/front/NIG135W");
$("#nig135wForm").submit();
}
Benefits
所有的報表程式,都透過這一支ReportWrapper class來處理。
我們只要專注於前端的business logic以及templates,後端如何去產生pdf, csv等格式,就交給ReportWrapper 處理就好。