jasperreport怎么集成到springmvc

 我来答
就烦条0o
2016-01-19 · 知道合伙人软件行家
就烦条0o
知道合伙人软件行家
采纳数:33315 获赞数:46487
从事多年系统运维,喜欢编写各种小程序和脚本。

向TA提问 私信TA
展开全部
项目原因需要在springmvc的基础上整合jasperreports生成报表。其实springmvc已经提供了对jasperreports的支持,感觉springmvc采用的一个比较好的方式是将报表的生成作为一个view处理,但是需要对每一种报表配置他的jasperreports模板及视图的映射,这样的话添加报表必须变更配置,比较麻烦,所以自己想了一个方法来避免这种配置,代码可以很容易和spring整合起来。
japserreports生成报表基本流程其实就是根据一个模板和数据源生成一个中间类型,然后可以在此基础上可以导出几种格式。我的想法是提供方法供springmvc的controller调用产生中间文件,然后在view里面向客户端导出请求的格式。
首先是ReportPrint类,很简单,只是包含一个JasperPrint对象(既上述的中间文件),代码很简单,不解释
01 public class ReportPrint {
02 JasperPrint jasperPrint = null;
03
04 public JasperPrint getJasperPrint() {
05 return jasperPrint;
06 }
07
08 public void setJasperPrint(JasperPrint jasperPrint) {
09 this.jasperPrint = jasperPrint;
10 }
11
12 }
接下来就是ReportCreater类,该类可通过spring注入到其他类中,调用它的createReport方法
01 public class ReportCreater {
02 private static final Log logger = LogFactory.getLog(ReportCreater.class);
03 private String jasperReportPath = null;//报表的模板文件存放路径(相对classpath,通过spring注入)
04 /**
05 * jasperDesignMap作为一个缓存来存储编译后的JasperReport模板
06 */
07 private Map<String, JasperReport> jasperDesignMap = newConcurrentHashMap<String, JasperReport>();
08
09 public void resetJasperDesignCache() {
10 jasperDesignMap.clear();
11 }
12
13 /**
14 * controller调用该方法来产生ReportPrint对象
15 */
16 public ReportPrint createReport(final String reportKey, final ResultSet rs, Map<String, ?> reportParams) throws ReportException {
17 try {
18 return _createReport(reportKey, rs, reportParams);
19 } catch (JRException e) {
20 logger.error(null, e);
21 throw new ReportException("产生报表出错" + reportKey);
22 }
23 }
24
25 private ReportPrint _createReport(final String reportKey, final ResultSet rs, Map<String, ?> reportParams) throws ReportException, JRException {
26 JasperReport jasperReport = getJasperReport(reportKey);
27 ReportPrint reportPrint = new ReportPrint();
28 JRResultSetDataSource resultSetDataSource = newJRResultSetDataSource(rs);
29 JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, reportParams, resultSetDataSource);
30 reportPrint.setJasperPrint(jasperPrint);
31
32 return reportPrint;
33 }
34
35 private JasperReport getJasperReport(final String reportKey) {
36 try {
37 return _getJasperReport(reportKey);
38 } catch (IOException e) {
39 logger.error(null, e);
40 throw new ReportException("关闭文件流异常:" + reportKey);
41 } catch (JRException e) {
42 logger.error(null, e);
43 throw new ReportException("产生报表异常:" + reportKey);
44 }
45 }
46
47 private JasperReport _getJasperReport(final String reportKey) throwsIOException, JRException {
48 JasperReport jasperReport = null;
49 if (jasperDesignMap.containsKey(reportKey)) {
50 jasperReport = jasperDesignMap.get(reportKey);
51 } else {
52 jasperReport = getJasperReportFromFile(final String reportKey);
53 jasperDesignMap.put(reportKey, jasperReport);
54 }
55
56 return jasperReport;
57 }
58
59 /**
60 * 从模板文件编译获得模板对象
61 */
62 private JasperReport getJasperReportFromFile(final String reportKey) throws IOException, JRException {
63 String filePath = jasperReportPath + reportKey + ".jrxml";//图省事只支持jrxml的
64 InputStream jasperFileIS = null;
65 JasperReport jasperReport = null;
66
67 try {
68 jasperFileIS =this.getClass().getClassLoader().getResourceAsStream(filePath);
69 if (jasperFileIS == null) {
70 throw new ReportException("报表文件不存在:" + filePath);
71 }
72
73 JasperDesign jasperDesign = JRXmlLoader.load(jasperFileIS);
74 jasperReport = JasperCompileManager.compileReport(jasperDesign);
75 } finally {
76 if (jasperFileIS != null) {
77 jasperFileIS.close();
78 }
79 }
80
81 return jasperReport;
82 }
83
84 public String getJasperReportPath() {
85 return jasperReportPath;
86 }
87
88 public void setJasperReportPath(String jasperReportPath) {
89 this.jasperReportPath = jasperReportPath;
90 }
91
92 public static void main(String[] argv) {
93
94 }
95
96 }
以上就可以产生中间文件了,接下来就是按照spring的view规范写一个导出各种格式的视图就可以了
01 public class ReportView extends AbstractView {
02 private static final Log logger = LogFactory.getLog(ReportView.class);
03 private static final String XLS = "xls";
04 private static final String PDF = "pdf";
05 private static final String CSV = "csv";
06 private static final String REPORT_NAME = "reportName";
07 private static final String FORMAT = "format";
08 private static final String REPORT_PRINT = "reportPrint";
09 private static final String HTML = "html";
10
11 private static Map<String, IReportFileExporter> EXPORTER_MAP =
12 new HashMap<String, IReportFileExporter>(4);
13
14 static {
15 EXPORTER_MAP.put(XLS, new ReportXlsExporter());
16 EXPORTER_MAP.put(PDF, new ReportPdfExporter());
17 EXPORTER_MAP.put(CSV, new ReportCsvExporter());
18 EXPORTER_MAP.put(HTML, new ReportHtmlExporter());
19 }
20
21 @Override
22 protected void renderMergedOutputModel(Map model, HttpServletRequest request,
23 HttpServletResponse response) {
24 String reportName = (String) model.get(REPORT_NAME);//报表的文件名
25 String format = (String) model.get(FORMAT);//报表的格式pdf xls .....
26 ReportPrint reportPrint = (ReportPrint) model.get(REPORT_PRINT);//这就是之前生成的中间文件
27 response.setContentType("application/x-msdown;charset=utf-8");
28 try {
29 /* http头里的文件名貌似不支持utf-8,gbk之类的编码,需要转换一下
30 * 另外发现如果用new String(reportName.getBytes("UTF-8"), "iso-8859-1")的话Chrome和FF的
31 * 下载对话框的文件名是正常的,IE却是乱码,只能用GBK才正常
32 */
33 response.setHeader("Content-Disposition","attachment;filename=\"" +
34 new String(reportName.getBytes("GBK"),"iso-8859-1") + "\"");
35 } catch (UnsupportedEncodingException e) {
36 logger.error(null, e);
37 }
38 exportFile(reportPrint, format, response);
39 }
40
41 private void exportFile(ReportPrint reportPrint, String format, HttpServletResponse response) {
42 try {
43 _exportFile(reportPrint, format, response);
44 } catch (JRException e) {
45 logger.error("导出报表异常", e);
46 } catch (IOException e) {
47 logger.error(null, e);
48 }
49 }
50
51 private void _exportFile(ReportPrint reportPrint, String format, HttpServletResponse response) throws IOException, JRException {
52 OutputStream buffOS = null;
53
54 try {
55 buffOS = newBufferedOutputStream(response.getOutputStream());
56 IReportFileExporter exporter = null;
57
58 if (EXPORTER_MAP.containsKey(format)) {
59 exporter = EXPORTER_MAP.get(format);//获取需要格式的导出类
60 exporter.export(reportPrint, buffOS);
61 } else {
62 logger.error("错误的报表格式:" + format);
63 }
64 } finally {
65 if (buffOS != null) {
66 buffOS.close();
67 }
68 }
69 }
70
71 }
导出器是一个简单的接口,各种格式只要实现export方法就可以了
1 public interface IReportFileExporter {
2 public void export(ReportPrint reportPrint, OutputStream os) throwsJRException;
3 }
给一个导出PDF格式的例子,很简单
01 public class ReportPdfExporter implements IReportFileExporter {
02
03 public void export(ReportPrint reportPrint, OutputStream os) throwsJRException {
04 JRPdfExporter exporter = new JRPdfExporter();
05 exporter.setParameter(JRExporterParameter.JASPER_PRINT, reportPrint.getJasperPrint());
06 exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, os);
07 exporter.exportReport();
08 }
09
10 }
匿名用户
2016-01-19
展开全部
最近要用JasperReport,试着和spring集成了一下,现总结如下:

spring提供了几种对应JasperReport的view,可以在spring的bean定义文件
中按需要定义好,在spring的controller中对报表数据进行填充,然后返回
ModelAndView就可以了,这样就和spring的MVC集成在一起了。
详细信息可以参看spring包中带的spring reference文档。

我是这么配置的,定义报表的ViewResolver:

Xml代码
<bean id="reportViewResolver" class="org.springframework.web.servlet.view.XmlViewResolver">
<property name="order" value="1"/>
<property name="location" value="/WEB-INF/reports.xml"/>
</bean>

spring可以定义多个ViewResolver,对于普通的jsp的view,还需要如下定义一个ViewResolver:

Xml代码
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
</bean>

报表的ViewResolver中引用的reports.xml在后面会说到。

对于报表的数据的填充,我试验了三种方式如下:

1. 直接指定DataSource

可以在View的定义时,直接指定DataSource,这时我们就不需要再获取数据对
报表进行填充,报表会自动从DataSource获取数据库连接,然后通过报表定义
中的SQL语句获取数据。在reports.xml中是这样定义的:

Xml代码
<bean id="datasourceCustomerReport" class="org.springframework.web.servlet.view.jasperreports.JasperReportsMultiFormatView">
<property name="url" value="/pages/report/report1.jasper" />
<property name="jdbcDataSource" ref="dataSource" />
</bean>

其中dataSource就是一般系统中定义的DataSource bean。spring refernce中
报表的ViewResolver用的是ResourceBundleViewResolver,View的定义是在一个
properties文件中完成的,但是我没找到在properties文件中指定jdbcDataSource
属性为一spring的bean(dataSource)的方法,所以用的是xml文件定义的方法。

这时controller的处理非常简单,没有获取数据的处理,代码如下:

Java代码
@RequestMapping(value = "/datasourceCustomer", method = RequestMethod.POST)
public ModelAndView datasourceCustomerReport(HttpServletRequest request) {
Map<String, String> model = new HashMap<String, String>();

//这段代码是按用户操作分别返回pdf和excel格式的报表
if (request.getParameter("excel") != null) {
model.put("format", "xls");
} else {
model.put("format", "pdf");
}

return new ModelAndView("datasourceCustomerReport", model);
}

这种方法代码很简单,但是有一个问题,就是生成报表时的数据库操作,不在
spring的事务管理下,所以并不适用需要严格的事务管理的情况。

2. 通过的Hibernate Dao中获取数据

这种方式view的定义只要指定class和url就可以了,reports.xml中的定义如下:

Xml代码
<bean id="customerReport" class="org.springframework.web.servlet.view.jasperreports.JasperReportsMultiFormatView">
<property name="url" value="/pages/report/report1.jasper" />
</bean>

这种方式是通过Hibernate Dao获取Collection类型的数据,然后保存在给View
的model中,Spring会自动寻找Collection类型的对象作为报表填充的数据。
Controller的代码如下:

Java代码
@RequestMapping(value = "/customer", method = RequestMethod.POST)
public ModelAndView customerReport(HttpServletRequest request) {
Map<String, Object> model = new HashMap<String, Object>();
List data = reportService.customerReport();
model.put("data", data);

...

return new ModelAndView("customerReport", model);
}

其中reportService通过Hibernate Dao获取数据,Dao中代码如下:

Java代码
@Override
public List customerReport() {
Session session = sessionFactory.getCurrentSession();

return session.createCriteria(CustomerBaseInfo.class).list();
}

此时,我们可以在service层定义Transaction,保证了事务管理。

但这种方式也有感觉不好的地方,如果我只是需要某个表的某几个字段,但这种
方法会把所有字段的数据都取出来,这是一种对系统资源的浪费,所以我又试
验了第三种方法:

3. 通过JdbcTemplate Dao获取数据

这种方式View的定义和Controller中的处理没什么变化,Controller中也是通过
service获取数据,但是service是通过一个JdbcTemplate的Dao获取的数据,这个
Dao的代码如下:

Java代码
public class ReportDaoImpl implements ReportDao {

private JdbcTemplate jdbcTemplate;

public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}

@Override
public List jdbcCustomerReport() {
return jdbcTemplate.queryForList("select name, listlaiyuan, yejie from customerbaseinfo");
}
}

通过这种方式,我们可以直接通过SQL语句或者存储过程灵活地获取数据,而且
由于HibernateTransactionManager能够检查到DataSource发起的数据库访问,所以
我们可以与系统中的其他Hibernate Dao一起用HibernateTransactionManager来
管理事务。

以上就是我试验的三种方式,三种方式各有侧重,可以根据具体情况选用。

以下附加上事务管理的定义:

Xml代码
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>

<tx:annotation-driven />

以及JdbcTemplate Dao的定义

Xml代码
<bean id="reportDao" class="daos.impl.ReportDaoImpl">
<property name="dataSource" ref="dataSource" />
</bean>
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式