领先一步
VMware 提供培训和认证,为您的进步加速。
了解更多作者:Jason Weathersby 和 Josh Long
开发人员使用 BIRT 在 Java/Java EE 环境中构建和部署报表。在 BIRT 3.7 中,提供了一个新的基于 POJO 的运行时环境,大大简化了 BIRT 引擎的部署。本文讨论了使用 Spring Framework 组件的几种 BIRT 集成场景。
图 1 – BIRT 拼贴画BIRT 项目包括以下关键组件:
Spring 框架是架构和实现方法流行的集合,可使企业级 Java 开发更加容易。该框架的核心部分是依赖注入和面向切面编程。利用这些特性可以减少应用程序基础设施特定部分与业务功能(这是其主要目标)之间的耦合。Spring 框架由 VMware 内的 SpringSource 业务部门(原 SpringSource 公司于 2009 年被 VMware 收购)以开源方式开发。它在 Java 开发社区中得到广泛使用,并可在所有平台上运行,包括 VMware 支持的 Tomcat 版本,称为 tcServer。
虽然 Spring Framework 提供了许多有用的功能,但关于与 BIRT 集成的大多数问题都围绕着 Spring MVC 和在报表内访问 Spring Bean。本文涵盖了三种场景:
本文假定读者具备 BIRT 和 Spring Framework 的编程知识。要了解有关 Spring 框架的更多信息,请查看“Green Beans”博客系列。
每种场景都有一个与本文关联的示例,该示例是使用以下组件构建和测试的:
这些示例旨在进行说明,包含很少的错误检查。
在整篇文章中,不同的集成场景都引用了一个通用的 Spring Bean,该 Bean 为 BIRT 报表提供数据。Spring Framework 包含许多复杂的数据访问组件,但这个简单的示例是学习更复杂场景的有用工具。在示例代码中,有两个包:org.eclipse.birt.spring.example 和 org.eclipse.birt.spring.core。示例包包含可以替换为您自己的数据访问对象的简单代码。核心包包含用于运行和渲染 BIRT 报表的 Spring View,一个参数转换器类用于将 URL 中输入的报表参数转换为相应的 BIRT 报表参数类型,以及一个 BIRT 引擎工厂,该工厂向其他 Bean 提供 Report Engine。示例类如下所示,并在本文中使用。核心类将在下一节中描述。
我们从一个简单的 POJO 开始,它将在我们的 BIRT 报表中使用。它命名为 Car,包含描述汽车的简单属性。
package org.eclipse.birt.spring.example;
public class Car{
private String make;
private String model;
private String year;
public String getMake() {
return make;
}
public void setMake(String make) {
this.make = make;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public String getYear() {
return year;
}
public void setYear(String year) {
this.year = year;
}
public Car() {
}
public String toString(){
return "Make:--"+this.make+" Model:--"+this.model+" Year:--"+this.year;
}
public String getCarString(){
return( this.toString() );
}
}
示例提供了一个服务类,用于加载多个 Car POJO 以用于报表目的。
package org.eclipse.birt.spring.example;
import java.util.*;
public class CarServiceImpl implements CarService {
public List getAllCars (){
Car car1 = new Car();
car1.setYear("2000");
car1.setMake("Chevrolet");
car1.setModel("Corvette");
Car car2 = new Car();
car2.setYear("2005");
car2.setMake("Dodge");
car2.setModel("Viper");
Car car3 = new Car();
car3.setYear("2002");
car3.setMake("Ford");
car3.setModel("Mustang GT");
List cars = Arrays.asList( car1, car2, car3 ) ;
return cars ;
}
}
为了在 Spring Context 中使此服务可用,我们使用一个简单的类,该类使用 Spring 注解进行配置。
package org.eclipse.birt.spring.example;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class BirtDataServiceConfiguration {
@Bean
public CarService carService(){
return new CarServiceImpl();
}
}
有许多方法可以将 BIRT 引擎集成到 Spring 中,特别是 Spring MVC。对于本例,我们实现了一个 Spring View,它使用参数来确定用户所需的报表和输出格式。BIRT 报表引擎被注入到 View 中,以执行报表的实际运行和渲染。
BIRT 引擎可以被多个线程使用,但启动通常很耗时。理想情况下,我们只希望在应用程序生命周期内启动 BIRT 引擎一次。我们还希望在应用程序关闭时正确地关闭引擎。考虑到这一点,我们首先创建了一个 BirtEngineFactory 类,它充当工厂 Bean,其他 Bean 可以使用它来返回 BIRT 报表引擎的实例。在 Spring 中,FactoryBean 接口是复杂对象的智能构造器。它有一个重要的契约:从其 getObject 方法返回一个随时可用的对象。
package org.eclipse.birt.spring.core;
import java.io.File;
import java.io.IOException;
import org.eclipse.birt.core.exception.BirtException;
import org.eclipse.birt.core.framework.Platform;
import org.eclipse.birt.report.engine.api.EngineConfig;
import org.eclipse.birt.report.engine.api.IReportEngine;
import org.eclipse.birt.report.engine.api.IReportEngineFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
/**
Factory bean for the instance of the {@link IReportEngine report engine}.
*/
public class BirtEngineFactory implements FactoryBean, ApplicationContextAware, DisposableBean {
public boolean isSingleton(){ return true ; }
private ApplicationContext context ;
private IReportEngine birtEngine ;
private Resource logDirectory ;
private File _resolvedDirectory ;
private java.util.logging.Level logLevel ;
public void setApplicationContext(ApplicationContext ctx){
this.context = ctx;
}
public void destroy() throws Exception {
birtEngine.destroy();
Platform.shutdown() ;
}
public void setLogLevel( java.util.logging.Level ll){
this.logLevel = ll ;
}
public void setLogDirectory( org.springframework.core.io.Resource resource ){
File f=null;
try {
f = resource.getFile();
validateLogDirectory(f);
this._resolvedDirectory = f ;
} catch (IOException e) {
throw new RuntimeException( couldnt set the log directory);
}
}
private void validateLogDirectory (File f) {
Assert.notNull ( f , " the directory must not be null");
Assert.isTrue(f.isDirectory() , " the path given must be a directory");
Assert.isTrue(f.exists() , "the path specified must exist!");
}
public void setLogDirectory ( java.io.File f ){
validateLogDirectory(f) ;
this._resolvedDirectory = f;
}
public IReportEngine getObject(){
EngineConfig config = new EngineConfig();
//This line injects the Spring Context into the BIRT Context
config.getAppContext().put("spring", this.context );
config.setLogConfig( null != this._resolvedDirectory ? this._resolvedDirectory.getAbsolutePath() : null , this.logLevel);
try {
Platform.startup( config );
}
catch ( BirtException e ) {
throw new RuntimeException ( "Could not start the Birt engine!", e) ;
}
IReportEngineFactory factory = (IReportEngineFactory) Platform.createFactoryObject( IReportEngineFactory.EXTENSION_REPORT_ENGINE_FACTORY );
IReportEngine be = factory.createReportEngine( config );
this.birtEngine = be ;
return be ;
}
@Override
public Class getObjectType() {
return IReportEngine.class;
}
}
该类还实现了 DisposableBean 接口,以便在应用程序关闭时可以正确关闭引擎。当 Spring ApplicationContext 关闭时,Spring 会调用所有实现 DisposableBean 的 Bean 上的 DisposableBean#destroy 方法。我们的实现调用了 destroy 方法。最后,该类实现了 ApplicationContextAware 接口,以接收 Spring ApplicationContext 的实例。我们存储 ApplicationContext,然后使用以下代码将其传递给 BIRT Report Engine:
EngineConfig config = new EngineConfig();
//This line injects the Spring Context into the BIRT Context
config.getAppContext().put("spring", this.context );
此代码将允许从 BIRT Scripting 和 Expressions 内部访问 Spring Context 对象。
接下来,我们创建一个 Spring View,它运行并渲染报表。此 View 期望注入 BIRT 报表引擎。该 View 搜索请求中的 ReportName 和 ReportFormat 参数,以决定运行哪个报表以及需要什么格式。请求中还会搜索报表参数名称。如果找到,这些报表参数将设置为相应的值。此 View 的一部分如下所示。有关更多信息,请参阅示例代码。
/**
* BirtView is used to run and render BIRT reports.
* This class expects the request to contain a ReportName and ReportFormat
* parameter. In addition Report parameters are automatically searched for in the
* the request object.
*/
public class BirtView extends AbstractView {
public static final String PARAM_ISNULL = "__isnull";
public static final String UTF_8_ENCODE = "UTF-8";
private IReportEngine birtEngine;
private String reportNameRequestParameter = ReportName ;
private String reportFormatRequestParameter = ReportFormat ;
private IRenderOption renderOptions ;
public void setRenderOptions(IRenderOption ro) {
this.renderOptions = ro;
}
public void setReportFormatRequestParameter( String rf ){
Assert.hasText( rf , the report format parameter must not be null) ;
this.reportFormatRequestParameter = rf ;
}
public void setReportNameRequestParameter ( String rn ) {
Assert.hasText( rn , the reportNameRequestParameter must not be null) ;
this.reportNameRequestParameter = rn ;
}
protected void renderMergedOutputModel(
Map map, HttpServletRequest request,
HttpServletResponse response) throws Exception {
String reportName = request.getParameter( this.reportNameRequestParameter );
String format = request.getParameter( this.reportFormatRequestParameter );
ServletContext sc = request.getSession().getServletContext();
if( format == null ){
format="html";
}
IReportRunnable runnable = null;
runnable = birtEngine.openReportDesign( sc.getRealPath("/Reports")+"/"+reportName );
IRunAndRenderTask runAndRenderTask = birtEngine.createRunAndRenderTask(runnable);
runAndRenderTask.setParameterValues(discoverAndSetParameters( runnable, request ));
response.setContentType( birtEngine.getMIMEType( format ));
IRenderOption options = null == this.renderOptions ? new RenderOption() : this.renderOptions;
if( format.equalsIgnoreCase("html")){
HTMLRenderOption htmlOptions = new HTMLRenderOption( options);
htmlOptions.setOutputFormat("html");
htmlOptions.setOutputStream(response.getOutputStream());
htmlOptions.setImageHandler(new HTMLServerImageHandler());
htmlOptions.setBaseImageURL(request.getContextPath()+"/images");
htmlOptions.setImageDirectory(sc.getRealPath("/images"));
runAndRenderTask.setRenderOption(htmlOptions);
}else if( format.equalsIgnoreCase("pdf") ){
PDFRenderOption pdfOptions = new PDFRenderOption( options );
pdfOptions.setOutputFormat("pdf");
pdfOptions.setOption(IPDFRenderOption.PAGE_OVERFLOW, IPDFRenderOption.FIT_TO_PAGE_SIZE);
pdfOptions.setOutputStream(response.getOutputStream());
runAndRenderTask.setRenderOption(pdfOptions);
}else{
String att ="download."+format;
String uReportName = reportName.toUpperCase();
if( uReportName.endsWith(".RPTDESIGN") ){
att = uReportName.replace(".RPTDESIGN", "."+format);
}
response.setHeader( "Content-Disposition", "attachment; filename=\"" + att + "\"" );
options.setOutputStream(response.getOutputStream());
options.setOutputFormat(format);
runAndRenderTask.setRenderOption(options);
}
runAndRenderTask.getAppContext().put( EngineConstants.APPCONTEXT_BIRT_VIEWER_HTTPSERVET_REQUEST, request );
runAndRenderTask.run();
runAndRenderTask.close();
}
public void setBirtEngine(IReportEngine birtEngine) {
this.birtEngine = birtEngine;
}
.
.
要设置 Spring MVC(并在我们的应用程序中使用此新 View),我们需要创建一个带有 @EnableWebMVC 注解的 Spring @Configuration 类。要覆盖 Spring MVC 机制的一部分,我们可以简单地扩展一个基类 - WebMvcConfigurerAdapter - 并钩入适当的回调方法。这个类是一个常规的 Spring @Configuration 类,就像我们之前配置服务时看到的那样。我们使用 @ComponentScan 注解来告诉 Spring 将来自我们两个包的带注解的 bean 注册到 Spring context。接下来,我们覆盖 addViewControllers 方法,告诉 Spring 将以“/reports”结尾的 URL 委托给新的 Birt Spring MVC View。birtView 和 BIRT 引擎被创建为 bean,并且设置了 BirtView bean 的 birtEngine 属性。
package org.eclipse.birt.spring.example;
import org.eclipse.birt.spring.core.BirtEngineFactory;
import org.eclipse.birt.spring.core.BirtView;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.BeanNameViewResolver;
@EnableWebMvc
@ComponentScan( {"org.eclipse.birt.spring.core", "org.eclipse.birt.spring.example"})
@Configuration
public class BirtWebConfiguration extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/reports").setViewName("birtView");
}
@Bean
public BirtView birtView(){
BirtView bv = new BirtView();
bv.setBirtEngine( this.engine().getObject() );
return bv;
}
@Bean public BeanNameViewResolver beanNameResolver(){
BeanNameViewResolver br = new BeanNameViewResolver() ;
return br;
}
@Bean
protected BirtEngineFactory engine(){
BirtEngineFactory factory = new BirtEngineFactory() ;
//Enable BIRT Engine Logging
//factory.setLogLevel( Level.FINEST);
//factory.setLogDirectory( new FileSystemResource("c:/temp"));
return factory ;
}
}
如前所述,在描述 BIRT 引擎工厂类时,我们从 BIRT 上下文提供了对 Spring ApplicationContext 的引用。BIRT 上下文对象不过是一个对象的 Map,BIRT 引擎将其提供给下游进程,例如 BIRT 表达式、BIRT 事件处理程序等。BIRT 使用 Rhino JavaScript 引擎来处理 BIRT 表达式并评估 JavaScript 事件处理程序。BIRT 上下文与 Rhino 引擎对象一起预加载到脚本环境中。这个对象允许报表开发人员使用以下语法检索 Spring Bean 并在表达式或事件脚本中使用它:
var mypojo = spring.getBean("carService");
mypojo.getAllCars() ().get(0);
如果您不想将 Spring 上下文注入 BIRT 应用程序上下文,您总是可以使用类似于以下代码的 JavaScript 来访问 BIRT 表达式和 JavaScript 事件处理程序中的 Spring bean:
importPackage(Packages.org.springframework.context);
importPackage(Packages.org.springframework.web.context.support );
//ServletContext
var sc = reportContext.getHttpServletRequest().getSession().getServletContext();
//ApplicationContext
var spring = WebApplicationContextUtils.getWebApplicationContext(sc);
var mypojo = spring.getBean("carService");
this.text = mypojo.getAllCars().get(0).getMake();
要运行此 Web 应用,请将从下载的 BIRT 3.7.1 运行时(birt-runtime-3_7_1\ReportEngine\lib 目录)中的 JAR 文件添加到 Web 应用的 WEB-INF/lib 目录。您还需要在 WEB-INF/lib 中添加从 Spring Framework 下载的以下 JAR 文件:
本文附带的示例具有以下 web.xml 文件:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
"http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">
<web-app>
<servlet>
<servlet-name>springandbirt</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>org.eclipse.birt.spring.example.BirtWebConfiguration</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springandbirt</servlet-name>
<url-pattern>/reports</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>
index.jsp
</welcome-file>
</welcome-file-list>
</web-app>
所有 /reports URL 都路由到 Spring DispatcherServlet。index.jsp 中有两个链接,用于运行两个报表示例。一个报表使用 BIRT Sample Derby 数据库,另一个访问 Car Service bean,如以下代码所示:
<html> <head> </head> <body> <h1>BIRT Report</h1> <p> <a href="https://:8080/springandbirt/reports?ReportName=TopNPercent.rptdesign">click here to run BIRT Report</a><br> <a href="https://:8080/springandbirt/reports?ReportName=SampleSpring.rptdesign">click here to run BIRT Report that calls a Spring Bean</a> </p> <%= new java.util.Date() %> </body> </html>
图 1 – 查看 BIRT Spring MVC 示例输出在许多情况下,BIRT 用户希望将 Spring IOC 容器添加到 BIRT Viewer 中。Viewer 是一个基于 AJAX 的 Java Web 应用,用于运行和渲染报表。Viewer 支持分页、目录和导出到 PDF 等其他格式。以这种方式部署时,开发人员需要访问位于 Spring 容器中的 bean 以进行报表处理。此场景实现起来非常简单。
从 BIRT 网站下载并解压 BIRT Runtime。BIRT Viewer 位于运行时下载的 WebViewerExample 目录中。要将 Viewer 部署到 Tomcat,用户只需将 WebViewerExample 目录复制到 tomcatinstall/webapps 目录即可。大多数用户会将此文件夹重命名为更合适的名称,例如 BirtViewer。BIRT 网站提供了将 Viewer 部署到其他应用服务器的更多详细信息。安装 Viewer 后,可以将 Spring ContextLoaderListener 添加到 Viewer 的 web.xml 中。为此,请将以下监听器条目添加到 web.xml 的上下文参数下方:
<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
您还可以指定一个上下文参数来指向 Spring Context 类,如以下代码所示:
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>org.eclipse.birt.spring.webviewer.example.BirtDataServiceConfiguration</param-value>
</context-param>
在此场景中,我们不需要 BirtWebConfiguration 类,因此我们将 contextConfigLocation 指向 BirtDataServiceConfiguration 类。
本文第一节中描述的相同 POJO 类在此处使用(只是包名不同),并且需要位于 WEB-INF/classes 目录中,或者该包需要位于 JAR 文件中并放置在 Viewer 的 WEB-INF/lib 目录中。最后,将 Spring Framework 下载中的以下 JAR 文件添加到 WebViewer 的 WEB-INF/lib 目录:
要在 BIRT 表达式或 BIRT JavaScript 事件处理程序中访问 carService bean,请使用以下语法:
//BIRT label report item onCreate Script
importPackage(Packages.org.springframework.context);
importPackage(Packages.org.springframework.web.context.support );
var sc = reportContext.getHttpServletRequest().getSession().getServletContext();
//ApplicationContext
spring = WebApplicationContextUtils.getWebApplicationContext(sc);
var mypojo = spring.getBean("carService");
this.Text = mypojo.getAllCars().get(0).getMake();
图 2 - 构建 BIRT 表达式在设计器中预览报表时,BIRT 表达式或脚本会失败。为防止失败,请将表达式或脚本包装在“if”语句中,如以下代码所示:
if( !reportContext.getHttpServletRequest().getAttribute("attributeBean").isDesigner()){
//Access Bean
}
图 3 – 在 BIRT Viewer 中显示 Spring bean 输出本文前两节侧重于将 BIRT 引擎和 Viewer 与 Spring 框架集成。虽然这些方法效果很好,但假设您需要访问位于单独上下文或另一台机器上的 Spring bean。可以使用 Spring Remoting 来实现此功能。
虽然任何 Spring Remoting 技术或其他机制,如 SOAP 或 REST 都可以使用,但本节描述了使用 Spring 基于 HTTP Invoker 的服务导出器。为了实现本示例,我们首先构建一个示例 Web 应用,其中包含一个 Car Service bean,该 bean 向远程调用客户端提供 Car POJO。
对于远程调用,我们首先定义 Car POJO,如以下代码所示:
package org.eclipse.birt.spring.remoting.example;
public class Car implements ICar{
private static final long serialVersionUID = 1L;
private String make;
private String model;
private String year;
public String getMake() {
return make;
}
public void setMake(String make) {
this.make = make;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public String getYear() {
return year;
}
public void setYear(String year) {
this.year = year;
}
public Car() {
this.year = "2000";
this.make = "Chevrolet";
this.model = "Corvette";
}
public String toString(){
return "Make:--"+this.make+" Model:--"+this.model+" Year:--"+this.year;
}
}
接下来,我们实现 Car Service。
package org.eclipse.birt.spring.remoting.example;
import java.util.Arrays;
import java.util.List;
import org.eclipse.birt.spring.remoting.example.Car;
import org.eclipse.birt.spring.remoting.example.CarService;
public class CarServiceImpl implements CarService{
public List getAllCars(){
Car car1 = new Car();
car1.setYear("2000");
car1.setMake("Chevrolet");
car1.setModel("Corvette");
Car car2 = new Car();
car2.setYear("2005");
car2.setMake("Dodge");
car2.setModel("Viper");
Car car3 = new Car();
car3.setYear("2002");
car3.setMake("Ford");
car3.setModel("Mustang GT");
List cars = Arrays.asList( car1, car2, car3 ) ;
return cars ;
}
}
最后,我们实现 BirtDataServiceConfiguration 文件来处理 Spring 上下文的 Java 配置。
package org.eclipse.birt.spring.remoting.example;
import java.util.HashMap;
import java.util.Map;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
@Configuration
public class BirtDataServiceConfiguration {
@Bean
public CarService carService(){
return new CarServiceImpl();
}
@Bean
public HttpInvokerServiceExporter myServiceExporter(){
HttpInvokerServiceExporter hse = new HttpInvokerServiceExporter();
hse.setService( this.carService()) ;
hse.setServiceInterface( CarService.class);
return hse;
}
@Bean
public SimpleUrlHandlerMapping myUrlMapping(){
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
Map urlMap = new HashMap();
urlMap.put("/carService", myServiceExporter());
mapping.setUrlMap(urlMap);
mapping.setAlwaysUseFullPath(true);
return mapping;
}
}
这个类只是将 /carService URL 映射到 HttpInvokerServiceExporter 对象,该对象将 carService bean 暴露给远程调用客户端。
接下来,我们可以为这个应用程序创建一个使用 Spring DispatcherServlet 的 web.xml 文件,如以下代码所示:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
"http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">
<web-app>
<servletgt;
<servlet-name>springandbirt</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-namegt;contextClass</param-name>
<param-valuegt;org.springframework.web.context.support.AnnotationConfigWebApplicationContextlt;/param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>org.eclipse.birt.spring.remoting.example.BirtDataServiceConfiguration</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springandbirt</servlet-name>
<url-pattern>/carService</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>
index.jsp
</welcome-file>
</welcome-file-list>
</web-app>
该 Web 应用程序需要在 WEB-INF/lib 目录中包含 Spring Framework 的以下 JAR 文件:
现在可以构建和部署该应用程序了。
接下来,我们需要构建一个远程调用客户端来访问之前构建的应用程序。在此示例中,它只是一个 JAR 文件,我们可以将其包含在 BIRT Viewer 中,以便在单独的上下文访问 carService。
客户端 JAR 文件应该包含 CarService 接口和 CarPojo/ICarPojo 类/接口。除了这三个类之外,我们还需要一个配置类来处理 Spring Context 的 Java 配置。
此类使用 AnnotationConfigApplicationContext 类指定一个 Java 类来处理 Spring Context 的配置。ContextConfig 类如下所示,并使用 HttpInvokerProxyFactoryBean 连接到服务器并检索 car service bean。
package org.eclipse.birt.spring.remoting.client.example;
import org.eclipse.birt.spring.remoting.example.CarService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean;
@Configuration
public class ContextConfig {
@Bean
public HttpInvokerProxyFactoryBean client() {
HttpInvokerProxyFactoryBean proxy = new HttpInvokerProxyFactoryBean();
proxy.setServiceInterface(CarService.class);
proxy.setServiceUrl("https://:8080/springandbirtremote/carService");
return proxy;
}
}
这个配置文件定义了一个 bean,它充当 HTTP invoker 代理。服务 URL 定义了我们之前定义的远程调用服务器的位置,服务接口定义了返回的对象。要构建客户端 JAR 文件,将为服务器添加的相同 JAR 文件添加到 classpath。
要从 BIRT 查看器调用 car service,请在 BIRT Expression Builder 或 JavaScript 事件处理程序中使用以下 JavaScript 代码片段,如以下代码所示:
importPackage(Packages.org.springframework.context);
importPackage(Packages.org.springframework.web.context.support );
var sc = reportContext.getHttpServletRequest().getSession().getServletContext();
//ApplicationContext
var spring = WebApplicationContextUtils.getWebApplicationContext(sc);
var mypojo = spring.getBean("client");
mypojo.getAllCars().get(0).getMake();
将构建远程调用服务器一节中描述的所有 JAR 文件添加到 BIRT Viewer 的 WEB-INF/lib 目录。此外,将远程调用客户端 JAR 文件添加到 BIRT Viewer 的 WEB-INF/lib 目录。最后,将以下内容添加到已部署 Viewer 的 web.xml 中。这些设置在本文“从 BIRT Viewer 访问 Spring Bean”一节中进行了讨论。请注意,contextConfigLocation 已更改为 ContextConfig 类。
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>org.eclipse.birt.spring.webviewer.example.ContextConfig</param-value>
</context-param>
这种方法允许已部署的 BIRT Viewer 访问单独的机器/上下文来访问远程 bean。最后,如果您使用中间 Java 类来访问远程 Bean,请使用以下代码。
.
.
private final CarService carPojoService;
public CarPojoClient(){
final ApplicationContext context = new AnnotationConfigApplicationContext( ContextConfig.class);
this.carPojoService = (CarService) context.getBean("client");
.
.
Spring 和 BIRT 框架在 Java 社区中非常流行。许多 BIRT 技术的用户也在其企业应用程序代码中使用 Spring 功能来处理数据源、报表呈现和访问控制等功能。这些只是将 Spring Framework 与 BIRT 结合使用的一些好处。本文介绍了如何集成 BIRT 和 Spring。虽然还存在其他场景,但本文可以作为入门工具,帮助您同时使用这两种技术。
希望利用本文所述集成类的开发人员可以使用下面的 SpringandBirtCoreJar.zip 下载。对于示例,请参阅 SpringBirtArticleSamples.zip 下载。