Springboot导出pdf文件(idea、jar包完美运行)

思路如下:

1、制作模板(建议写静态HTML,样式会好看些):按照导出的格式弄一个word文件,然后通过转换工具转成HTML,但是一般转换的会有一些问题,需要删除一些样式字体等

推荐一个在线转换(百度随便搜一下):在线WORD转HTMLhttps://cn.office-converter.com/Word-to-HTML-Converter​​​​

在样式中添加字体样式(重要),这是不乱码的关键一步

<style type="text/css">
        body {
            font-family: "simsun";
        }
</style>

2、准备字体:simsun.tcc,在windows目录也有拷一个就行:C:\Windows\Fonts

3、在项目中导入相关的依赖,主要是Freemarker、itextpdf

        <properties>
            <flying-saucer-pdf.version>9.1.16</flying-saucer-pdf.version>
            <itextpdf.version>5.5.13</itextpdf.version>
        </properties>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
        <dependency>
            <groupId>org.xhtmlrenderer</groupId>
            <artifactId>flying-saucer-pdf</artifactId>
            <version>${flying-saucer-pdf.version}</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>${itextpdf.version}</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf.tool</groupId>
            <artifactId>xmlworker</artifactId>
            <version>${itextpdf.version}</version>
        </dependency>>

此处为核心:maven打包会压缩字体,需要排除一下

<plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <version>2.7</version>
                <configuration>
                    <nonFilteredFileExtensions>
                        <nonFilteredFileExtension>ttc</nonFilteredFileExtension>
                        <nonFilteredFileExtension>html</nonFilteredFileExtension>
                    </nonFilteredFileExtensions>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>org.apache.maven.shared</groupId>
                        <artifactId>maven-filtering</artifactId>
                        <version>1.3</version>
                    </dependency>
                </dependencies>
            </plugin>

下面贴一下核心代码:

渲染模板、渲染PDF

package com.yx.exportpdfdemo.utils;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import freemarker.template.Template;
import org.springframework.core.io.ClassPathResource;

import java.io.*;
import java.nio.charset.Charset;
import java.util.Map;


/**
 * @Author: yaoxin
 * @Description: pdf 导出工具类
 * @createDate: 2022/3/26 10:20
 **/
public class PDFUtil {
    /**
     * 字体缓存目录
     */
    private static String FONT_CACHE_DIR = null;

    /**
     * freemarker渲染html
     *
     * @param data 数据
     * @return
     */
    public static String freeMarkerRender(Map<String, Object> data, Template template) {
        Writer out = new StringWriter();
        try {
            template.setOutputEncoding("UTF-8");
            // 合并数据模型与模板
            //将合并后的数据和模板写入到流中,这里使用的字符流
            template.process(data, out);
            out.flush();
            return out.toString();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 创建pdf文件并渲染pdf
     *
     * @param content pdf内容
     * @param tempDir pdf生成目录
     * @param font    字体resource路径
     * @throws IOException
     * @throws DocumentException
     */
    public static void createPdf(String content, String tempDir, String font) throws IOException, DocumentException {
        Document document = new Document(PageSize.A4, 36.0F, 36.0F, 60.0F, 36.0F);
        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(tempDir));
        document.open();
        XMLWorkerFontProvider fontImp = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);

        /**
         * 此处从resource目录下获取字体并拷贝到临时目录,并缓存目录
         * 因为打成jar包后无法获取直接获取文件,最好是拷贝到服务器写绝对目录
         */
        if (StrUtil.isBlankOrUndefined(FONT_CACHE_DIR)) {
            File fontTemp = new File(System.getProperty("java.io.tmpdir") + File.separator + "simsun.ttc");
            if (!fontTemp.exists()) {
                fontTemp.createNewFile();
            }
            ClassPathResource simResource = new ClassPathResource(font);
            FileUtil.writeFromStream(simResource.getInputStream(), fontTemp);
            FONT_CACHE_DIR = fontTemp.getPath();
        }
        fontImp.register(FONT_CACHE_DIR);
        XMLWorkerHelper.getInstance().parseXHtml(writer, document,
                new ByteArrayInputStream(content.getBytes()), null, Charset.forName("UTF-8"), fontImp);
        document.close();
        writer.close();
    }
}

Controller:

package com.yx.exportpdfdemo.controller;

import cn.hutool.json.JSONUtil;
import com.yx.exportpdfdemo.config.PDFExportConfig;
import com.yx.exportpdfdemo.utils.PDFUtil;
import freemarker.template.Template;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author: yaoxin
 * @Description:
 * @createDate: 2022/3/28 17:23
 **/

@RestController
@AllArgsConstructor
public class UserController {

    private final FreeMarkerConfigurer freeMarkerConfigurer;

    private final PDFExportConfig pdfExportConfig;
    /**
     * 导出文件名
     */
    private static String EXPORT_NAME = "export";
    /**
     * 导出后缀
     */
    private static String EXPORT_SUFFIX = "pdf";

    /**
     * 测试导出pdf
     *
     * @param response
     */
    @SneakyThrows
    @GetMapping(value = "/export")
    public void domesticViolenceSee(HttpServletResponse response) {

        //添加测试数据
        Map<String, Object> data = new HashMap();
        data.put("username", "法外狂徒张三");
        data.put("age", "24");
        //根据配置类拿到模板名称,再通过FreeMarkerConfigurer获取Template对象
        Template template = freeMarkerConfigurer.getConfiguration().getTemplate(pdfExportConfig.getUserFtl());
        String content = PDFUtil.freeMarkerRender(data, template);
        File exportFile = File.createTempFile(EXPORT_NAME, EXPORT_SUFFIX);
        PDFUtil.createPdf(content, exportFile.getPath(), pdfExportConfig.getFont());
        FileInputStream fin;
        try {
            fin = new FileInputStream(exportFile);
            OutputStream output = response.getOutputStream();
            byte[] buf = new byte[1024];
            int r;
            response.setContentType("application/pdf;charset=GB2312");
            while ((r = fin.read(buf, 0, buf.length)) != -1) {
                output.write(buf, 0, r);
            }
            fin.close();
            output.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            exportFile.delete();
        }
    }
}

配置类:

package com.yx.exportpdfdemo.config;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

/**
 * 配置类
 */
@Configuration
@Data
public class PDFExportConfig {

    /**
     * 字体目录
     */
    @Value("${font}")
    private String font;

    /**
     * 线索报告——查看 模板名称
     */
    @Value("${user-ftl}")
    private String userFtl;


}

HTML模板:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <style type="text/css">
        body {
            font-family: "simsun";
        }
        table {
            border-collapse: collapse;
            border-spacing: 0;
            empxy-cells: show
        }

        td, th {
            vertical-align: top;
            font-size: 12px;
        }

        h1, h2, h3, h4, h5, h6 {
            clear: both;
        }

        ol, ul {
            margin: 0;
            padding: 0;
        }

        li {
            list-style: none;
            margin: 0;
            padding: 0;
        }

        /* "li span.odfLiEnd" - IE 7 issue*/
        li span. {
            clear: both;
            line-height: 0;
            width: 0;
            height: 0;
            margin: 0;
            padding: 0;
        }

        span.footnodeNumber {
            padding-right: 1em;
        }

        span.annotation_style_by_filter {
            font-size: 95%;
            background-color: #fff000;
            margin: 0;
            border: 0;
            padding: 0;
        }

        span.heading_numbering {
            margin-right: 0.8rem;
        }

        * {
            margin: 0;
        }

        .P1 {
            font-size: 10.5px;
            margin-bottom: 0in;
            margin-top: 0in;
            text-align: justify ! important;

            writing-mode: horizontal-tb;
            direction: ltr;
        }

        .Standard {
            font-size: 10.5px;

            writing-mode: horizontal-tb;
            direction: ltr;
            margin-top: 0in;
            margin-bottom: 0in;
            text-align: justify ! important;
        }

        .Table1 {
            width: 5.7611in;
            margin-left: 0.0035in;
            margin-top: 0in;
            margin-bottom: 0in;
            margin-right: auto;
            writing-mode: horizontal-tb;
            direction: ltr;
        }

        .Table1_A1 {
            padding-left: 0.075in;
            padding-right: 0.075in;
            padding-top: 0in;
            padding-bottom: 0in;
            border-width: 0.0176cm;
            border-style: solid;
            border-color: #000000;
            writing-mode: horizontal-tb;
            direction: ltr;
        }


    </style>
</head>
<body dir="ltr" style="max-width:8.2681in;margin-top:1in; margin-bottom:1in; margin-left:1.25in; margin-right:1.25in; ">
<table border="0" cellspacing="0" cellpadding="0" class="Table1">
    <colgroup>
        <col width="320"/>
        <col width="320"/>
    </colgroup>
    <p>测试导出PDF</p>
    <tr class="Table11">
        <td style="text-align:left;width:2.8806in; " class="Table1_A1"><p class="P1">姓名</p></td>
        <td style="text-align:left;width:2.8799in; " class="Table1_A1"><p class="P1">${username}</p></td>
    </tr>
    <tr class="Table11">
        <td style="text-align:left;width:2.8806in; " class="Table1_A1"><p class="P1">年龄</p></td>
        <td style="text-align:left;width:2.8799in; " class="Table1_A1"><p class="P1">${age}</p></td>
    </tr>
</table>
<p class="Standard"></p></body>
</html>

YML:

spring:
  application:
    name: demo

  freemarker:
    enabled: true
    content-type: text/html
    suffix: .html  #后缀名
    charset: UTF-8 #编码格式
    template-loader-path: classpath:/templates/ #此为freemarker默认配置
server:
  port: 8090

#字体
font: simsun.ttc
user-ftl: user-ftl.html

此为导出结果:

DEMO代码

  • 6
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
在Spring Boot中导出PDF文件可以使用第三方库,比如iText或Apache PDFBox。以下是使用iText进行PDF导出的示例代码: 首先,需要将iText库添加到项目的依赖中。在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.5.13</version> </dependency> ``` 接下来,创建一个用于导出PDF的控制器,在该控制器中定义一个处理请求的方法。在方法中使用iText库来生成PDF文件。 ```java import com.itextpdf.text.Document; import com.itextpdf.text.DocumentException; import com.itextpdf.text.Paragraph; import com.itextpdf.text.pdf.PdfWriter; import org.springframework.http.MediaType; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.OutputStream; @Controller public class PdfController { @GetMapping("/exportpdf") public void exportPdf(HttpServletResponse response) throws IOException, DocumentException { response.setContentType(MediaType.APPLICATION_PDF_VALUE); response.setHeader("Content-Disposition", "attachment; filename=example.pdf"); Document document = new Document(); OutputStream outputStream = response.getOutputStream(); PdfWriter.getInstance(document, outputStream); document.open(); document.add(new Paragraph("Hello, World!")); document.close(); outputStream.close(); } } ``` 在上述代码中,我们使用`@GetMapping`注解来处理GET请求,并指定了导出PDF的URL为`/exportpdf`。在`exportPdf`方法中,我们首先设置响应的内容类型为PDF,然后设置响应头部的Content-Disposition,指定文件名为example.pdf。 接下来,创建一个`Document`实例,并使用`PdfWriter`将文档写入输出流中。在文档中添加内容,这里我们添加了一个简单的段落"Hello, World!"。最后关闭文档和输出流。 当访问`/exportpdf`URL时,将会下载一个名为example.pdfPDF文件,其中包含"Hello, World!"的内容。 这只是一个简单的示例,你可以根据实际需求来生成更复杂的PDF文件。希望对你有所帮助!
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值