本文共 9266 字,大约阅读时间需要 30 分钟。
项目是邮政的一个揽投项目,是我和我同学两个人做的,在这个项目中报表是一个难点,一开始想用jasper来做,因为涉及到的业务统计比较复杂,后来换成了birt,实践才发现birt确实功能强大。
有关birt的一些基本用法,这里就不啰嗦了,网上太多这样的资料了,这里谈下,birt怎么在spring里面集成。 birt有他单独的一套引擎,其强大的script支持促使其可以利用外部的数据缘,这也是集成spring的一个必要条件。 这里先看看报表要做成什么样子。 报表1: 日期 年票类 文书类 票务类 车辆类 小计 业务量 代收款总金额 业务量 代收款总金额 业务量 代收款总金额 业务量 代收款总金额 业务量 代收款总金额 2008-12-05 264 228302 255 215673.5 294 259918 813 703893.5 合计 264 228302 255 215673.5 294 259918 813 703893.5 报表2: 投递段名称 业务种类 业务量 代收款总金额 投递段010101 车辆类 44 64966 文书类 35 51348.5 年票类 34 49860 小计 113 166174.5 投递段010102 车辆类 4 5302 文书类 3 3470.5 年票类 2 2527 小计 9 11299.5 业务种类合计 年票类 36 52387 文书类 38 54819 车辆类 48 70268 总体合计 122 177474 报表3: 日期 投递段 当日业务总量 揽投成功情况 待处理 1天 2天 3天 4天 5天 6天 7天 8天 9天 10天 11天 12天 13天 14天 揽投中 2008-12-05 010101 113 24 9 79 2008-12-05 010102 9 9 揽投失败情况 日期 投递段 揽投失败3 2008-12-05 010101 1 010102 这里就不每个报表一一详述,以第一个报表做例子来详解: 看第一报表,是典型的交叉表,关于交叉表的设计,这里不啰嗦, 这个报表用的是script数据源,其中有四个参数,startDate(开始时间),endDate(结束时间),businessKind(业务种类),ranksId(投递队伍)。 1.在工程中建立一个BirtFactory单例工厂类,用于统一去获取外表的数据, /** * 提供给birt使用的Factory * * @author 3SeeFans */ public class BirtFactory { private static final Logger logger = LoggerFactory.getLogger(BirtFactory.class); private static BirtFactory instance; private static ApplicationContext context = AppContext.CONTEXT; private final StatisticsManager manager = (StatisticsManager) context.getBean("statisticsManager"); private BirtFactory() { logger.debug("Init the instance of BirtFactory..."); } public static BirtFactory getInstance() { if (instance == null) { if (context == null) { logger.debug("Get application context from birt-context.xml"); context = new ClassPathXmlApplicationContext("birt-context.xml"); } instance = new BirtFactory(); } return instance; } public List<MacroAnalysisBean> getMacroAnalysisData(Date startDate, Date endDate, Long businessKindId, Long ranksId) { return manager.getMacroAnalysisData(startDate, endDate, businessKindId, ranksId); } public List<DeliverCollectBean> getDeliverCollectData(Date startDate, Date endDate, Long businessKindId, String depId) { return manager.getDeliverCollectData(startDate, endDate, businessKindId, depId); } public List<DeliverAnalysisBean> getDeliverAnalysisData(Date startDate, Date endDate, String depId) { return manager.getDeliverAnalysisData(startDate, endDate, depId); } public List<DeliverAnalysisFailBean> getDeliverAnalysisFailData(Date startDate, Date endDate, String depId) { return manager.getDeliverAnalysisFailData(startDate, endDate, depId); } } 这里须注意点,StatisticsManager是负者业务相关的service类,配置在spring容器里, 这里birtFacotry通过两种方式得到ApplicationContext 。 第一种就是通过实现SerletContextListener得到servletContext,再通过 public static final ServletContext servletContext = AppContextLoader.getInstance().getServletContext(); public static final ApplicationContext CONTEXT = WebApplicationContextUtils .getRequiredWebApplicationContext(servletContext); 得到ApplicationContext ;通过注入的方式得到StatisticsManager。 第二种就是birt从新启动一个容器完全独立,先增加birt-context.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation="http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd" default-autowire="byName" default-lazy-init="true"> <context:property-placeholder location="classpath:init.properties" /> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}" p:username="${jdbc.username}" p:password="${jdbc.password}" /> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" p:dataSource-ref="dataSource"> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">${hibernate.dialect}</prop> <prop key="hibernate.show_sql">${hibernate.show_sql}</prop> </props> </property> </bean> <!-- 保证POJO中标注@Required的属性被注入 --> <bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor" /> <bean id="statisticsManager" class="com.gzpost.lantou.service.StatisticsManager" /> </beans> 2.配置script数据源: 在script 中的open方法加 factory = new Packages.com.gzpost.lantou.proxy.BirtFactory.getInstance(); collectList=factory.getMacroAnalysisData(params["startDate"].value,params["endDate"].value,params["businessKindId"].value,params["ranksId"].value); iterator = collectList.iterator(); fech方法中加 if(iterator.hasNext() == false ){ return false; } else{ var collectBean = iterator.next(); row["kindName"]=collectBean.getKindName(); row["acceptDate"] = collectBean.getAcceptDate(); row["totalCount"]=collectBean.getTotalCount(); row["totalPrice"]=collectBean.getTotalPrice(); return true; } colse方法中加 collectList = null; iterator = null; colectBean = null; factory=null; 这样script数据原就配置好了,很简单吧。 3.报表显示: 在jsp页面加入相应的标签 <div id="content"> <c:choose> <c:when test="${endDate!=null&&startDate!=null}"> <birt:viewer id="birtViewer" reportDesign="reports/macroAnalysis.rptdesign" format="HTML" showNavigationBar="false" width="800" height="480" left="0" top="0" showParameterPage="false" showTitle="false"> <birt:param name="startDate" value="${startDate}" /> <birt:param name="endDate" value="${endDate}" /> <birt:param name="businessKindId" value="${businessKindId}" /> <birt:param name="ranksId" value="${ranksId}" /> </birt:viewer> </c:when> </c:choose> </div> 执行相应的action就可以了。 补充: 关于第一种方式得到ApplicationContext 也就是你写个listener类实现ServletContextListener ,并实现contextInitialized方法,在里面加入AppContextLoader.getInstance().setServletContext(sc); 其中AppContextLoader代码为: /** * 用于存储ServletContext * @ * */ public class AppContextLoader { private static final Logger logger = LoggerFactory.getLogger(AppContextLoader.class); private static AppContextLoader instance; private ServletContext sc; private AppContextLoader() { logger.info("Init ServletContextLoader"); } public static AppContextLoader getInstance() { if (instance == null) { instance = new AppContextLoader(); } return instance; } public ServletContext getServletContext() { return sc; } public void setServletContext(ServletContext sc) { this.sc = sc; } } 其中context常量代码: /** * 系统context常量 * */ public abstract class AppContext { public static final ServletContext servletContext = AppContextLoader.getInstance().getServletContext(); public static final String ROOTPATH = (String) servletContext.getAttribute("rootPath"); public static final String REALPATH = (String) servletContext.getAttribute("realPath"); public static final ApplicationContext CONTEXT = WebApplicationContextUtils .getRequiredWebApplicationContext(servletContext); } 你要得到spring上下文:ApplicationContext CONTEXT = WebApplicationContextUtils .getRequiredWebApplicationContext(AppContextLoader.getInstance().getServletContext()); 就行了
另一位读者的看法:
其中,关键部分就是获得ApplicationContext的配置,通过翻转,获得配置中的service服务,以查询数据。
如何获得ApllicationContext,3seefans给了两种方式,先不说第一种。
第二种方式就是新建一个配置文件,然后通过private static ApplicationContext context = new ClassPathXmlApplicationContext("birt-context.xml");
得到配置,接着通过private final StatisticsManager manager = (StatisticsManager) context.getBean("statisticsManager"); 获得那个可以查询数据的service。
这种方法实现简单,但是却是WEB应用存在两个连接数据库的配置,上面是通过spring和hibernate结合实现的,而项目中往往还有通过连接池配置实现的,因此无法达到统一。况且上述配置的service往往也存在与项目原始配置的ApplicationContext.xml文件中,即会出现重复配置,那么,第一种方法才是一种最好的方法。
3seefans提到:“第一种就是通过实现SerletContextListener得到servletContext,再通过
public static final ServletContext servletContext = AppContextLoader.getInstance().getServletContext();
public static final ApplicationContext CONTEXT = WebApplicationContextUtils
.getRequiredWebApplicationContext(servletContext);
得到ApplicationContext ;通过注入的方式得到StatisticsManager。”
可是当我用这个方法的时候,却发现没有AppContextLoader这个类。最后,通过琢磨,用了如下的方法来实现的:
首先,编写一个类
test.birt.InitServlet,代码如下:
public class InitServlet extends HttpServlet{
private static final long serialVersionUID = 1L;
public static ServletContext SERVLET_CONTEXT;
public void init() throws ServletException
{
SERVLET_CONTEXT = getServletContext();
}
}
接着,在web.xml中加入如下代码:
<servlet>
<servlet-name>Birt config</servlet-name>
<servlet-class>test.birt.InitServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
然后,改写3seefans提供的BirtFactory中获得context的代码为:
private static ApplicationContext context = WebApplicationContextUtils
.getRequiredWebApplicationContext(InitServlet.SERVLET_CONTEXT);
这样,就可以实现birt和项目公用同一个配置文件了。
转载地址:http://ymtci.baihongyu.com/