Springmvc與jasperreport結合生成報表的一種方法

項目緣由須要在springmvc的基礎上整合jasperreports生成報表。其實springmvc已經提供了對jasperreports的支持,感受springmvc採用的一個比較好的方式是將報表的生成做爲一個view處理,可是須要對每一種報表配置他的jasperreports模板及視圖的映射,這樣的話添加報表必須變動配置,比較麻煩,因此本身想了一個方法來避免這種配置,代碼能夠很容易和spring整合起來。html

 japserreports生成報表基本流程其實就是根據一個模板和數據源生成一箇中間類型,而後能夠在此基礎上能夠導出幾種格式。個人想法是提供方法供springmvc的controller調用產生中間文件,而後在view裏面向客戶端導出請求的格式。java

首先是ReportPrint類,很簡單,只是包含一個JasperPrint對象(既上述的中間文件),代碼很簡單,不解釋spring

public class ReportPrint {
	JasperPrint jasperPrint = null;

	public JasperPrint getJasperPrint() {
		return jasperPrint;
	}

	public void setJasperPrint(JasperPrint jasperPrint) {
		this.jasperPrint = jasperPrint;
	}
	
}
接下來就是ReportCreater類,該類可經過spring注入到其餘類中,調用它的createReport方法

public class ReportCreater {
	private static final Log logger = LogFactory.getLog(ReportCreater.class);
	private String jasperReportPath = null;//報表的模板文件存放路徑(相對classpath,經過spring注入)
	/**
	 * jasperDesignMap做爲一個緩存來存儲編譯後的JasperReport模板
	 */
	private Map<String, JasperReport> jasperDesignMap = new ConcurrentHashMap<String, JasperReport>();
	
	public void resetJasperDesignCache() {
		jasperDesignMap.clear();
	}
	
	/**
	 * controller調用該方法來產生ReportPrint對象
	 */
	public ReportPrint createReport(final String reportKey, final ResultSet rs, Map<String, ?> reportParams) throws ReportException {
		try {
			return _createReport(reportKey, rs, reportParams);
		} catch (JRException e) {
			logger.error(null, e);
			throw new ReportException("產生報表出錯" + reportKey);
		}
	}
	
	private ReportPrint _createReport(final String reportKey, final ResultSet rs, Map<String, ?> reportParams) throws ReportException, JRException {
		JasperReport jasperReport = getJasperReport(reportKey);		
		ReportPrint reportPrint = new ReportPrint();
		JRResultSetDataSource resultSetDataSource = new JRResultSetDataSource(rs);
		JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, reportParams, resultSetDataSource);
		reportPrint.setJasperPrint(jasperPrint);
		
		return reportPrint;
	}
	
	private JasperReport getJasperReport(final String reportKey) {
		try {
			return _getJasperReport(reportKey);
		} catch (IOException e) {
			logger.error(null, e);
			throw new ReportException("關閉文件流異常:" + reportKey);
		} catch (JRException e) {
			logger.error(null, e);
			throw new ReportException("產生報表異常:" + reportKey);
		}
	}
	
	private JasperReport _getJasperReport(final String reportKey) throws IOException, JRException {
		JasperReport jasperReport = null;
		if (jasperDesignMap.containsKey(reportKey)) {
			jasperReport = jasperDesignMap.get(reportKey);
		} else {
			jasperReport = getJasperReportFromFile(final String reportKey);
			jasperDesignMap.put(reportKey, jasperReport);
		}
		
		return jasperReport;
	}
	
	/**
	 * 從模板文件編譯得到模板對象
	 */
	private JasperReport getJasperReportFromFile(final String reportKey)  throws IOException, JRException {
		String filePath = jasperReportPath + reportKey + ".jrxml";//圖省事只支持jrxml的
		InputStream jasperFileIS = null;
		JasperReport jasperReport = null;
		
		try {
			jasperFileIS = this.getClass().getClassLoader().getResourceAsStream(filePath);
			if (jasperFileIS == null) {
				throw new ReportException("報表文件不存在:" + filePath);
			}
			
			JasperDesign jasperDesign = JRXmlLoader.load(jasperFileIS);
			jasperReport = JasperCompileManager.compileReport(jasperDesign);
		} finally {
			if (jasperFileIS != null) {
				jasperFileIS.close();
			}
		}
		
		return jasperReport;
	}
	
	public String getJasperReportPath() {
		return jasperReportPath;
	}
	
	public void setJasperReportPath(String jasperReportPath) {
		this.jasperReportPath = jasperReportPath;
	}
	
	public static void main(String[] argv) {
	
	}
	
}

以上就能夠產生中間文件了,接下來就是按照spring的view規範寫一個導出各類格式的視圖就能夠了緩存

public class ReportView extends AbstractView  {
	private static final Log logger = LogFactory.getLog(ReportView.class);
	private static final String XLS = "xls";
	private static final String PDF = "pdf";
	private static final String CSV = "csv";
	private static final String REPORT_NAME = "reportName";
	private static final String FORMAT = "format";
	private static final String REPORT_PRINT = "reportPrint";
	private static final String HTML = "html";
	
	private static Map<String, IReportFileExporter> EXPORTER_MAP =
			new HashMap<String, IReportFileExporter>(4);
	
	static {
		EXPORTER_MAP.put(XLS, new ReportXlsExporter());
		EXPORTER_MAP.put(PDF, new ReportPdfExporter());
		EXPORTER_MAP.put(CSV, new ReportCsvExporter());
		EXPORTER_MAP.put(HTML, new ReportHtmlExporter());
	}
	
	@Override
	protected void renderMergedOutputModel(Map model, HttpServletRequest request,
			HttpServletResponse response) {
		String reportName = (String) model.get(REPORT_NAME);//報表的文件名
		String format = (String) model.get(FORMAT);//報表的格式pdf xls .....
		ReportPrint reportPrint = (ReportPrint) model.get(REPORT_PRINT);//這就是以前生成的中間文件
		response.setContentType("application/x-msdown;charset=utf-8");
		try {
			/* http頭裏的文件名貌似不支持utf-8,gbk之類的編碼,須要轉換一下
			 * 另外發現若是用new String(reportName.getBytes("UTF-8"), "iso-8859-1")的話Chrome和FF的
			 * 下載對話框的文件名是正常的,IE倒是亂碼,只能用GBK才正常
			 */
			response.setHeader("Content-Disposition","attachment;filename=\"" + 
					new String(reportName.getBytes("GBK"), "iso-8859-1") + "\"");
		} catch (UnsupportedEncodingException e) {
			logger.error(null, e);
		}
		exportFile(reportPrint, format, response);
	}
	
	private void exportFile(ReportPrint reportPrint, String format, HttpServletResponse response) {
		try {
			_exportFile(reportPrint, format, response);
		} catch (JRException e) {
			logger.error("導出報表異常", e);
		} catch (IOException e) {
			logger.error(null, e);
		}
	}
	
	private void _exportFile(ReportPrint reportPrint, String format, HttpServletResponse response) throws IOException, JRException {
		OutputStream buffOS = null;
		
		try {
			buffOS = new BufferedOutputStream(response.getOutputStream());
			IReportFileExporter exporter = null;
			
			if (EXPORTER_MAP.containsKey(format)) {
				exporter = EXPORTER_MAP.get(format);//獲取須要格式的導出類
				exporter.export(reportPrint, buffOS);
			} else {
				logger.error("錯誤的報表格式:" + format);
			}
		} finally {
			if (buffOS != null) {
				buffOS.close();
			}
		}
	}
	
}
導出器是一個簡單的接口,各類格式只要實現export方法就能夠了

public interface IReportFileExporter {
	public void export(ReportPrint reportPrint, OutputStream os) throws JRException;
}
給一個導出PDF格式的例子,很簡單

public class ReportPdfExporter implements IReportFileExporter {

	public void export(ReportPrint reportPrint, OutputStream os) throws JRException {
		JRPdfExporter exporter = new JRPdfExporter();
		exporter.setParameter(JRExporterParameter.JASPER_PRINT, reportPrint.getJasperPrint());
		exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, os);
		exporter.exportReport();
	}

}

差很少久這樣了,完整的代碼已經上傳。mvc

相關文章
相關標籤/搜索