SpringBoot 集成 Birt

需求

BIRT 一般是可以通过单独部署一个Webviewer的工程来处理客户的report查看请求.但是有些需求可能是根据业务规则定制查询条件生成report,然后定期生成report放在数据库里,供客户查询或是report通过邮件发给客户。

目标

  • 生成的report为PDF,存在硬盘上
  • report可以接收参数
  • report调用Javacode来获取数据集

Sample - car report

开发一个report,内容显示车辆的年份,型号,厂商。数据如下

    static List cars;
	static{
		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");
		cars = Arrays.asList(  car1, car2, car3 ) ;
	}

步骤

  1. 下载download birt开发工具 http://download.eclipse.org/birt/downloads 选All in one,安装后打开BIRT.exe

  2. File->new->New Report , 新建立一个report,命名为Car.rptdesign

  3. 在Outline里找到Data set,新建DataSet,在OutPut columns填入

  • Year type选Interger
  • model type选String
  • make type选String
  1. 在Outline里找到Data source,新键DataSource,在下拉框里选Scripted Data Source,Scripted Data Source是指通过script来获取到数据源。

  2. 在Outline里找到刚刚建立Data set,双击找到DataSource,关联上刚刚建立的DataSource。Data set 是指从DataSource来组装出需要的数据集合。
    例如:

DataSource 返回

userId firstname lastname
1 zhang san
2 Li si

Data set 则组装成

userId name
1 zhang san
2 Li si
  1. 在Outline里找到Report Parameters,新建立一个参数为year,Data type为String,Display type为Text Box
    SpringBoot 集成 Birt_第1张图片

  2. 在Outline里找到Body,在Outline里找到Rport Items里,拖动一个Table到右侧的layout里,会自动弹出对话框,DataSet选刚才的建立的DataSet,选中binding columns

预览report,可以在birt里选window->preference->web browser,勾上use external web browser ,在下面的选项框里选你的浏览器。然后在工具栏里选择播放标志的下拉选view report as html或其它的选项

到这里一个简单的Report就建立好了

  1. 代码在github上,可以下载下来对照理解java 工程如下图
    SpringBoot 集成 Birt_第2张图片
    有必要的代码说明如下:
  • pom.xml
    注意
    a) org.eclipse.birt.runtime:org.eclipse.orbit.mongodb排除掉,不然会启动报错
    b) 加入org.hectorclient:hector-core .在Birt中创建Datasource的时候,下拉框里要选Scripted Data Source,不要默认选第一个,第一个是Cassandra Scrpted Data Source.就需要加入这个包。

	org.eclipse.birt.runtime
	org.eclipse.birt.runtime
	4.4.2
	
        
            org.eclipse.birt.runtime
            org.eclipse.orbit.mongodb
        
	

  • BirtEngineFactory
public class BirtEngineFactory implements FactoryBean, ApplicationContextAware, DisposableBean {   public IReportEngine getObject(){ 

		EngineConfig config = new EngineConfig();
		
		//config.getAppContext()是个map
		//将ApplicationContext放到map里,key为pring
		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 ;
	} 
}
  • BirtConfiguration
public class BirtConfiguration {
	@Value("${birt.log.location}")
	String logLocation;

    //产生FactoryBean
    //在使用的依赖IReportEngine注入时候会调用到
	@Bean
	protected BirtEngineFactory engine(){ 
		BirtEngineFactory factory = new BirtEngineFactory() ;  
		//Enable BIRT Engine Logging
		factory.setLogLevel( Level.INFO);
		factory.setLogDirectory( new FileSystemResource(logLocation));
		return factory ; 
	}
}
  • BirtController

通过http//127.0.0.1/report/car/{searchBy}/{seachValue} 来生成car report,url中的占位符代表查询的条件和值


@RestController
public class BirtController {
    @Autowired
    BirtReportGenerator birtReportGenerator;

    Logger logger = LoggerFactory.getLogger(BirtController.class);

    @PostMapping("/report/car/{searchBy}/{seachValue}")
    public void test(@PathVariable("searchBy") String searchBy,@PathVariable("seachValue") String searchValue){
        ReportParameter rm=new ReportParameter("car","PDF");
        rm.setParameter(searchBy, searchValue);
        try {
            ByteArrayOutputStream baos=birtReportGenerator.generate(rm);
            FileOutputStream fops = new FileOutputStream("c:/test/carreport_"+System.currentTimeMillis()+".pdf");
            fops.write(baos.toByteArray());
            fops.close();
            baos.close();
        } catch (Exception e) {
            logger.error("Error: " + e.getMessage());
        }
    }
}
  • BirtReportGenerator
public class BirtReportGenerator {
    @Autowired
    private IReportEngine birtEngine ;

    public ByteArrayOutputStream generate(ReportParameter rptParam) throws Exception{
        //ByteArrayOutputStream 底层维护了一个byte[],可以自动扩容
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        IReportRunnable runnable = null;
       ClassPathResource cpr=new ClassPathResource("report/car.rptdesign");
        runnable = birtEngine
                .openReportDesign(cpr.getInputStream());
        IRunAndRenderTask runAndRenderTask = birtEngine.createRunAndRenderTask(runnable);
        runAndRenderTask.setParameterValues(setParameters(runnable, rptParam.getParameter()));

        IRenderOption options =new RenderOption();
        if (rptParam.getFormat().equalsIgnoreCase("pdf")) {
            PDFRenderOption pdfOptions = new PDFRenderOption(options);
            pdfOptions.setOutputFormat("pdf");
            pdfOptions.setOption(IPDFRenderOption.PAGE_OVERFLOW, IPDFRenderOption.FIT_TO_PAGE_SIZE);
            pdfOptions.setOutputStream(baos);
            runAndRenderTask.setRenderOption(pdfOptions);
        }
        runAndRenderTask.getAppContext().put(EngineConstants.APPCONTEXT_CLASSLOADER_KEY,
                this.getClass().getClassLoader());
        runAndRenderTask.run();
        runAndRenderTask.close();
        return baos;
    }


    protected HashMap setParameters(IReportRunnable report, Map m) throws Exception {

        HashMap parms = new HashMap();
      
        IGetParameterDefinitionTask task = birtEngine.createGetParameterDefinitionTask(report);
        //拿到birt里所有的parameter定义
        Collection params = task.getParameterDefns(true);
        Iterator iter = params.iterator();
        while (iter.hasNext()) {
            IParameterDefnBase param = (IParameterDefnBase) iter.next();
            Object val=m.get(param.getName());
            //如果拿到birt的parameter有定义
            if (val!=null) {
                parms.put(param.getName(),val);
            }
        }
        task.close();
        return parms;
    }
  1. Birt里建立的Car.rptdesign这个文件放到java工程的resouces/report里

  2. 整体流程

http//127.0.0.1/report/car/year/2000->
BirtController->BirtReportGenerator->IReportEngine

IReportEngine在factorybean里的getObject()里就将spring的applicationContext对象放到了IReportEngine的config里,代码

EngineConfig config = new EngineConfig();
config.getAppContext().put("spring", this.context );

而这个context是可以在Car.rptdesign的script里使用的

以下介绍Birt的script调用java工程里的代码

  1. 在Birt里打开Car.rptdesign,在Outline里找到Scripts,点Car.rptdesign,然后在右边的窗口里切换到script,在左上放的script下来里找达到initialize,然后输入以下代码
spring=reportContext.getAppContext().get("spring");
var carService=spring.getBean("carService");

如图
SpringBoot 集成 Birt_第3张图片

  1. 在Birt里打开Car.rptdesign,在Outline里找到dataset,然后在右边的窗口里切换到script,在左上的script下来里找到open,然后输入以下代码
var carService=spring.getBean("carService");
listdata=carService.getCarsByYear(params["year"]);
count=0;

如图
SpringBoot 集成 Birt_第4张图片

在左上的script下来里找到fetch,然后输入以下代码

count=0;
if (listdata.size()>count) {
car=listdata.get(count);
row.year=car.getYear();
row.mode=car.getMode();
row.make=car.getMake();
count++;
return true;
}
return false;

如图
SpringBoot 集成 Birt_第5张图片

运行

通过postman来测试
  • 启动Bootstrap工程
  • 代开postman,输入http://127.0.0.1:8080/report/car/year/2000
  • 查看c:/test/ 下会生产carreport_xxxxx.pdf
通过springtest测试
  • 在src/main/test里增加一个测试类
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class DemoApplicationTests {
    @Autowired
    private MockMvc mvc;
    @Test
    public void exampleTest() throws Exception {
        this.mvc.perform(post("/report/car/year/2000")).andExpect(status().isOk())
                .andExpect(content().string("Hello World"));
    }
}

发生异常排除

查看log,log 配置在application.properties里的birt.log.location=c:/logs/

参考文档

  • https://spring.io/blog/2012/01/30/spring-framework-birt
  • https://www.eclipse.org/birt/documentation/integrating/reapi.php
  • https://docs.spring.io/spring-boot/docs/2.1.1.RELEASE/reference/htmlsingle/#boot-features-testing-spring-boot-applications-testing-with-mock-environment

最后再放上github代码

你可能感兴趣的:(BIRT)