Pelaporan BIRT dengan Spring Boot

1. Perkenalan

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

2. Apakah BIRT itu ?

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

Ini adalah proyek perangkat lunak tingkat atas dalam Eclipse Foundation dan memanfaatkan kontribusi dari IBM dan Solusi Inovasi. Itu dimulai dan disponsori oleh Actuate pada akhir 2004.

Kerangka kerja ini memungkinkan pembuatan laporan yang terintegrasi dengan berbagai sumber data.

3. Ketergantungan Maven

BIRT memiliki dua komponen utama: desainer laporan visual untuk membuat file desain laporan, dan komponen runtime untuk menafsirkan dan menampilkan desain tersebut.

Dalam contoh aplikasi web kami, kami akan menggunakan keduanya di atas Spring Boot.

3.1. Ketergantungan Kerangka BIRT

Seperti yang biasa kita pikirkan tentang manajemen ketergantungan, pilihan pertama adalah mencari BIRT di Maven Central.

Namun, versi resmi terbaru dari pustaka inti yang tersedia adalah 4.6 dari tahun 2016 , sedangkan di halaman unduhan Eclipse, kami dapat menemukan tautan untuk setidaknya dua versi yang lebih baru ( yang terbaru adalah 4.8 ).

Jika kita memilih untuk menggunakan versi resmi, cara termudah untuk mengaktifkan dan menjalankan kode adalah dengan mengunduh paket BIRT Report Engine, yang merupakan aplikasi web lengkap yang juga berguna untuk belajar. Kami kemudian perlu menyalin nya lib folder ke dalam proyek kami (sekitar 68MB dalam ukuran) dan memberitahu IDE untuk mencakup semua guci di dalamnya.

Tidak perlu dikatakan bahwa, dengan menggunakan pendekatan ini, kita hanya dapat mengkompilasi melalui IDE , karena Maven tidak akan menemukan jars tersebut kecuali kita mengkonfigurasi dan menginstalnya secara manual (lebih dari 100 file!) Di repo lokal kita.

Untungnya, Solusi Inovasi telah memutuskan untuk mengambil tindakan dan menerbitkan di Maven Central bentukan sendiri dari dependensi BIRT terbaru, yang sangat bagus, karena mengelola untuk kita semua dependensi yang dibutuhkan.

Membaca komentar di forum online, tidak jelas apakah artefak ini siap produksi, tetapi Solusi Inovatif mengerjakan proyek di samping tim Eclipse sejak awal, jadi proyek kami bergantung padanya.

Termasuk BIRT sekarang sangat mudah:

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

3.2. Ketergantungan Spring Boot

Sekarang BIRT diimpor ke proyek kami, kami hanya perlu menambahkan dependensi Spring Boot standar di file pom kami.

Ada satu kekurangan, karena BIRT jar berisi implementasi Slf4J -nya sendiri , yang tidak berfungsi baik dengan Logback dan melontarkan pengecualian konflik selama startup.

Karena kami tidak dapat menghapusnya dari toples, untuk memperbaiki masalah ini, kami perlu mengecualikan Logback :

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

Sekarang kami akhirnya siap untuk memulai!

4. Laporan BIRT

Dalam kerangka kerja BIRT, laporan adalah file konfigurasi XML yang panjang , yang diidentifikasi dengan ekstensi rptdesign .

Ini memberi tahu Engine apa yang harus digambar dan di mana , dari gaya judul hingga properti yang diperlukan untuk terhubung ke sumber data.

Untuk laporan dinamis dasar, kita perlu mengkonfigurasi tiga hal:

  1. sumber data (dalam contoh kami, kami menggunakan file CSV lokal, tetapi bisa dengan mudah menjadi tabel database)
  2. elemen yang ingin kami tampilkan (grafik, tabel, dll)
  3. desain halaman

Laporan tersebut disusun seperti halaman HTML, dengan header, body, footer, skrip, dan gaya.

Kerangka kerja ini menyediakan sekumpulan komponen yang luas untuk dipilih di luar kotak , termasuk integrasi ke sumber data arus utama, tata letak, bagan, dan tabel. Dan, kita bisa memperluasnya untuk menambahkan milik kita sendiri!

Ada dua cara untuk membuat file laporan: visual atau terprogram.

5. Desainer Laporan Gerhana

Untuk memudahkan pembuatan laporan, tim Eclipse membuat plugin alat desain laporan untuk IDE-nya yang populer.

Alat ini menampilkan antarmuka seret & lepas yang mudah dari Palet di sebelah kiri, yang secara otomatis membuka jendela penyiapan untuk komponen baru yang kami tambahkan ke halaman. Kami juga dapat melihat semua penyesuaian yang tersedia untuk setiap komponen dengan mengkliknya pada halaman dan kemudian pada tombol Editor Properti (disorot pada gambar di bawah).

Untuk memvisualisasikan seluruh struktur halaman dalam tampilan hierarki, kita hanya perlu mengklik tombol Outline .

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

Contoh laporan yang ditampilkan dalam gambar dapat ditemukan di jalur /reports/csv_data_report.rptdesign

Keuntungan lain dari mencari desainer visual adalah dokumentasi online, yang lebih berfokus pada alat ini daripada pendekatan terprogram.

Jika kita sudah menggunakan Eclipse, kita hanya perlu menginstal plugin Desain Laporan BIRT , yang menyertakan perspektif yang telah ditentukan dan editor visual.

Untuk pengembang yang saat ini tidak menggunakan Eclipse dan tidak ingin beralih, ada paket Eclipse Report Designer , yang terdiri dari penginstalan Eclipse portabel dengan plugin BIRT yang sudah diinstal sebelumnya.

Setelah file laporan selesai, kita dapat menyimpannya dalam proyek kita dan kembali ke pengkodean di lingkungan pilihan kita.

6. Pendekatan Programatis

Kami juga dapat merancang laporan hanya menggunakan kode , tetapi pendekatan ini jauh lebih sulit karena dokumentasi yang buruk tersedia, jadi bersiaplah untuk menggali kode sumber dan forum online.

Yang juga perlu dipertimbangkan adalah bahwa semua detail desain yang membosankan seperti ukuran, panjang, dan posisi kisi jauh lebih mudah ditangani dengan menggunakan desainer .

Untuk membuktikan hal ini, berikut adalah contoh cara menentukan halaman statis 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!");

Kode ini akan menghasilkan laporan sederhana (dan jelek):

Contoh laporan yang ditampilkan pada gambar di atas dapat ditemukan di jalur ini: /reports/static_report.rptdesign.

Setelah kami mengkodekan tampilan laporan dan data apa yang harus ditampilkan, kami dapat membuat file XML dengan menjalankan kelas ReportDesignApplication kami .

7. Melampirkan Sumber Data

Kami telah menyebutkan sebelumnya bahwa BIRT mendukung banyak sumber data yang berbeda.

Untuk proyek contoh kami, kami menggunakan file CSV sederhana dengan tiga entri. Ini dapat ditemukan di folder laporan dan terdiri dari tiga baris data sederhana, ditambah tajuk:

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

7.1. Mengonfigurasi Sumber Data

Untuk mengizinkan BIRT menggunakan file kita (atau jenis sumber lainnya), kita harus mengkonfigurasi Sumber Data .

Untuk file kami, kami membuat Sumber Data File Datar dengan desainer 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 mengintegrasikan BIRT dengan Spring Boot, menjelajahi jebakan dan tantangan, tetapi juga kekuatan dan fleksibilitasnya.

Kode sumber artikel tersedia di GitHub.