freemarker+itext5实现用模板方式,导出word和pdf(spring-boot直接可使用)

freemarker导出word、word转pdf,带附件、图片等比缩放 1、通过freemarker模板,导出word文档,同时可将word转为pdf。2、导出的word带图片,如果图片太大,可通过等比缩放解决图片尺寸变小后变形的问题。3、导出时,将文档里面的图片作为单独的附件一起下载下来;或者是还有其他文件附件需要和文档一起下载。用到的所有资源和源码都放在文章结尾了~ 阅读详情

第一步:需要引入的jar包

            <!--用于导出word文档-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-freemarker</artifactId>
            </dependency>

            <!-- 非spring-boot依赖 用于导出word文档-->
<!--            <dependency>-->
<!--                <groupId>org.freemarker</groupId>-->
<!--                <artifactId>freemarker</artifactId>-->
<!--                <version>2.3.28</version>-->
<!--            </dependency>-->
            <!-- 导出 pdf -->
            <dependency>
                <groupId>com.itextpdf</groupId>
                <artifactId>itextpdf</artifactId>
                <version>5.5.13</version>
            </dependency>
            <dependency>
                <groupId>com.itextpdf.tool</groupId>
                <artifactId>xmlworker</artifactId>
                <version>5.5.13</version>
            </dependency>
            <!--        解决Linux下导出pdf,不显示中文问题-->
            <dependency>
                <groupId>com.itextpdf</groupId>
                <artifactId>itext-asian</artifactId>
                <version>5.2.0</version>
            </dependency>

第二步:准备模板文件(当然,不使用模板在代码中拼也可以,但是有点麻烦)

模板实例文件:https://download.youkuaiyun.com/download/Copy_ing/13117006

2.1 word模板: 使用xml格式的模板文件

    说明:首先准备一个word文档,将word的内容编写为你最终要的样子.  然后另存为xml格式的文件,接着在根据自己的需要,将xml文件中要动态替换的关键字替换为${关键字} 的格式.  最后将文件后缀修改为ftl

2.2 pdf模板: 使用html格式的模板文件(对html的格式要求,比较严格,一定要仔细检查.)

    说明:首先也是创建一个word文件,编写成最终要导出的样子,然后另存为html格式的文件.然后同上.

模板文件放置位置:   

例:

第三步:(上代码)

package com.gs.hiring.app.util;

import com.gs.hiring.app.vo.customer.resume.CustomerResumeInfoVO;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Document;
import com.itextpdf.text.Font;
import com.itextpdf.text.FontProvider;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author copying
 * @date 2020/11/5 10:40
 * 根据模板文件(.ftl)生成对应的word文档
 *
 * 使用说明: 官方文档:http://freemarker.foofun.cn/dgui_misc_userdefdir.html
 *     1.首先准备一份指定格式的word文档.
 *     2.将其中的参数 修改为指定格式: ${?}  (? 字段名)
 *     3.将word文档,另存为xml格式的文件.
 *     4.修改文件后缀为.ftl
 *
 */
@Slf4j
public class ResumeWordExportUtil {
    private ResumeWordExportUtil(){
        super();
    }
    private static ResumeWordExportUtil service = null;

    public static ResumeWordExportUtil getInstance() {
        if(service == null) {
            synchronized(ResumeWordExportUtil.class){
                if(service == null) {
                    service = new ResumeWordExportUtil();
                }
            }
        }
        return service;
    }

    /**
     * 生成要导出的文件
     * @param templateFilePath
     * @param data
     * @param response
     * @param isCh
     */
    public void createResumeFile(String templateFilePath, CustomerResumeInfoVO data,Integer type, HttpServletResponse response, boolean isCh) throws Exception {
        String fileName;
        if(isCh){
            fileName=data.getChName()+" 简历";
        }else {
            fileName=data.getEnName()+" resume";
        }

        String fileType="doc";
        if(Objects.nonNull(type)){
            if(type==1){
                fileType="pdf";
            }
        }
        setResponseHeader(response,fileName,fileType);
        OutputStream out=response.getOutputStream();
        Writer responseOut = new OutputStreamWriter(out);
        try{
            Configuration configuration = new Configuration(Configuration.VERSION_2_3_28);
            configuration.setClassForTemplateLoading(this.getClass(), "/templates");
            Template template = configuration.getTemplate(templateFilePath, "UTF-8");
            if(type==1){
                Writer writerPdf=new StringWriter();
                template.process(data, writerPdf);
                String pdf=writerPdf.toString();
                Document document=new Document();
                PdfWriter pdfWriter =PdfWriter.getInstance(document,out);
                FontProvider fontProvider=new ChinaFontProvide();
                document.open();
                XMLWorkerHelper.getInstance().parseXHtml(pdfWriter,document,new ByteArrayInputStream(pdf.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8,fontProvider);
                document.close();
                responseOut = new OutputStreamWriter(out);
            }else {
                //获取头像信息
                if (isGetStandardPhoto(data.getStandardPhoto())) {
                    data.setStandardPhoto(image2Base64(data.getStandardPhoto()));
                }
                template.process(data, responseOut);
            }
        }catch (Exception e){
            throw e;
        } finally {
            try {
                responseOut.flush();
                responseOut.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 提供中文
     * 不用字体文件,显示中文的解决方法
     */
    public static final class ChinaFontProvide implements FontProvider {

        @Override
        public Font getFont(String arg0, String arg1, boolean arg2, float arg3,
                            int arg4, BaseColor arg5) {
            BaseFont bfChinese = null;
            try {
                bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return new Font(bfChinese, 10, Font.NORMAL);
        }

        @Override
        public boolean isRegistered(String arg0) {
            return false;
        }
    }

    /**
     * 判断是否获取头像
     * @return boolean
     */
    private boolean isGetStandardPhoto(String url){
        if(Objects.nonNull(url) && !"".equals(url)){
            //校验url格式
            return url.startsWith("http://") || url.startsWith("https://");
        }
        return false;
    }

    /**
     * 通过url获取图片
     * @param imgUrl  图片地址
     * @return 图片编码
     */
    public String image2Base64(String imgUrl) {
        URL url;
        InputStream is = null;
        ByteArrayOutputStream outStream = null;
        HttpURLConnection httpUrl = null;
        try{
            url = new URL(imgUrl);
            httpUrl = (HttpURLConnection) url.openConnection();
            httpUrl.connect();
            httpUrl.getInputStream();
            is = httpUrl.getInputStream();
            outStream = new ByteArrayOutputStream();
            //创建一个Buffer字符串
            byte[] buffer = new byte[1024];
            //每次读取的字符串长度,如果为-1,代表全部读取完毕
            int len;
            //使用一个输入流从buffer里把数据读取出来
            while( (len=is.read(buffer)) != -1 ){
                //用输出流往buffer里写入数据,中间参数代表从哪个位置开始读,len代表读取的长度
                outStream.write(buffer, 0, len);
            }
            // 对字节数组Base64编码
            return encodeImage(outStream.toByteArray());
        }catch (Exception e) {
            e.printStackTrace();
        }
        finally{
            if(is != null)
            {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(outStream != null)
            {
                try {
                    outStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(httpUrl != null)
            {
                httpUrl.disconnect();
            }
        }
        return imgUrl;
    }

    /**
     * 图片转字符串
     * @param image 图片
     * @return 编码
     */
    public static String encodeImage(byte[] image){
        return replaceEnter(Base64.getEncoder().encodeToString(image));
    }

    public static String replaceEnter(String str){
        String reg ="[\n-\r]";
        Pattern p = Pattern.compile(reg);
        Matcher m = p.matcher(str);
        return m.replaceAll("");
    }

    private void setResponseHeader(HttpServletResponse response, String fileName,String fileType) {
        try {
            response.reset();
            // 设置生成的文件类型
            response.setContentType("application/ms"+fileType);
            // 设置文件头编码方式和文件名
            response.setCharacterEncoding("UTF-8");
            // 在浏览器中测试生效,postman中文件名为response,无法修改
            response.setHeader("Content-disposition", "attachment;filename="
                    .concat(String.valueOf(URLEncoder.encode(fileName + "."+fileType, "UTF-8"))));
            // 此设置,可保证web端可以取到文件名
            response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     *  把路径的\替换成/
     * @param path 原地址
     * @return 处理后的地址
     */
    private String pathReplace(String path) {
        while(path != null && path.contains("\\")) {
            path = path.replace("\\", "/");
        }
        return path;
    }
}

遇到的问题:

1.直接生成的html文件格式不严谨,导致itext无法解析.

   解决方案:1.html标签必须要,一一对应,有开始,有结束.例:<tr></tr>     2.只有一行的标签必须有结束符号.例:<br/>  <meta />

2.freemarker 动态赋值时,要进行属性检查 . 具体语法请参考官方文档: http://freemarker.foofun.cn/dgui_misc_userdefdir.html

3.linux环境,导出的pdf文件不显示中文(本地导出pdf显示中文,到服务器上就不显示了)    解决方案: 由于没有设置字体文件导致,在上面代码中已经解决.

4.导出word时,无法显示图片(freemarker不支持超链接).   解决方法:在代码中获取图片,转换为Base64位编码,直接放到xml中. 

注:要是有什么问题,或对你有所帮助,欢迎点赞\评论.

 

 

Spring Boot Freemark HTML 生成 PDF、生成水印Logo、docx文件生成PDF,Jar包运行可读取模板文件、字体文件 Spring Boot Freemark HTML 生成 PDF,Jar包运行可读取模板文件、字体文件 阅读详情

相关推荐

技术研究方法论:起点思维与闭环验证实战指南

技术研究不是掌握原理的静态学习,而是面向问题解决的能力构建过程。其核心在于建立清晰的认知起点——从真实业务场景出发,理解技术能做什么、为谁服务;再通过可量化的闭环验证,将抽象概念转化为可测、可调、可交付的工程成果。这种‘以终为始’的实践路径,有效规避了知识沼泽、方案摇摆和落地失效等常见陷阱,特别适用于快速选型、低代码集成、报表引擎开发等强调实效的工程场景。本文聚焦‘起点思维’与‘闭环验证’两大关键动作,提供可立即上手的72小时最小闭环、三句话定义法、问题-方案-证据三角表等一线验证工具。

ciyinzhi8788的博客 449

2023最新SpringBoot导出PDF方式(模板方式)

在开发中经常会遇到需要进行对一些数据进行动态导出PDF文件,然后让用户自己选择是否需要打印出来,这篇文章我们来用个相对来说比较简单的方式来实现PDF动态导出;

JAVA_EE_J的博客 7340

iText通过FreeMarker模板生成PDF解决方案

iText通过FreeMarker模板生成PDF解决方案

猿小白的博客 3357

基于freemarker生成pdf

java8字符集GBK。

qq_32434535的博客 5702

sap销售发货的流程_SAP销售订单发货后如何实现发票的自动创建?

问SAP销售订单发货后如何实现发票的自动创建?答业务场景有些快消零售企业,SAP系统单据量大,单据金额少,一般在销售发货后即可确认收入。此时无需人工在系统内操作VF01或者VF04进行开票操作,可将该操作设置成后台作业进行自动批量开票,具体操作如下:1、定义任务:VF06输入完以上信息,点击保存进入以下界面:说明:当前日期的意思是“开票的日期”等于“系统电脑中的当前日期”当前日期+/-...

weixin_42358409的博客 3361

Anaconda下安装LabelImg

Anaconda下安装LabelImg

LYH8543的博客 756

Java自动化生成Word文档:从POI到poi-tl的实战指南

在企业级应用开发中,数据与文档的自动化处理是提升效率的关键技术。其核心原理在于将程序中的数据与文档的格式分离,通过模板引擎实现批量、精准的文档生成。这项技术的价值在于能够极大解放生产力,保证输出质量的一致性,尤其适用于报告生成、合同打印等需要处理结构化数据的场景。Java凭借其强大的生态和企业级应用中的稳固地位,成为处理后端文档生成任务的首选语言之一。本文聚焦于Java操作Word文档的实战方案,通过对比Apache POI、poi-tl等主流技术,深入解析如何利用模板引擎实现高效、复杂的文档自动化生产,并

weixin_30660027的博客 299

从零搭建企业网络:使用Packet Tracer模拟多区域OSPF组网全过程

本文通过Cisco Packet Tracer模拟,详细演示了从零搭建一个典型企业多区域OSPF网络的完整流程。内容涵盖网络拓扑规划、IP地址设计、多区域划分原理,并提供了从设备初始化、接口配置到OSPF多区域核心配置与验证的详细步骤。文章旨在帮助网络学习者与IT支持人员通过动手实验,将理论知识转化为实际的配置与排障能力。

day7的博客 1030

Java生成Word文档实战指南:从Apache POI选型到性能优化

在Java企业级应用开发中,自动化文档生成是常见的业务需求,尤其涉及合同、报告等格式复杂的文件输出。其核心原理基于Office Open XML(OOXML)标准,即.docx文件实质为XML描述的压缩包,使得程序化操作成为可能。从技术价值看,这能显著提升工作效率,减少人工错误,并支持大规模批量处理。在应用场景上,广泛用于财务对账、人事档案、数据报表导出等。针对Java技术栈,Apache POI作为主流库,提供了对OOXML底层元素的精细控制,但需注意其API在设置复杂样式时可能较为繁琐。而docx4j则

weixin_33957648的博客 394

嵌入式常用通信协议 #概述

嵌入式通信协议

AFK3060的博客 2116

君正T31x metartc集成测试

metartc为国内杨大侠部分开源的一款用于嵌入式领域webrtc库,它与谷歌官方webrtc相比,编译到君正平台的可执行文件仅有5M即可实现webrtc的通信。1. 目前实现的是基于开源版v5.0-b0版本做的简单修改,官方的好几个版本都多少缺点东西,我这里给整理了一下。目前是局域网连接的webrtc,后续尝试走stun和turn试一下NAT穿越的效果。

fsmpeg的博客 3157

Java生成PPT实战:Apache POI深度应用与OOXML底层控制

PPT自动化生成本质上是Office Open XML(OOXML)文档的解析与重构过程,其核心原理在于对ZIP封装内XML节点的精准操作。Java凭借纯字节码实现、无本地依赖、强合规性等优势,成为金融、政务等高安全要求场景下Office文档处理的首选技术栈。Apache POI并非黑盒渲染库,而是面向OOXML规范的底层操作工具,需深入理解EMUs坐标系、Slide Master继承机制、CT对象模型及XPath节点劫持等关键技术。其真实价值体现在数据闭环(如Flink实时计算直连)、模板复用(23+标准

axfcjwkbi259888707的博客 94

电磁场仿真软件:Sonnet_(12).Sonnet与其他软件的集成

Sonnet作为电磁场仿真领域的强大工具,不仅能够独立完成复杂的仿真任务,还可以通过与其他软件的集成,实现更高效的工作流程和更广泛的功能扩展。通过与CAD、EDA、数据处理软件、MATLAB、Python以及云计算平台的集成,Sonnet用户可以更好地利用现有设计资源,进行参数优化和结果分析,从而提升设计和仿真效率。希望本节的内容能够帮助你更好地理解和应用Sonnet的集成功能。

kkchenjj的博客 1432

大厂Java面试实录:从HashMap到AQS,八股文背后的源码真相

Java集合框架与并发编程是后端开发的核心基石,也是技术面试中高频出现的考察重点。HashMap在JDK8中为何引入红黑树?AQS如何通过CLH队列与CAS自旋实现锁的公平与非公平?这些看似“八股”的问题,本质上是数据结构、并发控制与工程折中思想的综合体现。深入理解源码级原理,不仅能从容应对面试官的连环追问,更能帮助开发者解决缓存一致性、分布式锁误删等真实生产痛点。本文以一位两年Java后端开发者的三轮大厂面试实录为线索,逐层拆解HashMap、AQS、动态代理、数据一致性等高频考点,并复盘面试官的追问逻辑

weixin_31309419的博客 122

QGraphicsView通过鼠标操作来绘制图元

在Visio和MindManager等类似的图元操作软件中,很多时候我们会通过鼠标操作来添加自定义的图元。这里就介绍一下如何在QT的图形视图框架中通过鼠标绘制来添加图元。

yang1fei2的博客 3576

华为od 面试八股文_C++_01_含答案

华为od 面试八股文_C++_01_含答案

MISAYAONE的博客 5588

java-springboot中使用freemarker模板生成并doc与pdf文件

这个功能还是我接手的别人写的……顺便吐槽下ftl模板文件是真的麻烦! 使用freemarker模板生成doc与pdf文件。一般使用freemarker模板生成doc与pdf文件的功能是因为系统中有需要固定生成的文档格式需求,本篇基本能解决这类需求。大家可以通过这篇博文进行学习和参考。 模板的上传功能就不写了,因为大家的文件的存储方式和位置都不同,只写如何生成doc和pdf的功能。 以下是代码内容: 1、controller: /** * 下载 * * @param

程序员救不了第四宇宙的博客 2211

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

springboot freemarker生成pdf文件

https://blog.youkuaiyun.com/Mrqiang9001/article/details/86241836

无术不学的博客 1617

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

springboot下freemarker导出PDF(绝对路径,相对路径加载模板方式)

springboot下freemarker导出PDF(绝对路径,相对路径加载模板方式)

卓越之识论道,平常之识论事,狭隘之识论人 2116

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

SpringBoot+Freemark根据html模板动态导出PDF

SpringBoot+Freemark根据html模板导出PDF。java导出PDF,动态导出PDF,FreeMark遍历,按条件是否显示列表

张刚的博客 1306

在Springboot环境下,使用Docx4J + Freemarker 完成word docx文件生成与Pdf文件转换(附带兼容linux字体问题处理办法)

在Springboot环境下,使用Docx4J + Freemarker 完成word docx文件生成与Pdf文件转换(附带兼容linux字体问题处理办法)前言效果展示正文docx文件模板创建Freemarker改造模板由创建好的docx文件模板与Freemarker XML模板创建Docx文件打包Windows下的ttf字体文件生成ttc字体文件包将docx文件转换为Pdf 前言 首先介绍一下当前文档产生的原因:由于工作中需要 Docx文档的生成,以及word转Pdf的转换,但在网上所查到的文章中,都或

FreezetimeLOGO的博客 6017

Spring Boot集成Freemarker和iText生成PDF文档

PDF格式文档导出,是信息系统中非常实用的一种功能,用于各种报表和文档的到处。最近正好有空,用之前项目中使用过的itext做一个简单的示例,方便以后使用。示例中,使用Freemarker生成要导出的HTML格式文档,通过Spring Boot来实现PDF文件下载。 源代码:GitHub 创建Gradle项目 需要在build.gradl...

weixin_33861800的博客 1176

itextpdf实现word模板生成文件

使用word模板生成文件,如下图,将左侧的模板生成为右侧的填充word文档。

不积跬步,无以至千里 1933

freemarker生成的word转pdf解决方案

freemarker生成的word本体是xml格式的文件,所有直接将文件后缀改为xml。 利用商业版软件spire将xml转为真正的word文件(docx),当然我使用的事免费功能,免费功能转为word后文档中会出现警告提示。(如果money到位可以直接购买商业spire,可直接转pdf,即可剩下后边步骤。免费版的转pdf文件只能是前几页,所以不适用) 利用XWPFDocument的功能将警告提示信息去除。然后利用poi里的功能将word转换为pdf文件。 废话不多说了,见代码。

wyazyf 2061

springboot 基于.ftl模板生成pdf文件

个人信息根据ftl模板生成pdf文件

疾风劲草_的博客 2620

java freemarker 动态生成word,再转pdf

1.制作模板为动态导出做准备 因为转pdf需要docx格式。所有先弄一个word模板。 保存后再复制一个将后缀名改为zip压缩包的格式。解压取出document.xml和document.xml.rels。 document.xml对图片的设置 document.xml.rels设置动态图片地址 这样模板就配好了。 2.maven配置 <!-- 如果只是想实现word导出,只需要这一...

baidu_39547612的博客 2824
上一篇: 使用itext5 解析 html 生成pdf 表格中的<td> 内容无法居中问题
下一篇: Anaconda Scrapy 安装
Copying505
博客等级 码龄9年 2粉丝 23原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值