Java 输出 PDF 及定制模板——使用 JasperReports

本文共有6390个字,页面加载耗时0.001秒,关键词:

当下项目中需要用户定制导出 PDF,以便快速的适应客户的需求变化。后来在网上查资料发现可以使用 JasperReports + Jaspersoft Studio工具来实现可配置的报表。

1.JasperReports 介绍

JasperReports 是一个非常强大,易用的开源报表引擎,它是用 Java 编写的。它可以通过各种各样的数据源来生成像素级的文档,这些文档都可以查看,打印以及导出(文档格式包括 HTML、PDF、Excel、Word 等等)。

1.1.Jaspersoft Studio

Jaspersoft Studio 是一个设计报表模板的工具,我们通过它来设计需要使用报表的模板。 下载地址
使用教程
.jrxml 文件复制到项目的 resources/pdf/templates 目录下。
下载示例文件:https://wwa.lanzous.com/i7Sfejetw7g
模板文件预览

2.导入 jasperreports

<!-- https://mvnrepository.com/artifact/net.sf.jasperreports/jasperreports -->
<dependency>
    <groupId>net.sf.jasperreports</groupId>
    <artifactId>jasperreports</artifactId>
    <version>6.14.0</version>
</dependency>

3.配置字体

配置字体指的是在设计 PDF 模板时使用的字体需要配置到项目内,如果不配置将会导出时不显示中文字符。

3.1.首先在 resources 创建文件 jasperreports_extension.properties

net.sf.jasperreports.extension.registry.factory.simple.font.families=net.sf.jasperreports.engine.fonts.SimpleFontExtensionsRegistryFactory
net.sf.jasperreports.extension.simple.font.families.lobstertwo=fonts/fonts.xml

3.2.然后在 resources/fonts 创建 fonts.xml

<?xml version="1.0" encoding="UTF-8"?>
<fontFamilies>
    <fontFamily name="华文宋体">
        <normal>fonts/stsong.ttf</normal>
        <bold>fonts/stsong.ttf</bold>
        <italic>fonts/stsong.ttf</italic>
        <boldItalic>fonts/stsong.ttf</boldItalic>
        <pdfEncoding>Identity-H</pdfEncoding>
        <pdfEmbedded>true</pdfEmbedded>
        <exportFonts>
            <export key="net.sf.jasperreports.html">'华文宋体',Helvetica,sans-serif</export>
            <export key="net.sf.jasperreports.xhtml">'华文宋体',Helvetica,sans-serif</export>
        </exportFonts>
    </fontFamily>
    <fontFamily name="思源黑体">
        <normal>fonts/SourceHanSansCN.ttf</normal>
        <bold>fonts/SourceHanSansCN.ttf</bold>
        <italic>fonts/SourceHanSansCN.ttf</italic>
        <boldItalic>fonts/SourceHanSansCN.ttf</boldItalic>
        <pdfEncoding>Identity-H</pdfEncoding>
        <pdfEmbedded>true</pdfEmbedded>
        <exportFonts>
            <export key="net.sf.jasperreports.html">'思源黑体',Arial</export>
            <export key="net.sf.jasperreports.xhtml">'思源黑体',Arial</export>
        </exportFonts>
    </fontFamily>
</fontFamilies>

原理分析:https://www.cnblogs.com/xyyz120/p/12681258.html

3.3.复制字体文件(必须是.ttf格式)

4. 编写Java代码

package com.hsmus;

import net.sf.jasperreports.engine.*;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.*;

public class PDFMaker {
    public static void main(String[] args) throws JRException, IOException {
        String sourceFilePath = PDFMaker.class.getResource("/pdf_template/demo1.jrxml").getPath();
        String targetFilePath = PDFMaker.class.getResource("/pdf_template/").getPath() + "demo1.jasper";
        compileXML(sourceFilePath, targetFilePath);
        writeByJavaBean(targetFilePath);
    }

    /**
     * 编译jrxml文件,如果修改过jrxml文件,务必删除已经编译过的jasper
     *
     * @param sourceFilePath jrxml文件路径
     * @param targetFilePath jasper目标文件路径
     */
    private static void compileXML(String sourceFilePath, String targetFilePath) throws JRException {
        File file = new File(targetFilePath);
        if (!file.exists()) {
            System.out.println("jasper文件不存在,正在编译...");
            JasperCompileManager.compileReportToFile(sourceFilePath, targetFilePath);
        } else {
            System.out.println("jasper文件存在,跳过编译...");
        }
    }

    /**
     * 通过填充数据生成PDF
     * @param targetFilePath jasper目标文件路径
     * @throws JRException
     * @throws IOException
     */
    private static void writeByJavaBean(String targetFilePath) throws JRException, IOException {
        System.out.println("正在填充数据...");
        // 构造数据
        Map<String, Object> parameter = new HashMap<String, Object>();
        parameter.put("username", "王小明");
        parameter.put("business_name", "5G高速通信网络开通");
        parameter.put("item_amount", "500.00");

        List<Map> list = new ArrayList<Map>();
        Map<String, Object> itemMap = new HashMap<String, Object>();
        itemMap.put("item_id", "KT0001");
        itemMap.put("item_name", "业务开通");
        itemMap.put("item_price", 200.00f);
        itemMap.put("item_count", 1);
        itemMap.put("item_amount", 1 * 200f);
        itemMap.put("item_remark", "一年的使用");
        list.add(itemMap);

        itemMap = new HashMap<String, Object>();
        itemMap.put("item_id", "KT0002");
        itemMap.put("item_name", "香蕉手机购买");
        itemMap.put("item_price", 9000.00f);
        itemMap.put("item_count", 1);
        itemMap.put("item_amount", 1 * 9000f);
        itemMap.put("item_remark", "三年免费换新");
        list.add(itemMap);

        parameter.put("all_amount", "19900.00");

        JasperPrint jasperPrint = JasperFillManager.fillReport(
                targetFilePath,
                parameter,
                new JRBeanCollectionDataSource(list)
        );

        System.out.println("正在输出...");

        String pdfPath = "D:\\test" + new Date().getTime() + ".pdf";
        // 1.直接输出到文件,适合本地操作
        // JasperExportManager.exportReportToPdfFile(jasperPrint, pdfPath);

        // 2.输出到fileOutputStream,方便改造成在网站上导出
        FileOutputStream fileOutputStream = new FileOutputStream(pdfPath);
        JasperExportManager.exportReportToPdfStream(jasperPrint, fileOutputStream);
        fileOutputStream.close();
        System.out.println("输出完成:" + pdfPath);

        /*
            // 网站输出记得设置响应头信息
            response.setContentType("application/pdf");
            response.setHeader("Content-Disposition", "attachment;filename=report.pdf");
         */

    }
}

5.结果

运行结果
PDF结果

扫码在手机查看