最近要用JasperReport,试着和spring集成了一下,现总结如下:
spring提供了几种对应JasperReport的view,可以在spring的bean定义文件
中按需要定义好,在spring的controller中对报表数据进行填充,然后返回
ModelAndView就可以了,这样就和spring的MVC集成在一起了。
详细信息可以参看spring包中带的spring reference文档。
我是这么配置的,定义报表的ViewResolver:
- <bean?id="reportViewResolver"?class="org.springframework.web.servlet.view.XmlViewResolver">??
- ????<property?name="order"?value="1"/>??
- ????<property?name="location"?value="/WEB-INF/reports.xml"/>??
- </bean>??
<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:
- <bean?id="viewResolver"?class="org.springframework.web.servlet.view.InternalResourceViewResolver">??
- </bean>??
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> </bean>
报表的ViewResolver中引用的reports.xml在后面会说到。
对于报表的数据的填充,我试验了三种方式如下:
1. 直接指定DataSource
可以在View的定义时,直接指定DataSource,这时我们就不需要再获取数据对
报表进行填充,报表会自动从DataSource获取数据库连接,然后通过报表定义
中的SQL语句获取数据。在reports.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>??
<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的处理非常简单,没有获取数据的处理,代码如下:
- @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); ??
- }??
@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中的定义如下:
- <bean?id="customerReport"?class="org.springframework.web.servlet.view.jasperreports.JasperReportsMultiFormatView">??
- ????<property?name="url"?value="/pages/report/report1.jasper"?/>??
- </bean>??
<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的代码如下:
- @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); ??
- }??
@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中代码如下:
- @Override??
- public?List?customerReport()?{ ??
- ????Session?session?=?sessionFactory.getCurrentSession(); ??
- ???? ??
- ????return?session.createCriteria(CustomerBaseInfo.class).list(); ??
- }??
@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的代码如下:
- 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"); ??
- ????} ??
- }??
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来
管理事务。
以上就是我试验的三种方式,三种方式各有侧重,可以根据具体情况选用。
以下附加上事务管理的定义:
- <bean?id="transactionManager"??
- ????class="org.springframework.orm.hibernate3.HibernateTransactionManager">??
- ????<property?name="sessionFactory"?ref="sessionFactory"?/>??
- </bean>??
- ??
- <tx:annotation-driven?/>??
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <tx:annotation-driven />
以及JdbcTemplate Dao的定义
- <bean?id="reportDao"?class="daos.impl.ReportDaoImpl">??
- ????<property?name="dataSource"?ref="dataSource"?/>??
- </bean>??
<bean id="reportDao" class="daos.impl.ReportDaoImpl"> <property name="dataSource" ref="dataSource" /> </bean>
最后,希望各位大侠拍砖,呵呵