[JasperReports Notes 04] How to use Jasper Studio to make parent-child reports and fill template files with Java + Parameters parameters

This article mainly introduces how to use Jasper Studio to make parent-child reports and fill template files with Java + Parameters parameters.

Table of contents

1. JasperReports implements parent-child reports

1.1. Operation effect

1.2, making templates

(1) Make a subreport

(2) Precautions for making subreports

(3) Make a parent report

(4) Set the subreport data source

1.3. Use Java to fill template files

(1) Introduce dependencies

(2) Create the JasperReportsUtil tool class

(3) Create entity classes

(4) Place the template file

(5) Create a test controller class

(6) Run the test


1. JasperReports implements parent-child reports

1.1. Operation effect

Here is the parent-child report template made using Jasper Studio, and the PDF file generated after filling the data through Java, as follows:

1.2, making templates

To make a parent-child report, it is obvious that there needs to be a parent report and a sub-report. The sub-report is embedded in the parent report, and then the template file is rendered through the data source. First, the sub-report template file is created.

(1) Make a subreport

Create a new template file in Jasper Studio, here I call it [sub_report.jrxml], delete everything except the Detail area in the template file, as shown below:

Then add three Text Field text field components to the Detail area, adjust the style, and modify the height of the Detail area to be equal to 30px. The purpose of modifying the height here is to make the height of the subreport automatically expand according to the data.

At this point, even if the sub-report has been made, of course you need to add styles, you can change it according to actual needs, I just tell you how to make parent-child reports.

(2) Precautions for making subreports

When creating subreports, you need to pay attention to the following points:

  • The height of the subreport is generally set to be stretchable, and the default 30px is enough, and the height can be adjusted according to actual needs.
  • Generally, only one Detail area needs to be reserved in the subreport.
  • In sub-reports, generally there is no need to set the outer margin, and the page margin can be set equal to 0.

(3) Make a parent report

Create a new report file in Jasper Studio, the name here is [main_report.jrxml], then add the Statid Text static text field, and draw the table, as shown below:

Here, the column width of each field in the table is fixed and adjusted according to actual needs. For example, the column width of the three fields I set here is 185px, which is consistent with the column width in the subreport. It is because these three columns need to embed the subreport component in a while, and it is better to set the width to be the same.

  • Next, create Field data domain fields, which are: product, category, subData, where the data type of subData is set to [java.util.List]. This field is the data source of the subreport, which is a collection type.

  • Then add the Text Field text field and set the data row content of the table, as follows:

  • In the component area in the upper right corner, drag the [SubReport] component to the Detail area.

  • A window will pop up allowing you to select the path to the subreport file.

  • Then click [Workspace resource] to select the subreport file from the current workspace.

  • After the selection is successful, adjust the style of the subreport. The final style is as follows.

(4) Set the subreport data source

After the parent report is created, you can set the data source used by the subreport components in the parent report and the path location of the subreport. First select the subreport, and you can set the expression in the lower right corner area. In general, the path of the subreport is set as a parameter, and then the path location of the subreport is dynamically specified in the Java program.

Clicking will bring up a window that lets you select the expression field, as shown below:

It should be noted that the data source type must be packaged with [new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{subData})].

If the subreport path is incorrect, an error will be reported:

net.sf.jasperreports.engine.JRException: Resource not found at: sub_report.jrxml.

If the data source setting of the subreport is incorrect, an error will be reported:

Unsupported subreport section type java.util.ArrayList.

At this point, our parent-child report template file has been successfully created, compile the template file, generate the corresponding [] file, and put it into the Java project.

1.3. Use Java to fill template files

(1) Introduce dependencies

The SpringBoot project is built here. First, the dependency of jasperreports is introduced, as follows:

<?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.gitcode.demo</groupId>
    <artifactId>jasper-demo</artifactId>
    <version>1.0.0</version>

    <parent>
        <artifactId>spring-boot-starter-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>2.3.5.RELEASE</version>
    </parent>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- JasperReports 报表开发所需依赖 START -->
        <!-- https://mvnrepository.com/artifact/net.sf.jasperreports/jasperreports -->
        <dependency>
            <groupId>net.sf.jasperreports</groupId>
            <artifactId>jasperreports</artifactId>
            <version>6.20.0</version>
            <exclusions>
                <!--
                    排除自带的itext依赖,因为自带的itext版本是 2.1.7.js10
                    这个版本在中央仓库里面没有,无法下载
                -->
                <exclusion>
                    <groupId>com.lowagie</groupId>
                    <artifactId>itext</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- 引入itext依赖,因为JasperReports中使用了itext操作PDF -->
        <dependency>
            <groupId>com.lowagie</groupId>
            <artifactId>itext</artifactId>
            <version>2.1.7</version>
        </dependency>
        <!-- JasperReports 报表开发所需依赖 END -->
        <!--
            引入 poi 依赖,因为 jasper 底层操作excel使用的是poi组件
        -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>4.1.2</version>
        </dependency>
    </dependencies>

    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.*</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.*</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/webapp</directory>
                <includes>
                    <include>**/*.*</include>
                </includes>
            </resource>
        </resources>
    </build>
</project>

(2) Create the JasperReportsUtil tool class

package com.gitcode.demo.util;

import net.sf.jasperreports.engine.*;
import net.sf.jasperreports.engine.export.JRXlsExporter;
import net.sf.jasperreports.engine.export.ooxml.JRXlsxExporter;
import net.sf.jasperreports.engine.util.JRLoader;
import net.sf.jasperreports.export.*;
import org.springframework.core.io.ClassPathResource;

import java.io.InputStream;
import java.util.Map;
import java.util.Objects;

/**
 * @version 1.0.0
 * @Date: 2023/8/7 14:14
 * @Author ZhuYouBin
 * @Description: JasperReports 工具类
 */
public class JasperReportsUtil {

    /**
     * 使用 JasperReports 生成报表文件
     * @param templatePath 模板文件路径及名称
     * @param fileName 生成的文件名称
     * @param fileType 生成的文件类型,例如: pdf、html、xls 等
     * @param parameters 传递到 jrxml 模板文件中的数据参数
     * @return 返回生成的报表文件路径
     */
    public static String generateReport(String templatePath, String fileName, String fileType, Map<String, Object> parameters) throws Exception {
        return generateReport(templatePath, fileName, fileType, parameters, new JREmptyDataSource());
    }

    public static String generateReport(String templatePath, String fileName, String fileType, Map<String, Object> parameters, JRDataSource dataSource) throws Exception {
        // 1、获取 jasper 模板文件【采用流的方式读取】
        ClassPathResource resource = new ClassPathResource(templatePath);
        InputStream in = resource.getInputStream();
        JasperReport jasperReport = (JasperReport) JRLoader.loadObject(in);
        // 2、将 parameters 数据参数填充到模板文件中
        JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, dataSource);
        // 3、按照指定的 fileType 文件类型导出报表文件
        if (fileType == null || "".equals(fileType.trim())) {
            fileType = "pdf";
        }
        if (Objects.equals("pdf", fileType)) {
            JasperExportManager.exportReportToPdfFile(jasperPrint, fileName + ".pdf");
        } else if (Objects.equals("xls", fileType)) { // 导出 xls 表格
            JRXlsExporter exporter = new JRXlsExporter();
            exporter.setExporterInput(new SimpleExporterInput(jasperPrint)); // 设置导出的输入源
            exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(fileName + ".xls")); // 设置导出的输出源
            // 配置信息
            SimpleXlsReportConfiguration configuration = new SimpleXlsReportConfiguration();
            configuration.setOnePagePerSheet(true); // 每一页一个sheet表格
            exporter.setConfiguration(configuration); // 设置配置对象
            exporter.exportReport(); // 执行导出
        } else if (Objects.equals("xlsx", fileType)) {  // 导出 xlsx 表格
            JRXlsxExporter exporter = new JRXlsxExporter();
            exporter.setExporterInput(new SimpleExporterInput(jasperPrint)); // 设置导出的输入源
            exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(fileName + ".xlsx")); // 设置导出的输出源
            SimpleXlsxReportConfiguration configuration = new SimpleXlsxReportConfiguration();
            configuration.setOnePagePerSheet(true); // 每一页一个sheet表格
            exporter.setConfiguration(configuration);
            exporter.exportReport(); // 执行导出
        } else if (Objects.equals("html", fileType)) {
            JasperExportManager.exportReportToHtmlFile(jasperPrint, fileName + ".html");
        }
        return null;
    }

}

(3) Create entity classes

  • Create the entity class for the main report.
package com.gitcode.demo.domain;

import java.io.Serializable;
import java.util.List;

/**
 * @version 1.0.0
 * @Date: 2023/8/19 14:57
 * @Author ZhuYouBin
 * @Description: 主报表实体类
 */
public class MainEntity implements Serializable {
    private String product;
    private String category;
    private List<SubEntity> subData;
    // setter and getter

    public String getProduct() {
        return product;
    }

    public void setProduct(String product) {
        this.product = product;
    }

    public String getCategory() {
        return category;
    }

    public void setCategory(String category) {
        this.category = category;
    }

    public List<SubEntity> getSubData() {
        return subData;
    }

    public void setSubData(List<SubEntity> subData) {
        this.subData = subData;
    }
}
  • Entity class for creating subreports.
package com.gitcode.demo.domain;

import java.io.Serializable;

/**
 * @version 1.0.0
 * @Date: 2023/8/19 14:58
 * @Author ZhuYouBin
 * @Description: 子报表实体类
 */
public class SubEntity implements Serializable {
    private String name;
    private String price;
    private Integer amount;
    // setter and getter
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPrice() {
        return price;
    }

    public void setPrice(String price) {
        this.price = price;
    }

    public Integer getAmount() {
        return amount;
    }

    public void setAmount(Integer amount) {
        this.amount = amount;
    }
}

(4) Place the template file

Put the parent-child report file just compiled and generated under the [src/main/resource] directory, as shown below:

(5) Create a test controller class

package com.gitcode.demo.web;

import com.gitcode.demo.domain.MainEntity;
import com.gitcode.demo.domain.SubEntity;
import com.gitcode.demo.util.JasperReportsUtil;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @version 1.0.0
 * @Date: 2023/8/12 16:34
 * @Author ZhuYouBin
 * @Description: 【父子报表】测试
 */
@RestController
@RequestMapping("/api/report")
public class ParentChildReportController {


    @GetMapping("/sub-report")
    public String exportFile(String format) throws Exception {
        ClassPathResource resource = new ClassPathResource("main_report.jasper");
        String templatePath = resource.getPath();
        String fileName = "父子报表模板文件";
        // 表格数据集是 JRBeanCollectionDataSource 类型的,也就是 JavaBean 实体类类型
        List<MainEntity> data = this.getData(3);
        JRBeanCollectionDataSource dataSource = new JRBeanCollectionDataSource(data);
        // 设置 parameters 参数
        Map<String, Object> parameters = new HashMap<>();
        String subReportPath = new ClassPathResource("sub_report.jasper").getPath();
        parameters.put("subReportPath", subReportPath); // 设置子报表的路径
        // 执行导出操作
        return JasperReportsUtil.generateReport(templatePath, fileName, format, parameters, dataSource);
    }

    private List<MainEntity> getData(int num) {
        List<MainEntity> ansMap = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            MainEntity main = new MainEntity();
            main.setProduct("product_00" + i);
            main.setCategory("phone_00" + i);
            List<SubEntity> subData = new ArrayList<>();
            int idx = (int)(Math.random() * 10) + i;
            for (int j = 0; j < idx; j++) {
                SubEntity subEntity = new SubEntity();
                subEntity.setName("name_" + j);
                subEntity.setPrice((int)(Math.random() * 100) + "");
                subEntity.setAmount((int)(Math.random() * 100));
                subData.add(subEntity);
            }
            main.setSubData(subData);
            ansMap.add(main);
        }
        return ansMap;
    }
}

(6) Run the test

Start the project, open the browser and visit the http://localhost:8080/api/report/sub-report?format=pdf address, and the corresponding PDF file will be generated at this time. Open the PDF file as shown in the figure below:

At this point, Jasper Stduio has completed the creation of the parent-child report template file, and the official account will reply to [Father-child Report] to obtain the source code .

In summary, this article is over. It mainly introduces how to use Jasper Studio to make parent-child reports and fill template files with Java + Parameters parameters.

Guess you like

Origin blog.csdn.net/qq_39826207/article/details/132379227