郝岩峰 發表於 2026-5-3 17:24:25

SpringBoot集成JasperReports实现PDF、HTML、XML的一键生成

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">核心原理</a></li><li><a href="#_label1">集成JasperReports步骤</a></li><li><a href="#_label2">项目目录结构</a></li><li><a href="#_label3">引入依赖</a></li><li><a href="#_label4">核心代码实现</a></li><li><a href="#_label5">测试接口</a></li><li><a href="#_label6">结论</a></li></ul></div><p style="text-align:center">JasperReports 是一个基于 Java 的开源报表工具,支持多种输出格式(如 PDF、HTML、XML 等),广泛应用于 Java 开发中生成动态报表&zwnj;。本文将完整演示如何在 Spring Boot 项目中整合 JasperReports,从环境配置、模板设计到接口开发,逐步实现用户数据报表的导出。</p>
<p class="maodian"><a name="_label0"></a></p><h2>核心原理</h2>
<ul><li><p>&zwnj;<strong>工作流程</strong>&zwnj;</p>
<ul><li>&zwnj;<strong>JRXML</strong>&zwnj;:XML 格式的报表模板文件,通过设计器(如 Jaspersoft Studio)创建&zwnj;。</li><li>&zwnj;<strong>Jasper</strong>&zwnj;:编译 JRXML 生成的二进制文件,用于数据填充&zwnj;。</li><li>&zwnj;<strong>Jrprint</strong>&zwnj;:填充数据后的报表对象,最终通过导出器生成目标格式文件&zwnj;。</li></ul></li><li><p>&zwnj;<strong>技术特点</strong>&zwnj;</p>
<ul><li>支持多种数据源(JDBC、JavaBeans、XML 等)&zwnj;。</li><li>可生成带水印的报表和子报表。</li></ul></li></ul>
<p class="maodian"><a name="_label1"></a></p><h2>集成JasperReports步骤</h2>
<p style="text-align:center"></p>
<p style="text-align:center"><img alt="实现 PDF、HTML、XML 一键生成!_xml_02" src="https://img.jbzj.com/file_images/article/202510/202510031050026.webp" width="632" /></p>
<p></p>
<p class="maodian"><a name="_label2"></a></p><h2>项目目录结构</h2>
<p style="text-align:center"></p>
<p style="text-align:center"><img alt="实现 PDF、HTML、XML 一键生成!_java_03" src="https://img.jbzj.com/file_images/article/202510/202510031050027.webp" width="520" /></p>
<p></p>
<p class="maodian"><a name="_label3"></a></p><h2>引入依赖</h2>
<p>在&nbsp;<code>pom.xml</code>&nbsp;中添加 JasperReports 相关依赖:</p>
<div class="jb51code"><pre class="brush:java;">&lt;dependencies&gt;
    &lt;!-- JasperReports 核心依赖 --&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;net.sf.jasperreports&lt;/groupId&gt;
      &lt;artifactId&gt;jasperreports&lt;/artifactId&gt;
      &lt;version&gt;7.0.3&lt;/version&gt;
    &lt;/dependency&gt;


    &lt;!-- JasperReports PDF 支持 --&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;net.sf.jasperreports&lt;/groupId&gt;
      &lt;artifactId&gt;jasperreports-pdf&lt;/artifactId&gt;
      &lt;version&gt;7.0.3&lt;/version&gt;
    &lt;/dependency&gt;


    &lt;!-- Spring Boot Web --&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
      &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
    &lt;/dependency&gt;


    &lt;!-- Lombok 简化实体类代码 --&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.projectlombok&lt;/groupId&gt;
      &lt;artifactId&gt;lombok&lt;/artifactId&gt;
      &lt;optional&gt;true&lt;/optional&gt;
    &lt;/dependency&gt;
&lt;/dependencies&gt;</pre></div>
<p class="maodian"><a name="_label4"></a></p><h2>核心代码实现</h2>
<p>&nbsp;启动类</p>
<div class="jb51code"><pre class="brush:java;">package com.icoderoad;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication
public class SpringbootJasperreportApplication {
    public static void main(String[] args) {
      SpringApplication.run(SpringbootJasperreportApplication.class, args);
    }
}</pre></div>
<p>User 实体类</p>
<div class="jb51code"><pre class="brush:java;">package com.icoderoad.entity;


public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
    private String address;


    public User(Long id, String name, Integer age, String email, String address) {
      this.id = id;
      this.name = name;
      this.age = age;
      this.email = email;
      this.address = address;
    }


    public User() {}


    // Getter 和 Setter
    public Long getId() {
      return id;
    }
    public void setId(Long id) {
      this.id = id;
    }


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


    public Integer getAge() {
      return age;
    }
    public void setAge(Integer age) {
      this.age = age;
    }


    public String getEmail() {
      return email;
    }
    public void setEmail(String email) {
      this.email = email;
    }


    public String getAddress() {
      return address;
    }
    public void setAddress(String address) {
      this.address = address;
    }
}</pre></div>
<p>报表生成工具类</p>
<div class="jb51code"><pre class="brush:java;">package com.icoderoad.report;


import com.icoderoad.entity.User;
import net.sf.jasperreports.engine.*;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import org.springframework.core.io.ClassPathResource;


import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;


public class ReportGenerator {


    public static byte[] generate(List&lt;User&gt; users, String format) throws Exception {
      // 1. 加载并编译报表模板
      ClassPathResource resource = new ClassPathResource("templates/user.jrxml");
      JasperReport jasperReport = JasperCompileManager.compileReport(resource.getInputStream());


      // 2. 准备数据源和参数
      JRBeanCollectionDataSource dataSource = new JRBeanCollectionDataSource(users);
      Map&lt;String, Object&gt; parameters = new HashMap&lt;&gt;();
      parameters.put("title", "用户列表");


      JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, dataSource);


      // 3. 导出不同格式
      return switch (format) {
            case "pdf" -&gt; JasperExportManager.exportReportToPdf(jasperPrint);
            case "xml" -&gt; JasperExportManager.exportReportToXml(jasperPrint).getBytes();
            case "html" -&gt; {
                String path = "/tmp/user.html";
                JasperExportManager.exportReportToHtmlFile(jasperPrint, path);
                yield Files.readAllBytes(Paths.get(path));
            }
            default -&gt; throw new IllegalArgumentException("不支持的格式: " + format);
      };
    }
}</pre></div>
<p>控制层</p>
<div class="jb51code"><pre class="brush:java;">package com.icoderoad.controller;


import com.icoderoad.entity.User;
import com.icoderoad.report.ReportGenerator;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;


import java.util.*;


@RestController
@RequestMapping("/users")
public class ReportController {


    @GetMapping("/export/{format}")
    public ResponseEntity&lt;Resource&gt; export(@PathVariable String format) throws Exception {
      // 模拟数据
      List&lt;User&gt; users = new ArrayList&lt;&gt;();
      for (int i = 0; i &lt; 10; i++) {
            users.add(new User((long) i, "姓名-" + i, new Random().nextInt(100),
                  i + "@qq.com", "地址-" + i));
      }


      // 生成报表
      byte[] content = ReportGenerator.generate(users, format);
      ByteArrayResource resource = new ByteArrayResource(content);


      return ResponseEntity.ok()
                .contentType(MediaType.APPLICATION_OCTET_STREAM)
                .header(HttpHeaders.CONTENT_DISPOSITION,
                        ContentDisposition.attachment()
                              .filename("user-report." + format)
                              .build().toString())
                .contentLength(resource.contentLength())
                .body(resource);
    }
}</pre></div>
<p>配置文件</p>
<div class="jb51code"><pre class="brush:java;">server:
port: 8080
spring:
application:
    name: springboot-jasperreport-demo</pre></div>
<p><code>jasperreports.properties</code></p>
<div class="jb51code"><pre class="brush:java;">net.sf.jasperreports.extension.registry.factory.simple.font.families=net.sf.jasperreports.engine.fonts.SimpleFontExtensionsRegistryFactory
net.sf.jasperreports.extension.simple.font.families.simhei=fonts/fonts.xml</pre></div>
<p>首先,在 Linux 系统中,将 Windows 的&nbsp;<strong>黑体</strong>字体文件&nbsp;<code>simhei.ttf</code>&nbsp;拷贝到项目目录:</p>
<div class="jb51code"><pre class="brush:java;">src/main/resources/fonts/simhei.ttf</pre></div>
<div class="jb51code"><pre class="brush:java;">fonts/fonts.xml</pre></div>
<div class="jb51code"><pre class="brush:java;">&lt;?xml versinotallow="1.0" encoding="UTF-8"?&gt;
&lt;fontFamilies&gt;
&lt;fontFamily name="黑体"&gt;
    &lt;normal&gt;fonts/simhei.ttf&lt;/normal&gt;
    &lt;bold&gt;fonts/simhei.ttf&lt;/bold&gt;
    &lt;italic&gt;fonts/simhei.ttf&lt;/italic&gt;
    &lt;boldItalic&gt;fonts/simhei.ttf&lt;/boldItalic&gt;
    &lt;pdfEncoding&gt;Identity-H&lt;/pdfEncoding&gt;
    &lt;pdfEmbedded&gt;true&lt;/pdfEmbedded&gt;
    &lt;exportFonts&gt;
      &lt;export key="net.sf.jasperreports.html"&gt;'黑体', Arial, Helvetica, sans-serif&lt;/export&gt;
      &lt;export key="net.sf.jasperreports.xhtml"&gt;'黑体', Arial, Helvetica, sans-serif&lt;/export&gt;
    &lt;/exportFonts&gt;
&lt;/fontFamily&gt;
&lt;/fontFamilies&gt;</pre></div>
<p>&nbsp;user.jrxml 示例模板</p>
<div class="jb51code"><pre class="brush:java;">&lt;?xml versinotallow="1.0" encoding="UTF-8"?&gt;
&lt;!-- 用户列表报表模板 --&gt;
&lt;jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports
                                  http://jasperreports.sourceforge.net/xsd/jasperreport.xsd"
            name="user_report"
            pageWidth="595" pageHeight="842"
            columnWidth="555" leftMargin="20" rightMargin="20"
            topMargin="20" bottomMargin="20" uuid="123e4567-e89b-12d3-a456-426614174000"&gt;


    &lt;!-- 报表参数 --&gt;
    &lt;parameter name="title" class="java.lang.String"/&gt;


    &lt;!-- 字段定义 --&gt;
    &lt;field name="id" class="java.lang.Long"/&gt;
    &lt;field name="name" class="java.lang.String"/&gt;
    &lt;field name="age" class="java.lang.Integer"/&gt;
    &lt;field name="email" class="java.lang.String"/&gt;
    &lt;field name="address" class="java.lang.String"/&gt;


    &lt;!-- 报表标题 --&gt;
    &lt;title&gt;
      &lt;band height="50"&gt;
            &lt;staticText&gt;
                &lt;reportElement x="0" y="10" width="555" height="30"/&gt;
                &lt;textElement textAlignment="Center"&gt;
                  &lt;font fontName="黑体" size="16" isBold="true"/&gt;
                &lt;/textElement&gt;
                &lt;text&gt;&lt;!]&gt;&lt;/text&gt;
            &lt;/staticText&gt;
      &lt;/band&gt;
    &lt;/title&gt;


    &lt;!-- 表头 --&gt;
    &lt;columnHeader&gt;
      &lt;band height="20"&gt;
            &lt;staticText&gt;&lt;reportElement x="0" y="0" width="50" height="20"/&gt;&lt;text&gt;&lt;!]&gt;&lt;/text&gt;&lt;/staticText&gt;
            &lt;staticText&gt;&lt;reportElement x="50" y="0" width="100" height="20"/&gt;&lt;text&gt;&lt;!]&gt;&lt;/text&gt;&lt;/staticText&gt;
            &lt;staticText&gt;&lt;reportElement x="150" y="0" width="50" height="20"/&gt;&lt;text&gt;&lt;!]&gt;&lt;/text&gt;&lt;/staticText&gt;
            &lt;staticText&gt;&lt;reportElement x="200" y="0" width="150" height="20"/&gt;&lt;text&gt;&lt;!]&gt;&lt;/text&gt;&lt;/staticText&gt;
            &lt;staticText&gt;&lt;reportElement x="350" y="0" width="205" height="20"/&gt;&lt;text&gt;&lt;!]&gt;&lt;/text&gt;&lt;/staticText&gt;
      &lt;/band&gt;
    &lt;/columnHeader&gt;


    &lt;!-- 数据体 --&gt;
    &lt;detail&gt;
      &lt;band height="20"&gt;
            &lt;textField&gt;&lt;reportElement x="0" y="0" width="50" height="20"/&gt;&lt;textFieldExpression&gt;&lt;!]&gt;&lt;/textFieldExpression&gt;&lt;/textField&gt;
            &lt;textField&gt;&lt;reportElement x="50" y="0" width="100" height="20"/&gt;&lt;textFieldExpression&gt;&lt;!]&gt;&lt;/textFieldExpression&gt;&lt;/textField&gt;
            &lt;textField&gt;&lt;reportElement x="150" y="0" width="50" height="20"/&gt;&lt;textFieldExpression&gt;&lt;!]&gt;&lt;/textFieldExpression&gt;&lt;/textField&gt;
            &lt;textField&gt;&lt;reportElement x="200" y="0" width="150" height="20"/&gt;&lt;textFieldExpression&gt;&lt;!]&gt;&lt;/textFieldExpression&gt;&lt;/textField&gt;
            &lt;textField&gt;&lt;reportElement x="350" y="0" width="205" height="20"/&gt;&lt;textFieldExpression&gt;&lt;!]&gt;&lt;/textFieldExpression&gt;&lt;/textField&gt;
      &lt;/band&gt;
    &lt;/detail&gt;
&lt;/jasperReport&gt;</pre></div>
<p class="maodian"><a name="_label5"></a></p><h2>测试接口</h2>
<p>启动服务后,分别访问以下地址即可获取不同格式的报表:</p>
<ul><li>PDF 报表:http://localhost:8080/users/export/pdf</li><li>XML 报表:http://localhost:8080/users/export/xml</li><li>HTML 报表:http://localhost:8080/users/export/html</li></ul>
<p class="maodian"><a name="_label6"></a></p><h2>结论</h2>
<p>通过本文的实践,我们基于&nbsp;<strong>Spring Boot + JasperReports</strong>&nbsp;搭建了一套完整的报表生成解决方案,实现了&nbsp;<strong>PDF、HTML、XML</strong>&nbsp;的多格式一键导出。整个过程涵盖了&nbsp;<strong>依赖引入、字体配置、模板设计、数据填充、接口实现</strong>&nbsp;等关键环节。</p>
頁: [1]
查看完整版本: SpringBoot集成JasperReports实现PDF、HTML、XML的一键生成