「報表神器!」Spring Boot + JasperReport 實現(xiàn) PDF、HTML、XML 一鍵生成
在企業(yè)應(yīng)用中,報表是業(yè)務(wù)系統(tǒng)的關(guān)鍵組成部分,承擔著數(shù)據(jù)可視化和統(tǒng)計分析的重要職責。傳統(tǒng)方式生成報表往往費時費力,而 JasperReports 作為一款成熟的開源報表引擎,能夠與 Spring Boot 無縫集成,實現(xiàn) PDF、HTML、XML 多格式一鍵導出,幫助開發(fā)者快速構(gòu)建專業(yè)級報表系統(tǒng)。
本文將完整演示如何在 Spring Boot 項目中整合 JasperReports,從環(huán)境配置、模板設(shè)計到接口開發(fā),逐步實現(xiàn)用戶數(shù)據(jù)報表的導出。
技術(shù)方案概覽
集成 JasperReports 的整體步驟如下:
- 引入依賴:在
pom.xml中添加jasperreports相關(guān)依賴。 - 配置字體:解決中文顯示問題,保證報表渲染正常。
- 設(shè)計模板:使用 Jaspersoft Studio 創(chuàng)建
.jrxml模板。 - 加載與編譯:通過
JasperCompileManager編譯模板。 - 填充數(shù)據(jù):將 Java 集合或數(shù)據(jù)庫數(shù)據(jù)綁定到報表。
- 多格式導出:使用
JasperExportManager輸出 PDF、HTML、XML。
項目目錄結(jié)構(gòu)
springboot-jasperreport-demo/
├── pom.xml
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── icoderoad/
│ │ │ ├── SpringbootJasperreportApplication.java
│ │ │ ├── controller/
│ │ │ │ └── ReportController.java
│ │ │ ├── entity/
│ │ │ │ └── User.java
│ │ │ └── report/
│ │ │ └── ReportGenerator.java
│ │ └── resources/
│ │ ├── application.yml
│ │ ├── templates/
│ │ │ └── user.jrxml
│ │ ├── fonts/
│ │ │ ├── simhei.ttf
│ │ │ └── fonts.xml
│ │ └── jasperreports.properties
│ └── test/
│ └── java/
│ └── com/
│ └── icoderoad/
│ └── SpringbootJasperreportApplicationTests.java引入依賴
在 pom.xml 中添加 JasperReports 相關(guān)依賴:
<dependencies>
<!-- JasperReports 核心依賴 -->
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports</artifactId>
<version>7.0.3</version>
</dependency>
<!-- JasperReports PDF 支持 -->
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports-pdf</artifactId>
<version>7.0.3</version>
</dependency>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Lombok 簡化實體類代碼 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>核心代碼實現(xiàn)
啟動類
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);
}
}User 實體類
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;
}
}報表生成工具類
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<User> users, String format) throws Exception {
// 1. 加載并編譯報表模板
ClassPathResource resource = new ClassPathResource("templates/user.jrxml");
JasperReport jasperReport = JasperCompileManager.compileReport(resource.getInputStream());
// 2. 準備數(shù)據(jù)源和參數(shù)
JRBeanCollectionDataSource dataSource = new JRBeanCollectionDataSource(users);
Map<String, Object> parameters = new HashMap<>();
parameters.put("title", "用戶列表");
JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, dataSource);
// 3. 導出不同格式
return switch (format) {
case "pdf" -> JasperExportManager.exportReportToPdf(jasperPrint);
case "xml" -> JasperExportManager.exportReportToXml(jasperPrint).getBytes();
case "html" -> {
String path = "/tmp/user.html";
JasperExportManager.exportReportToHtmlFile(jasperPrint, path);
yield Files.readAllBytes(Paths.get(path));
}
default -> throw new IllegalArgumentException("不支持的格式: " + format);
};
}
}控制層
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<Resource> export(@PathVariable String format) throws Exception {
// 模擬數(shù)據(jù)
List<User> users = new ArrayList<>();
for (int i = 0; i < 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);
}
}配置文件
server:
port: 8080
spring:
application:
name: springboot-jasperreport-demojasperreports.properties
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首先,在 Linux 系統(tǒng)中,將 Windows 的 黑體字體文件 simhei.ttf 拷貝到項目目錄:
src/main/resources/fonts/simhei.ttffonts/fonts.xml<?xml version="1.0" encoding="UTF-8"?>
<fontFamilies>
<fontFamily name="黑體">
<normal>fonts/simhei.ttf</normal>
<bold>fonts/simhei.ttf</bold>
<italic>fonts/simhei.ttf</italic>
<boldItalic>fonts/simhei.ttf</boldItalic>
<pdfEncoding>Identity-H</pdfEncoding>
<pdfEmbedded>true</pdfEmbedded>
<exportFonts>
<export key="net.sf.jasperreports.html">'黑體', Arial, Helvetica, sans-serif</export>
<export key="net.sf.jasperreports.xhtml">'黑體', Arial, Helvetica, sans-serif</export>
</exportFonts>
</fontFamily>
</fontFamilies>user.jrxml 示例模板
<?xml version="1.0" encoding="UTF-8"?>
<!-- 用戶列表報表模板 -->
<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">
<!-- 報表參數(shù) -->
<parameter name="title" class="java.lang.String"/>
<!-- 字段定義 -->
<field name="id" class="java.lang.Long"/>
<field name="name" class="java.lang.String"/>
<field name="age" class="java.lang.Integer"/>
<field name="email" class="java.lang.String"/>
<field name="address" class="java.lang.String"/>
<!-- 報表標題 -->
<title>
<band height="50">
<staticText>
<reportElement x="0" y="10" width="555" height="30"/>
<textElement textAlignment="Center">
<font fontName="黑體" size="16" isBold="true"/>
</textElement>
<text><![CDATA[$P{title}]]></text>
</staticText>
</band>
</title>
<!-- 表頭 -->
<columnHeader>
<band height="20">
<staticText><reportElement x="0" y="0" width="50" height="20"/><text><![CDATA[ID]]></text></staticText>
<staticText><reportElement x="50" y="0" width="100" height="20"/><text><![CDATA[姓名]]></text></staticText>
<staticText><reportElement x="150" y="0" width="50" height="20"/><text><![CDATA[年齡]]></text></staticText>
<staticText><reportElement x="200" y="0" width="150" height="20"/><text><![CDATA[郵箱]]></text></staticText>
<staticText><reportElement x="350" y="0" width="205" height="20"/><text><![CDATA[地址]]></text></staticText>
</band>
</columnHeader>
<!-- 數(shù)據(jù)體 -->
<detail>
<band height="20">
<textField><reportElement x="0" y="0" width="50" height="20"/><textFieldExpression><![CDATA[$F{id}]]></textFieldExpression></textField>
<textField><reportElement x="50" y="0" width="100" height="20"/><textFieldExpression><![CDATA[$F{name}]]></textFieldExpression></textField>
<textField><reportElement x="150" y="0" width="50" height="20"/><textFieldExpression><![CDATA[$F{age}]]></textFieldExpression></textField>
<textField><reportElement x="200" y="0" width="150" height="20"/><textFieldExpression><![CDATA[$F{email}]]></textFieldExpression></textField>
<textField><reportElement x="350" y="0" width="205" height="20"/><textFieldExpression><![CDATA[$F{address}]]></textFieldExpression></textField>
</band>
</detail>
</jasperReport>測試接口
啟動服務(wù)后,分別訪問以下地址即可獲取不同格式的報表:
- PDF 報表:http://localhost:8080/users/export/pdf
- XML 報表:http://localhost:8080/users/export/xml
- HTML 報表:http://localhost:8080/users/export/html
結(jié)論
通過本文的實踐,我們基于 Spring Boot + JasperReports 搭建了一套完整的報表生成解決方案,實現(xiàn)了 PDF、HTML、XML 的多格式一鍵導出。整個過程涵蓋了 依賴引入、字體配置、模板設(shè)計、數(shù)據(jù)填充、接口實現(xiàn) 等關(guān)鍵環(huán)節(jié)。
這一方案具有以下優(yōu)勢:
- 可擴展性強:支持 JDBC、JPA、內(nèi)存數(shù)據(jù)等多種數(shù)據(jù)源。
- 模板靈活:通過 Jaspersoft Studio 可視化設(shè)計,報表樣式可自由調(diào)整。
- 多格式支持:一次開發(fā),多端復用,滿足不同業(yè)務(wù)場景。
在未來,開發(fā)者可以基于此方案擴展到更加復雜的業(yè)務(wù),例如 財務(wù)結(jié)算報表、統(tǒng)計分析報表、業(yè)務(wù)大屏導出 等,從而幫助企業(yè)快速實現(xiàn)數(shù)據(jù)驅(qū)動的決策支持。






























