Pelaporan BIRT dengan Spring Boot

1. Pengenalan

Dalam tutorial ini, kita akan mengintegrasikan BIRT (Business Intelligence and Reporting Tools) dengan Spring Boot MVC, untuk melayani laporan statik dan dinamik dalam format HTML dan PDF.

2. Apa itu BIRT ?

BIRT adalah mesin sumber terbuka untuk membuat visualisasi data yang dapat diintegrasikan ke dalam aplikasi web Java.

Ini adalah projek perisian peringkat teratas dalam Yayasan Eclipse dan memanfaatkan sumbangan oleh IBM dan Innovent Solutions. Ia dimulakan dan ditaja oleh Actuate pada akhir tahun 2004.

Kerangka kerja memungkinkan pembuatan laporan yang disatukan dengan berbagai sumber data.

3. Pergantungan Maven

BIRT mempunyai dua komponen utama: perancang laporan visual untuk membuat fail reka bentuk laporan, dan komponen jangka masa untuk menafsirkan dan membuat reka bentuk tersebut.

Dalam aplikasi web contoh kami, kami akan menggunakan kedua-duanya di atas Spring Boot.

3.1. Pergantungan Rangka Kerja BIRT

Oleh kerana kita terbiasa berfikir dalam hal pengurusan ketergantungan, pilihan pertama adalah mencari BIRT di Maven Central.

Walau bagaimanapun, versi rasmi perpustakaan teras yang tersedia ialah 4.6 dari 2016 , sementara di halaman muat turun Eclipse, kita dapat mencari pautan untuk sekurang-kurangnya dua versi yang lebih baru ( yang sekarang ialah 4.8 ).

Sekiranya kita memilih untuk mendapatkan versi rasmi, cara termudah untuk menjalankan kod adalah dengan memuat turun pakej BIRT Report Engine, yang merupakan aplikasi web lengkap yang juga berguna untuk belajar. Kami kemudian perlu menyalin folder lib ke dalam projek kami (berukuran sekitar 68MB) dan memberitahu IDE untuk memasukkan semua balang di dalamnya.

Sudah tentu , dengan menggunakan pendekatan ini, kita akan dapat menyusun hanya melalui IDE , kerana Maven tidak akan menemui balang tersebut kecuali kita mengkonfigurasi dan memasangnya secara manual (lebih dari 100 fail!) Di repo tempatan kita.

Nasib baik, Innovent Solutions telah memutuskan untuk menguruskan masalahnya dan menerbitkan di Maven Central binaan tanggungan BIRT terbaru, yang sangat bagus, kerana ia menguruskan semua pergantungan yang diperlukan.

Membaca komen dalam forum dalam talian, tidak jelas sama ada artifak ini sudah siap untuk dihasilkan, tetapi Innovent Solutions mengusahakan projek di sebelah pasukan Eclipse sejak awal, jadi projek kami bergantung pada mereka.

Termasuk BIRT kini sangat mudah:

 com.innoventsolutions.birt.runtime org.eclipse.birt.runtime_4.8.0-20180626 4.8.0 

3.2. Pergantungan Spring Boot

Sekarang BIRT diimport ke dalam projek kami, kami hanya perlu menambahkan pergantungan Spring Boot standard dalam fail pom kami.

Terdapat satu perangkap, kerana jar BIRT mengandungi pelaksanaan Slf4J sendiri , yang tidak bermain dengan baik dengan Logback dan membuang pengecualian konflik semasa permulaan.

Oleh kerana kita tidak dapat mengeluarkannya dari balang, untuk menyelesaikan masalah ini, kita perlu mengecualikan Logback :

 org.springframework.boot spring-boot-starter-logging   ch.qos.logback logback-classic   

Sekarang kita akhirnya bersedia untuk memulakan!

4. Laporan BIRT

Dalam kerangka BIRT, laporan adalah file konfigurasi XML yang panjang , yang dikenal pasti oleh rptdesign peluasan .

Ini memberitahu Engine apa yang harus dilukis dan di mana , dari gaya tajuk hingga sifat yang diperlukan untuk menyambung ke sumber data.

Untuk laporan dinamik asas, kita perlu mengkonfigurasi tiga perkara:

  1. sumber data (dalam contoh kami menggunakan fail CSV tempatan, tetapi dengan mudah boleh menjadi jadual pangkalan data)
  2. elemen yang ingin kita paparkan (carta, jadual, dll)
  3. reka bentuk halaman

Laporan ini disusun seperti halaman HTML, dengan tajuk, isi, footer, skrip, dan gaya.

Kerangka ini menyediakan sekumpulan komponen yang luas untuk dipilih dari luar kotak , termasuk integrasi ke sumber data arus perdana, susun atur, carta, dan tabel. Dan, kita boleh memperluasnya untuk menambahkan sendiri!

Terdapat dua cara untuk menghasilkan fail laporan: visual atau programatik.

5. Pereka Laporan Gerhana

Untuk memudahkan pembuatan laporan, pasukan Eclipse membina plugin alat reka bentuk laporan untuk IDE yang popular.

Alat ini mempunyai antara muka seret & lepas yang mudah dari Palet di sebelah kiri, yang secara automatik membuka tetingkap persediaan untuk komponen baru yang kita tambahkan ke halaman. Kita juga dapat melihat semua penyesuaian yang tersedia untuk setiap komponen dengan mengkliknya di halaman dan kemudian pada butang Editor Properti (disorot pada gambar di bawah).

Untuk menggambarkan keseluruhan struktur halaman dalam paparan pokok, kita hanya perlu mengklik butang Garis Besar .

The Data Explorer tab juga mengandungi sumber data yang ditetapkan untuk laporan kami:

Contoh laporan yang dipaparkan dalam gambar dapat ditemukan di jalan /reports/csv_data_report.rptdesign

Kelebihan lain untuk memilih pereka visual adalah dokumentasi dalam talian, yang lebih memfokuskan pada alat ini dan bukannya pendekatan program.

Sekiranya kita sudah menggunakan Eclipse, kita hanya perlu memasang plugin BIRT Report Design , yang merangkumi perspektif yang telah ditentukan dan editor visual.

Bagi pembangun yang tidak menggunakan Eclipse dan tidak mahu beralih, terdapat pakej Eclipse Report Designer , yang terdiri daripada pemasangan Eclipse mudah alih dengan plugin BIRT yang telah dipasang sebelumnya.

Setelah fail laporan selesai, kami dapat menyimpannya dalam projek kami dan kembali ke pengekodan di persekitaran pilihan kami.

6. Pendekatan Berprogram

Kami juga dapat merancang laporan dengan hanya menggunakan kod , tetapi pendekatan ini jauh lebih sukar kerana dokumentasi yang lemah tersedia, jadi bersiaplah untuk menggali kod sumber dan forum dalam talian.

Juga perlu dipertimbangkan adalah bahawa semua butiran reka bentuk yang membosankan seperti ukuran, panjang, dan kedudukan grid jauh lebih mudah ditangani dengan menggunakan pereka .

Untuk membuktikan perkara ini, berikut adalah contoh cara menentukan halaman statik sederhana dengan gambar dan teks:

DesignElementHandle element = factory.newSimpleMasterPage("Page Master"); design.getMasterPages().add(element); GridHandle grid = factory.newGridItem(null, 2, 1); design.getBody().add(grid); grid.setWidth("100%"); RowHandle row0 = (RowHandle) grid.getRows().get(0); ImageHandle image = factory.newImage(null); CellHandle cell = (CellHandle) row0.getCells().get(0); cell.getContent().add(image); image.setURL("\"//www.baeldung.com/wp-content/themes/baeldung/favicon/favicon-96x96.png\""); LabelHandle label = factory.newLabel(null); cell = (CellHandle) row0.getCells().get(1); cell.getContent().add(label); label.setText("Hello, Baeldung world!");

Kod ini akan menghasilkan laporan yang mudah (dan jelek):

Contoh laporan yang ditunjukkan dalam gambar di atas boleh didapati di jalan ini: /reports/static_report.rptdesign.

Setelah kami membuat pengekodan bagaimana tampilan laporan dan data apa yang harus dipaparkan, kami dapat menghasilkan fail XML dengan menjalankan kelas ReportDesignApplication .

7. Melampirkan Sumber Data

Kami sebutkan sebelumnya bahawa BIRT menyokong banyak sumber data yang berbeza.

Untuk projek contoh kami, kami menggunakan fail CSV ringkas dengan tiga entri. Ia boleh didapati di folder laporan dan terdiri daripada tiga baris data sederhana, ditambah tajuk:

Student, Math, Geography, History Bill, 10,3,8 Tom, 5,6,5 Anne, 7, 4,9

7.1. Mengkonfigurasi Sumber Data

Untuk membiarkan BIRT menggunakan fail kami (atau jenis sumber lain), kami harus mengkonfigurasi Sumber Data .

Untuk fail kami, kami membuat Sumber Data Fail Datar dengan pereka laporan, semuanya hanya dalam beberapa langkah:

  1. Open the designer perspective and look at the outline on the right.
  2. Right-click on the Data Sources icon.
  3. Select the desired source type (in our case the flat file source).
  4. We can now choose either to load an entire folder or just one file. We used the second option (if our data file is in CSV format, we want to make sure to use the first line as column name indicator).
  5. Test the connection to make sure the path is correct.

We attached some pictures to show each step:

7.2. The Data Set

The data source is ready, but we still need to define our Data Set, which is the actual data shown in our report:

  1. Open the designer perspective and look at the outline on the right.
  2. Right-click on the Data Sets icon.
  3. Select the desired Data Source and the type (in our case there's only one type).
  4. The next screen depends on the type of data source and data set we're selected: in our case, we see a page where we can select the columns to include.
  5. Once the setup is complete, we can open the configuration at any time by double-clicking on our data set.
  6. In Output Columns, we can set the right type of the data displayed.
  7. We can then look at a preview by clicking on Preview Results.

Again, some pictures to clarify these steps:

7.3. Other Data Source Types

As mentioned in step 4 of the Data Set configuration, the options available may change depending on the Data Source referred.

For our CSV file, BIRT gives options related to which columns to show, the data type, and if we want to load the entire file. On the other hand, if we had a JDBC data source, we may have to write an SQL query or a stored procedure.

From the Data Sets menu, we can also join two or more data sets in a new data set.

8. Rendering the Report

Once the report file is ready, we have to pass it to the engine for rendering. To do this, there are a few things to implement.

8.1. Initializing the Engine

The ReportEngine class, which interprets the design files and generates the final result, is part of the BIRT runtime library.

It uses a bunch of helpers and tasks to do the job, making it quite resource-intensive:

Image source: Eclipse BIRT documentation

There is a significant cost associated with creating an engine instance, due primarily to the cost of loading extensions. Therefore, we should create just one ReportEngine instance and use it to run multiple reports.

The report engine is created through a factory supplied by the Platform. Before creating the engine, we have to start the Platform, which will load the appropriate plug-ins:

@PostConstruct protected void initialize() throws BirtException { EngineConfig config = new EngineConfig(); config.getAppContext().put("spring", this.context); Platform.startup(config); IReportEngineFactory factory = (IReportEngineFactory) Platform .createFactoryObject(IReportEngineFactory.EXTENSION_REPORT_ENGINE_FACTORY); birtEngine = factory.createReportEngine(config); imageFolder = System.getProperty("user.dir") + File.separatorChar + reportsPath + imagesPath; loadReports(); }

When we don't need it anymore, we can destroy it:

@Override public void destroy() { birtEngine.destroy(); Platform.shutdown(); }

8.2. Implementing the Output Format

BIRT already supports multiple output formats:HTML, PDF, PPT, and ODT, to name a few.

For the sample project, we implemented two of them with the methods generatePDFReport and generateHTMLReport.

They differ slightly depending on the specific properties needed, such as output format and image handlers.

In fact, PDFs embed images together with text, while HTML reports need to generate them and/or link them.

Thus, the PDF rendering function is quite straightforward:

private void generatePDFReport(IReportRunnable report, HttpServletResponse response, HttpServletRequest request) { IRunAndRenderTask runAndRenderTask = birtEngine.createRunAndRenderTask(report); response.setContentType(birtEngine.getMIMEType("pdf")); IRenderOption options = new RenderOption(); PDFRenderOption pdfRenderOption = new PDFRenderOption(options); pdfRenderOption.setOutputFormat("pdf"); runAndRenderTask.setRenderOption(pdfRenderOption); runAndRenderTask.getAppContext().put(EngineConstants.APPCONTEXT_PDF_RENDER_CONTEXT, request); try { pdfRenderOption.setOutputStream(response.getOutputStream()); runAndRenderTask.run(); } catch (Exception e) { throw new RuntimeException(e.getMessage(), e); } finally { runAndRenderTask.close(); } }

While the HTML rendering function needs more settings:

private void generateHTMLReport(IReportRunnable report, HttpServletResponse response, HttpServletRequest request) { IRunAndRenderTask runAndRenderTask = birtEngine.createRunAndRenderTask(report); response.setContentType(birtEngine.getMIMEType("html")); IRenderOption options = new RenderOption(); HTMLRenderOption htmlOptions = new HTMLRenderOption(options); htmlOptions.setOutputFormat("html"); htmlOptions.setBaseImageURL("/" + reportsPath + imagesPath); htmlOptions.setImageDirectory(imageFolder); htmlOptions.setImageHandler(htmlImageHandler); runAndRenderTask.setRenderOption(htmlOptions); runAndRenderTask.getAppContext().put( EngineConstants.APPCONTEXT_BIRT_VIEWER_HTTPSERVET_REQUEST, request); try { htmlOptions.setOutputStream(response.getOutputStream()); runAndRenderTask.run(); } catch (Exception e) { throw new RuntimeException(e.getMessage(), e); } finally { runAndRenderTask.close(); } }

Most noteworthy, we set the HTMLServerImageHandler instead of leaving the default handler. This small difference has a big impact on the generated img tag:

  • the default handler links the img tag to the file system path, blocked for security by many browsers
  • the HTMLServerImageHandler links to the server URL

With the setImageDirectory method, we specify where the engine will save the generated image file.

By default, the handler generates a new file at every request, so we could add a caching layer or a deletion policy.

8.3. Publishing the Images

In the HTML report case, image files are external, so they need to be accessible on the server path.

In the code above, with the setBaseImageURL method, we tell the engine what relative path should be used in the img tag link, so we need to make sure that the path is actually accessible!

For this reason, in our ReportEngineApplication, we configured Spring to publish the images folder:

@SpringBootApplication @EnableWebMvc public class ReportEngineApplication implements WebMvcConfigurer { @Value("${reports.relative.path}") private String reportsPath; @Value("${images.relative.path}") private String imagesPath; ... @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry .addResourceHandler(reportsPath + imagesPath + "/**") .addResourceLocations("file:///" + System.getProperty("user.dir") + "/" + reportsPath + imagesPath); } }

Whatever the path we choose, we have to make sure the same path is used here and in the htmlOptions of the previous snippet, or our report won't be able to display images.

9. Displaying the Report

The last component needed to get our application ready is a Controller to return the rendered result:

@RequestMapping(method = RequestMethod.GET, value = "/report/{name}") @ResponseBody public void generateFullReport(HttpServletResponse response, HttpServletRequest request, @PathVariable("name") String name, @RequestParam("output") String output) throws EngineException, IOException { OutputType format = OutputType.from(output); reportService.generateMainReport(name, format, response, request); }

With the output parameter, we can let the user choose the desired format — HTML or PDF.

10. Testing the Report

We can start the application by running the ReportEngineApplication class.

During startup, the BirtReportService class will load all the reports found in the /reports folder.

To see our reports in action, we just need to point our browser to:

  • /report/csv_data_report?output=pdf
  • /report/csv_data_report?output=html
  • /report/static_report?output=pdf
  • /report/static_report?output=html

Here is how the csv_data_report report looks:

To reload a report after changing the design file, we just point our browser to /report/reload.

11. Conclusion

Dalam artikel ini, kami menggabungkan BIRT dengan Spring Boot, meneroka perangkap dan cabaran, tetapi juga kekuatan dan kelenturannya.

Kod sumber untuk artikel tersebut terdapat di GitHub.