Total Pageviews

2011/06/14

ReportWrapper Class for JasperReport Implementation

在JasperReport開發,主要會分成五個部分:
  1. Get data source: 傳入List of value object,並建立JRBeanCollectionDataSource
  2. Read Jasper File: 讀取.jasper file
  3. Generate JasperPrint: 讀取report input stream並建立JasperPrint物件
  4. Set response content type and header: 根據user要輸出的格式,指定content type and header
  5. 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 處理就好。

No comments: