【JasperReports笔记04】如何使用Jasper Studio制作父子报表,并且通过Java + Parameters参数填充模板文件

news2024/12/25 14:34:29

这篇文章,主要介绍如何使用Jasper Studio制作父子报表,并且通过Java + Parameters参数填充模板文件。

目录

一、JasperReports实现父子报表

1.1、运行效果

1.2、制作模板

(1)制作子报表

(2)制作子报表的注意事项

(3)制作父报表

(4)设置子报表数据源

1.3、使用Java填充模板文件

(1)引入依赖

(2)创建JasperReportsUtil工具类

(3)创建实体类

(4)放置模板文件

(5)创建测试控制器类

(6)运行测试


一、JasperReports实现父子报表

1.1、运行效果

这里是使用Jasper Studio制作的父子报表模板,以及通过Java填充数据之后生成的PDF文件,如下所示:

1.2、制作模板

制作父子报表,很明显需要有一个父报表、一个子报表,子报表嵌入到父报表里面,之后通过数据源进行渲染模板文件,首先创建子报表模板文件。

(1)制作子报表

在Jasper Studio中新建一个模板文件,这里我就叫做【sub_report.jrxml】,将模板文件中除了Detail区域之外,其余的都删除,如下图示:

接着添加三个Text Field文本域组件到Detail区域里面,调整样式,修改Detail区域高度等于30px,这里修改高度是为了让子报表的高度根据数据的来自动扩展。

到这里,子报表就算已经制作完成了,当然你要增加样式,你可以根据实际需求改动,我这里只是告诉你如何制作父子报表。

(2)制作子报表的注意事项

制作子报表的时候,需要注意以下几点:

  • 子报表的高度,一般情况下,都设置成可伸展的,默认30px够了,高度根据实际需求调整。
  • 一般情况下,子报表中只需要保留一个Detail区域即可。
  • 子报表中,一般不需要设置外边距,可以设置页面的边距等于0。

(3)制作父报表

在Jasper Studio中新建一个报表文件,名称我这里叫做【main_report.jrxml】,然后添加Statid Text静态文本域,绘制表格,如下所示:

这里表格每一个字段的列宽是固定的,根据实际需求来调整,例如:我这里设置的name、price、amount三个字段的列宽度都是185px,和子报表中的列宽度是一致的,这是因为一会这三个列需要嵌入子报表组件,宽度设置成一样更好些。

  • 接着,创建Field数据域字段,分别是:product、category、subData,其中subData的数据类型设置成【java.util.List】,这个字段就是子报表的数据源,是一个集合类型。

  • 接着添加Text Field文本域字段,设置表格的数据行内容,如下所示:

  • 在右上角的组件区域,将【SubReport】组件拖拽到Detail区域。

  • 此时会弹出一个窗口,让你选择子报表文件的路径。

  • 接着点击【Workspace resource】,从当前工作空间中选择子报表文件。

  • 选择成功之后,调整一下子报表的样式,最终样式如下所示。

(4)设置子报表数据源

父报表制作完成之后,就可以设置父报表中子报表组件使用的数据源以及子报表的路径位置啦,首先选中子报表,在右下角区域可以设置表达式。一般情况下,子报表的路径都会设置成一个参数,然后在Java程序中动态的指定子报表的路径位置。

点击会弹出窗口,让你选择表达式字段,如下所示:

需要注意的是,数据源类型必须使用【new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{subData})】方式包装起来。

如果子报表路径不正确,则会报错:

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

如果子报表的数据源设置不正确,则会报错:

Unsupported subreport section type java.util.ArrayList.

到这里,我们的父子报表模板文件就制作成功啦,编译模板文件,生成对应的【】文件,将其放入到Java工程里面。

1.3、使用Java填充模板文件

(1)引入依赖

这里搭建的是SpringBoot工程,首先引入jasperreports的依赖,如下:

<?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)创建JasperReportsUtil工具类

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)创建实体类

  • 创建主报表的实体类。
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;
    }
}
  • 创建子报表的实体类。
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)放置模板文件

将刚刚编译生成的父子报表文件放入到【src/main/resource】目录下面,如下所示:

(5)创建测试控制器类

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)运行测试

启动工程,打开浏览器访问http://localhost:8080/api/report/sub-report?format=pdf地址,此时就会生成对应的PDF文件,打开PDF文件如下图所示:

到此,Jasper Stduio制作父子报表模板文件就完成啦,公众号回复【父子报表】获取源代码

综上,这篇文章结束了,主要介绍如何使用Jasper Studio制作父子报表,并且通过Java + Parameters参数填充模板文件。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/899120.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机竞赛 图像检索算法

文章目录 1 前言2 图像检索介绍(1) 无监督图像检索(2) 有监督图像检索 3 图像检索步骤4 应用实例5 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 图像检索算法 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff…

0101读写分离测试-jdbc-shardingsphere-中间件

文章目录 1 前言2、创建SpringBoot程序2.1、创建项目2.2、添加依赖2.3、生成实体类、service与Mapper1.5、配置读写分离 2、测试2.1、读写分离测试2.2、事务测试2.3、负载均衡测试 结语 1 前言 shardingshpere-jdbc定位为轻量级 Java 框架&#xff0c;在 Java 的 JDBC 层提供的…

处理Selenium3+python3定位鼠标悬停才显示的元素

这篇文章主要介绍了Selenium3python3--如何定位鼠标悬停才显示的元素 &#xff0c;文中通过简单代码给大家介绍的非常详细,需要的朋友可以参考下 先给大家介绍下Selenium3python3--如何定位鼠标悬停才显示的元素 定位鼠标悬停才显示的元素&#xff0c;要引入新模块 # coding…

Tableau画图

目录 蝴蝶图 四象图 排序图 盒型图/散点图 圆环图 火柴图 直方图 瀑布图 地理图 面积图 树地图 面积图 条形图 词云图 双轴图 填充地图 tableau2023.2 须知 蝴蝶图 拉好数据之后 创建新字段正负销售额&#xff0c;并拖入第一个颜色标记卡 四象图 智能推荐 散…

使用句子嵌入的无监督文本摘要

一、说明 这是一个AI研究生班的作业练习&#xff0c; 在本文中&#xff0c;我将描述我用来在 Python 中执行文本摘要的方法&#xff0c;这是我在导师分配给我的很棒的任务列表之一。 二、什么是文本摘要&#xff1f; 文本摘要是从一个或多个源中提取最重要的信息以生成特定用户…

华为ENSP网络设备配置实战4(OSPF+BGP+VPN+单臂路由)

题目要求 1、loopback口通过OSPF连通&#xff0c;合理规划OSPF开销&#xff0c;通过设置AR1->AR2->AR4链路&#xff0c;来消除负载链路。 2、AR3、AR4分别与AR1、AR2建立BGP邻居 3、AR3、AR4作为PC机网关设备 4、PC1、PC3由VPN-spi承载&#xff0c;PC2、PC4由VPN-spims承…

【算法挨揍日记】day03——双指针算法_有效三角形的个数、和为s的两个数字

611. 有效三角形的个数 611. 有效三角形的个数https://leetcode.cn/problems/valid-triangle-number/ 题目描述&#xff1a; 给定一个包含非负整数的数组 nums &#xff0c;返回其中可以组成三角形三条边的三元组个数。 解题思路&#xff1a; 本题是一个关于三角形是否能成立…

通过爬虫抓取上市企业利润表并在睿思BI中展示

睿思BI从v5.3开始支持网络爬虫&#xff0c;可以从指定URL抓取表格数据&#xff0c;本示例实现从网络上抓取上市企业招商银行的利润表数据&#xff0c;并在睿思BI中进行展现。 首先&#xff1a;从搜狐财经抓取招商银行利润表数据&#xff0c;操作过程如下&#xff1a; 1.在睿思…

提示词4大经典框架;将AI融入动画工作流的案例和实践经验;构建基于LLM的系统和产品的模式;提示工程的艺术 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; &#x1f916; 高效提示词的4大经典框架&#xff1a;ICIO、CRISPE、BROKE、RASCEF ICIO 框架 Intruction (任务) &#xff1a;你希望AI去做的任务&am…

软件测试中如何测试算法?

广义的算法是指解决问题的方案,小到求解数学题,大到制定商业策略,都可以叫做算法。而我们 今天讨论的软件测试中的算法,对应的英文单词为Algorithm ,专指计算机处理复杂问题的程序或 指令。 随着最近几年人工智能等领域的快速发展,算法受到前所未有的重视,算法测试也随之兴起。…

异步电机IM-改进的电压模型磁链观测器学习

导读&#xff1a;本期文章主要介绍异步电机的改进型电压模型磁链观测器。传统纯积分形式的积分器在低速区域存在初始值问题和直流偏置问题&#xff0c;所以在实际应用中必须对电压模型进行改进。本期文章中的对电压模型改进是借鉴一篇IEEE中的方法。 如果需要文章中对应的仿真…

gcc make cmake ninja的区别

理清C编译过程用到的工具概念 ref: 知乎 早先学C的时候&#xff0c;因为只需要点击IDE的运行按钮&#xff0c;程序就可以跑起来&#xff0c;写过最复杂的只不过是几个文件的学生管理系统。 现在要重新拾起C&#xff0c;看的项目和之前的不可同日而语&#xff0c;构建系统也复…

最优化方法Python计算:牛顿算法

设函数 f ( x ) f(\boldsymbol{x}) f(x)&#xff0c; x ∈ R n \boldsymbol{x}\in\text{ℝ}^n x∈Rn二阶连续可微&#xff0c;记 g ( x ) ∇ f ( x ) \boldsymbol{g}(\boldsymbol{x})\nabla f(\boldsymbol{x}) g(x)∇f(x)&#xff0c; H ( x ) ∇ 2 f ( x ) \boldsymbol{H}(\…

【数据结构OJ题】用栈实现队列

原题链接&#xff1a;https://leetcode.cn/problems/implement-queue-using-stacks/ 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 用两个栈实现&#xff0c;一个栈进行入队操作&#xff0c;另一个栈进行出队操作。 出队操作&#xff1a; 当出队的栈…

ARFoundation避坑记录

网上很多人说这个要改成可选的&#xff0c;否则如果没有安装arcore就会自动弹窗&#xff0c;但是如果关闭了&#xff0c;确实不会弹窗了&#xff0c;但是检测设备的代码也不能完美执行了&#xff0c;如果设备安装了arcore还好&#xff0c;如果没有安装测无法检测。 如果不想有…

常见的CRM系统报价

一个CRM系统大概多少钱&#xff1f;CRM系统的价格因为不同的厂商、功能、部署方式、用户数等因素而有很大的差异&#xff0c;没有一个固定的标准。但是&#xff0c;我们可以根据一些常见的CRM软件的报价&#xff0c;对CRM价格有一个大致的了解。 一、CRM的部署方式 CRM系统的…

填充柄功能

单元格右下角十字符号 顺序式填充 输入1,2&#xff0c;直接拉取即可实现顺序1到10. 复制式填充 CtrlD或者拉取&#xff0c;选择右下角复制单元格。 规律式填充 输入星期一&#xff0c;星期二&#xff0c;下拉一直可以到星期日 自定义填充 选择文件-》选项-》自定义序列 输…

AI工程师招募;60+开发者AI工具清单;如何用AI工具读懂插件源码;开发者出海解读;斯坦福LLM课程 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; &#x1f916; 一则AI工程师招募信息&#xff1a;新领域需要新技能 Vision Flow (目的涌现) 是一家基于 AGI 原生技术的创业公司&#xff0c;是全球探…

CSGO饰品价格会一直下跌吗?市场何时止跌回升?

最后一届巴黎major终于落下帷幕&#xff0c;Vitality小蜜蜂2-0战胜GL成功赢下本次Major冠军&#xff0c;也是首次夺得Major冠军&#xff01;有人欢喜有人忧啊&#xff0c;csgo搬砖的饰品商人们一点也高兴不起来。 4月-5月&#xff0c;csgo皮肤饰品已持续走低快两个月了。手里满…

OPTEE3.17+ubuntu20.04+qemu_v8搭建OPTEE开发环境

参考文章&#xff1a; https://blog.csdn.net/capodexi/article/details/123548850 https://blog.csdn.net/qq_42557044/article/details/130973200 https://blog.csdn.net/zhuwade/article/details/125513873 https://zhuanlan.zhihu.com/p/521196386 https://blog.csdn.net/…