首页 > 其他分享 >服务端自定义生成PDF的几种方案

服务端自定义生成PDF的几种方案

时间:2022-10-24 12:00:12浏览次数:39  
标签:java 自定义 freemarker templateName 服务端 import PDF pdf 模板

一、itext 表单填充

使用方式:

  • itext表单填充方案是以pdf作为基础模板,通过在pdf中嵌入表单元素组件的方式(需要使用pdf编辑工具),最后由程序进行数据填充并另存为pdf结果。

方案优缺点:

  • 优点:代码优雅,生成后格式变化影响极小。
  • 缺点:原始模板变化需要重新生成pdf,重新编辑表单元素;不支持列表填充数据。

二、freemarker + doc4J 基于Word 生成 PDF

使用方式:

  • 首先将调整好格式的原始 word 导出为 XML 格式,编辑 XML 模板中需要填充元素的位置,最后由程序处理先由freemarker模板工具替换元素内容,再使用doc4J进行pdf导出。

方案优缺点:

  • 优点:通用性强,基于模板引擎功能强大。
  • 缺点:XML 格式的word真的有够复杂,想要在此模板上调整样式真的难上加难;由于系统不支持的原因需要导入中文字体库;doc4J 部分 doc 元素不支持(例如直线),导出格式差异较大。

这可能是由于doc4J迭代问题无法保证新元素的支持,导出结果比较奔放。。。

三、freemarker + aspose-words 导出PDF

使用方式:

  • 类似于 freemarker+doc4J 方式,同样需要编辑XML,导出格式相较doc4J而言有极大提升。

方案优缺点:

  • 优点:通用性强,基于模板引擎功能强大,无需手工管理字体(macOS),代码简单,导出格式与模板基本无差异。
  • 缺点:需要编辑 XML 模板;该方案不是免费版(当然有大神)。

受限于调试前期需要的修修改改,模板能给人整吐了,所以才有了下一个方案。

四、html + freemarker + itextpdf(html2pdf)

使用方式:

  • 翻译 word 为 html 页面(当然就是手写啦,还原度很重要!),html中模板元素插入(文字填充、列表循环 freemarker 支持的全都能写),最后由程序处理先由freemarker模板工具替换元素内容,再使用html2pdf进行pdf导出。

方案优缺点:

  • 优点:可维护性相较与上面方案都有极大提升(调试可见性,动态替换生效);通用性强,基于模板引擎功能强大;导出格式可控性较强;
  • 缺点:需要中文字体库。

这个方案是综合以上多次踩坑的结果,结果是显而易见的。

浅浅来一点代码,省的大家到处找

<dependencies>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>html2pdf</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-pdf-itext5</artifactId>
<version>9.0.3</version>
</dependency>
<dependency>
<groupId>binarta.oss</groupId>
<artifactId>groovy-template-enginex-freemarker</artifactId>
<version>0.1.3</version>
</dependency>
<dependencies>

个人以为自己的代码会自解释,就不贴太多注释了服务端自定义生成PDF的几种方案_html


import cn.hutool.core.io.FileUtil;
import cn.hutool.core.map.MapUtil;
import com.google.common.collect.Lists;
import com.itextpdf.text.pdf.BaseFont;
import freemarker.cache.ByteArrayTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.SneakyThrows;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;

import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.StringWriter;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.function.Supplier;

public class HtmlToPdfUtil {

private static final ByteArrayTemplateLoader TEMPLATE_LOADER = new ByteArrayTemplateLoader();

// 导入需要字体库的位置哦;simsun 为 宋体
public static final String FRONT_PATH = "/usr/share/fonts/simsun.ttc";

/**
* 看明白的话只用这个方法就够
*/
public static ByteArrayOutputStream htmlToPdf(String templateName, Supplier<byte[]> loadTemplateSupplier, Map<String, Object> modeViewMap){

String html = xmlFormat(templateName, loadTemplateSupplier, modeViewMap);

return htmlToPdf(html);
}

@SneakyThrows
public static ByteArrayOutputStream htmlToPdf(String htmlStr){
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ITextRenderer renderer = new ITextRenderer();
renderer.setDocumentFromString(htmlStr);
ITextFontResolver resolver = renderer.getFontResolver();
//添加字体,解决中文不显示的问题
resolver.addFont(FRONT_PATH, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
renderer.layout();
renderer.createPDF(outputStream);
return outputStream;
}


public static String xmlFormat(String templateName, Supplier<byte[]> loadTemplateSupplier, Map<String, Object> modeViewMap){
if (Objects.isNull(TEMPLATE_LOADER.findTemplateSource(templateName))) {
synchronized (TEMPLATE_LOADER) {
if (Objects.isNull(TEMPLATE_LOADER.findTemplateSource(templateName))) {
TEMPLATE_LOADER.putTemplate(templateName, loadTemplateSupplier.get());
}
}
}
return xmlFormat(templateName, modeViewMap);
}

@SneakyThrows
public static String xmlFormat(String templateName, Map<String, Object> modeViewMap){
Configuration cfg = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
// 指定FreeMarker模板文件的位置
cfg.setTemplateLoader(TEMPLATE_LOADER);
// 设置模板的编码格式
cfg.setEncoding(Locale.CHINA, Charset.defaultCharset().name());
// 获取模板文件 template
Template template = cfg.getTemplate(templateName, Charset.defaultCharset().name());
StringWriter stringWriter = new StringWriter();

BufferedWriter writer = new BufferedWriter(stringWriter);
template.process(modeViewMap, writer);
return stringWriter.toString();
}

}

解决这个问题的核心思路方案其实一直没变,变化的只是工具,一定要思路清晰!

标签:java,自定义,freemarker,templateName,服务端,import,PDF,pdf,模板
From: https://blog.51cto.com/u_15430445/5789049

相关文章

  • pg_basebackup备份(无自定义表空间)
    环境:OS:Centos7DB:13.81.直接备份需要提前创建好备份目录su-postgres[postgres@host134pg_backup]$mkdir-p/tmp/pg_backup/[postgres@host134pg_backup]$pg_bas......
  • 浏览器打开PDF标题乱码
    问题用itext5生成PDF后,用window.open打开生成的pdf会发现title是乱码解决办法js重置title(未解决)letw=window.open("<%=staticPath%>/"+response.message,"_blank")......
  • java下载pdf等静态文件
    packagecom.example.climbnumber;importjava.io.FileOutputStream;importjava.io.InputStream;importjava.io.OutputStream;importjava.net.URL;importjava.net......
  • C语言——自定义类型(结构体+枚举+联合)
    结构体基础知识结构是一些值的集合,这些值被称为成员变量;结构体可以存储不同类型的数据项,而数组中是存储相同类型数据项声明structtag{//struct是关键字,tag是结构体标签名......
  • hands-on design patterns with c++ 电子书 pdf
    作者:FedorGPikus出版社:PacktPublishing-ebooksAccount副标题:MastertheDesignPatternstocreaterobust,reusableandeasilymaintainableapps 链接:h......
  • android实现pdf阅读器
    添加依赖implementation'com.github.barteksc:android-pdf-viewer:3.1.0-beta.1'MainActivity文件importandroidx.appcompat.app.AppCompatActivity;importan......
  • 自定义transform的重塑
    #cartoontransformdefct(names,*args):'''names:alistofmobjectsargsr......
  • 7.Python自定义排序详解
    如果以创建的对象作为列表中的元素,那么对列表进行排序时可使用sort()函数或sorted()函数,但要注意的是:①当排序对象为列表的时候两者适合的场景不同②sorted()函数会返......
  • 配置docker 容器自定义ip 网段
    1.打开cat/etc/docker/daemon.json添加 "bip":"192.168.0.1/16",配置如下{"bip":"192.168.0.1/16","data-root":"/data/bkce/public/paas_agent/docker",......
  • 计算机体系结构基础 第三版 电子书 pdf
    作者:胡伟武等出版社:机械工业出版社 链接:计算机体系结构基础第三版  本书由国内从事微处理器设计的一线科研人员编写而成。作者从微处理器设计的角度出发,充......