Merge pull request #6627 from gmconte/BAEL-617
Bael 617: BIRT reporting with Spring Boot
This commit is contained in:
commit
713972cdf0
2
pom.xml
2
pom.xml
|
@ -618,6 +618,7 @@
|
|||
<module>spring-boot-keycloak</module>
|
||||
<module>spring-boot-logging-log4j2</module>
|
||||
<module>spring-boot-mvc</module>
|
||||
<module>spring-boot-mvc-birt</module>
|
||||
<module>spring-boot-ops</module>
|
||||
<module>spring-boot-rest</module>
|
||||
<module>spring-boot-data</module>
|
||||
|
@ -1260,6 +1261,7 @@
|
|||
<module>spring-boot-keycloak</module>
|
||||
<module>spring-boot-logging-log4j2</module>
|
||||
<module>spring-boot-mvc</module>
|
||||
<module>spring-boot-mvc-birt</module>
|
||||
<module>spring-boot-ops</module>
|
||||
<module>spring-boot-rest</module>
|
||||
<module>spring-boot-data</module>
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>spring-boot-mvc-birt</artifactId>
|
||||
<name>spring-boot-mvc-birt</name>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
<description>Module For Spring Boot Integration with BIRT</description>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.1.1.RELEASE</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-logging</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.innoventsolutions.birt.runtime</groupId>
|
||||
<artifactId>org.eclipse.birt.runtime_4.8.0-20180626</artifactId>
|
||||
<version>4.8.0</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<version>1.2.17</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.6</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<spring-boot.version>2.1.1.RELEASE</spring-boot.version>
|
||||
<start-class>com.baeldung.springbootmvc.SpringBootMvcApplication</start-class>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
</project>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,4 @@
|
|||
Student, Math, Geography, History
|
||||
Bill, 10,3,8
|
||||
Tom, 5,6,5
|
||||
Anne, 7, 4,9
|
|
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<report xmlns="http://www.eclipse.org/birt/2005/design" version="3.2.23" id="1">
|
||||
<text-property name="title">Sample Report</text-property>
|
||||
<page-setup>
|
||||
<simple-master-page name="Page Master" id="2"/>
|
||||
</page-setup>
|
||||
<body>
|
||||
<grid id="3">
|
||||
<property name="width">100%</property>
|
||||
<column id="4"/>
|
||||
<column id="5"/>
|
||||
<row id="6">
|
||||
<cell id="7">
|
||||
<image id="9">
|
||||
<property name="source">url</property>
|
||||
<expression name="uri">"https://www.baeldung.com/wp-content/themes/baeldung/favicon/favicon-96x96.png"</expression>
|
||||
</image>
|
||||
</cell>
|
||||
<cell id="8">
|
||||
<label id="10">
|
||||
<text-property name="text">Hello, Baeldung world!</text-property>
|
||||
</label>
|
||||
</cell>
|
||||
</row>
|
||||
</grid>
|
||||
</body>
|
||||
</report>
|
|
@ -0,0 +1,93 @@
|
|||
package com.baeldung.birt.designer;
|
||||
|
||||
import com.ibm.icu.util.ULocale;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.eclipse.birt.core.exception.BirtException;
|
||||
import org.eclipse.birt.core.framework.Platform;
|
||||
import org.eclipse.birt.report.model.api.*;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
@SpringBootApplication
|
||||
public class ReportDesignApplication implements CommandLineRunner {
|
||||
|
||||
private static final Logger log = Logger.getLogger(ReportDesignApplication.class);
|
||||
|
||||
@Value("${reports.relative.path}")
|
||||
private String REPORTS_FOLDER;
|
||||
|
||||
public static void main(String[] args) {
|
||||
new SpringApplicationBuilder(ReportDesignApplication.class).web(WebApplicationType.NONE).build().run(args);
|
||||
}
|
||||
|
||||
@Override public void run(String... args) throws Exception {
|
||||
buildReport();
|
||||
}
|
||||
|
||||
private void buildReport() throws IOException, BirtException {
|
||||
final DesignConfig config = new DesignConfig();
|
||||
|
||||
final IDesignEngine engine;
|
||||
try {
|
||||
Platform.startup(config);
|
||||
IDesignEngineFactory factory = (IDesignEngineFactory) Platform
|
||||
.createFactoryObject(IDesignEngineFactory.EXTENSION_DESIGN_ENGINE_FACTORY);
|
||||
engine = factory.createDesignEngine(config);
|
||||
|
||||
} catch (Exception ex) {
|
||||
log.error("Exception during creation of DesignEngine", ex);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
SessionHandle session = engine.newSessionHandle(ULocale.ENGLISH);
|
||||
|
||||
ReportDesignHandle design = session.createDesign();
|
||||
design.setTitle("Sample Report");
|
||||
|
||||
// The element factory creates instances of the various BIRT elements.
|
||||
ElementFactory factory = design.getElementFactory();
|
||||
|
||||
// Create a simple master page that describes how the report will
|
||||
// appear when printed.
|
||||
//
|
||||
// Note: The report will fail to load in the BIRT designer
|
||||
// unless you create a master page.
|
||||
|
||||
DesignElementHandle element = factory.newSimpleMasterPage("Page Master"); //$NON-NLS-1$
|
||||
design.getMasterPages().add(element);
|
||||
|
||||
// Create a grid
|
||||
GridHandle grid = factory.newGridItem(null, 2 /* cols */, 1 /* row */);
|
||||
design.getBody().add(grid);
|
||||
grid.setWidth("100%");
|
||||
|
||||
RowHandle row0 = (RowHandle) grid.getRows().get(0);
|
||||
|
||||
// Create an image and add it to the first cell.
|
||||
ImageHandle image = factory.newImage(null);
|
||||
CellHandle cell = (CellHandle) row0.getCells().get(0);
|
||||
cell.getContent().add(image);
|
||||
image.setURL("\"https://www.baeldung.com/wp-content/themes/baeldung/favicon/favicon-96x96.png\"");
|
||||
|
||||
// Create a label and add it to the second cell.
|
||||
LabelHandle label = factory.newLabel(null);
|
||||
cell = (CellHandle) row0.getCells().get(1);
|
||||
cell.getContent().add(label);
|
||||
label.setText("Hello, Baeldung world!");
|
||||
|
||||
// Save the design and close it.
|
||||
File report = new File(REPORTS_FOLDER);
|
||||
report.mkdirs();
|
||||
|
||||
design.saveAs(new File(report, "static_report.rptdesign").getAbsolutePath());
|
||||
design.close();
|
||||
log.info("Report generated");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package com.baeldung.birt.engine;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableWebMvc
|
||||
public class ReportEngineApplication implements WebMvcConfigurer {
|
||||
@Value("${reports.relative.path}")
|
||||
private String reportsPath;
|
||||
@Value("${images.relative.path}")
|
||||
private String imagesPath;
|
||||
|
||||
public static void main(final String[] args) {
|
||||
SpringApplication.run(ReportEngineApplication.class, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
registry
|
||||
.addResourceHandler(reportsPath + imagesPath + "/**")
|
||||
.addResourceLocations("file:///" + System.getProperty("user.dir") + "/" + reportsPath + imagesPath);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package com.baeldung.birt.engine.controller;
|
||||
|
||||
import com.baeldung.birt.engine.dto.OutputType;
|
||||
import com.baeldung.birt.engine.dto.Report;
|
||||
import com.baeldung.birt.engine.service.BirtReportService;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.eclipse.birt.report.engine.api.EngineException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.List;
|
||||
|
||||
@Controller
|
||||
public class BirtReportController {
|
||||
private static final Logger log = Logger.getLogger(BirtReportController.class);
|
||||
|
||||
@Autowired
|
||||
private BirtReportService reportService;
|
||||
|
||||
@RequestMapping(produces = "application/json", method = RequestMethod.GET, value = "/report")
|
||||
@ResponseBody
|
||||
public List<Report> listReports() {
|
||||
return reportService.getReports();
|
||||
}
|
||||
|
||||
@RequestMapping(produces = "application/json", method = RequestMethod.GET, value = "/report/reload")
|
||||
@ResponseBody
|
||||
public ResponseEntity reloadReports(HttpServletResponse response) {
|
||||
try {
|
||||
log.info("Reloading reports");
|
||||
reportService.loadReports();
|
||||
} catch (EngineException e) {
|
||||
log.error("There was an error reloading the reports in memory: ", e);
|
||||
return ResponseEntity.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).build();
|
||||
}
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/report/{name}")
|
||||
@ResponseBody
|
||||
public void generateFullReport(HttpServletResponse response, HttpServletRequest request,
|
||||
@PathVariable("name") String name, @RequestParam("output") String output) {
|
||||
log.info("Generating full report: " + name + "; format: " + output);
|
||||
OutputType format = OutputType.from(output);
|
||||
reportService.generateMainReport(name, format, response, request);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package com.baeldung.birt.engine.dto;
|
||||
|
||||
import org.eclipse.birt.report.engine.api.IRenderOption;
|
||||
|
||||
public enum OutputType {
|
||||
HTML(IRenderOption.OUTPUT_FORMAT_HTML),
|
||||
PDF(IRenderOption.OUTPUT_FORMAT_PDF),
|
||||
INVALID("invalid");
|
||||
|
||||
String val;
|
||||
OutputType(String val) {
|
||||
this.val = val;
|
||||
}
|
||||
|
||||
public static OutputType from(String text) {
|
||||
for (OutputType output : values()) {
|
||||
if(output.val.equalsIgnoreCase(text)) return output;
|
||||
}
|
||||
return INVALID;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package com.baeldung.birt.engine.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Report DTO class
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class Report {
|
||||
private String title;
|
||||
private String name;
|
||||
private List<Parameter> parameters;
|
||||
|
||||
public Report(String title, String name) {
|
||||
this.title = title;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class Parameter {
|
||||
private String title;
|
||||
private String name;
|
||||
private ParameterType type;
|
||||
|
||||
}
|
||||
|
||||
public enum ParameterType {
|
||||
INT, STRING
|
||||
}
|
||||
}
|
|
@ -0,0 +1,168 @@
|
|||
package com.baeldung.birt.engine.service;
|
||||
|
||||
import com.baeldung.birt.engine.dto.OutputType;
|
||||
import com.baeldung.birt.engine.dto.Report;
|
||||
import org.eclipse.birt.core.exception.BirtException;
|
||||
import org.eclipse.birt.core.framework.Platform;
|
||||
import org.eclipse.birt.report.engine.api.*;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
||||
@Service
|
||||
public class BirtReportService implements ApplicationContextAware, DisposableBean {
|
||||
@Value("${reports.relative.path}")
|
||||
private String reportsPath;
|
||||
@Value("${images.relative.path}")
|
||||
private String imagesPath;
|
||||
|
||||
private HTMLServerImageHandler htmlImageHandler = new HTMLServerImageHandler();
|
||||
|
||||
@Autowired
|
||||
private ResourceLoader resourceLoader;
|
||||
@Autowired
|
||||
private ServletContext servletContext;
|
||||
|
||||
private IReportEngine birtEngine;
|
||||
private ApplicationContext context;
|
||||
private String imageFolder;
|
||||
|
||||
private Map<String, IReportRunnable> reports = new HashMap<>();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@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();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load report files to memory
|
||||
*
|
||||
*/
|
||||
public void loadReports() throws EngineException {
|
||||
File folder = new File(reportsPath);
|
||||
for (String file : Objects.requireNonNull(folder.list())) {
|
||||
if (!file.endsWith(".rptdesign")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
reports.put(file.replace(".rptdesign", ""),
|
||||
birtEngine.openReportDesign(folder.getAbsolutePath() + File.separator + file));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public List<Report> getReports() {
|
||||
List<Report> response = new ArrayList<>();
|
||||
for (Map.Entry<String, IReportRunnable> entry : reports.entrySet()) {
|
||||
IReportRunnable report = reports.get(entry.getKey());
|
||||
IGetParameterDefinitionTask task = birtEngine.createGetParameterDefinitionTask(report);
|
||||
Report reportItem = new Report(report.getDesignHandle().getProperty("title").toString(), entry.getKey());
|
||||
for (Object h : task.getParameterDefns(false)) {
|
||||
IParameterDefn def = (IParameterDefn) h;
|
||||
reportItem.getParameters()
|
||||
.add(new Report.Parameter(def.getPromptText(), def.getName(), getParameterType(def)));
|
||||
}
|
||||
response.add(reportItem);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
private Report.ParameterType getParameterType(IParameterDefn param) {
|
||||
if (IParameterDefn.TYPE_INTEGER == param.getDataType()) {
|
||||
return Report.ParameterType.INT;
|
||||
}
|
||||
return Report.ParameterType.STRING;
|
||||
}
|
||||
|
||||
public void generateMainReport(String reportName, OutputType output, HttpServletResponse response, HttpServletRequest request) {
|
||||
switch (output) {
|
||||
case HTML:
|
||||
generateHTMLReport(reports.get(reportName), response, request);
|
||||
break;
|
||||
case PDF:
|
||||
generatePDFReport(reports.get(reportName), response, request);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Output type not recognized:" + output);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a report as HTML
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a report as PDF
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
birtEngine.destroy();
|
||||
Platform.shutdown();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
reports.relative.path=reports/
|
||||
images.relative.path=images/
|
Loading…
Reference in New Issue