Merge pull request #6627 from gmconte/BAEL-617

Bael 617: BIRT reporting with Spring Boot
This commit is contained in:
Loredana Crusoveanu 2019-04-09 09:08:07 +03:00 committed by GitHub
commit 713972cdf0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 2549 additions and 0 deletions

View File

@ -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>

View File

@ -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

View File

@ -0,0 +1,4 @@
Student, Math, Geography, History
Bill, 10,3,8
Tom, 5,6,5
Anne, 7, 4,9
1 Student Math Geography History
2 Bill 10 3 8
3 Tom 5 6 5
4 Anne 7 4 9

View File

@ -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>

View File

@ -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");
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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
}
}

View File

@ -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();
}
}

View File

@ -0,0 +1,2 @@
reports.relative.path=reports/
images.relative.path=images/