itextpdf(html2pdf)有这样的坑?java导出pdf必看

背景

        公司最近有做做Java导出pdf的需求,因为之前没有做过的缘故,所以从网上找来了itextpdf的包,前期做的还是非常顺利的,本地测试都是非常的顺利,正当我以为导出pdf如此简单的时候,上Linux测试就踩了大坑。

com.itextpdfhtml2pdf2.0.2com.itextpdffont-asian7.1.2
import com.itextpdf.html2pdf.ConverterProperties;
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.html2pdf.resolver.font.DefaultFontProvider;
import com.itextpdf.kernel.colors.Color;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.canvas.draw.ILineDrawer;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.LineSeparator;import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;public class PdfUtil {/*** @param html html页面字符串* @return* @throws FileNotFoundException* @throws IOException* @Description 将html转换为pdf文件*/public ByteArrayOutputStream html2Pdf(String html) throws FileNotFoundException, IOException {
//       PdfFont font = PdfFontFactory.createFont("STSongStd-Light", "UniGB-UCS2-H", false);ConverterProperties props = new ConverterProperties();DefaultFontProvider defaultFontProvider = new DefaultFontProvider(false, false, false);defaultFontProvider.addFont(this.getClass().getClassLoader().getResource("../conf/simkai.ttf").getPath());defaultFontProvider.addSystemFonts();props.setFontProvider(defaultFontProvider);ByteArrayOutputStream bao = new ByteArrayOutputStream();PdfWriter writer = new PdfWriter(bao);PdfDocument pdf = new PdfDocument(writer);pdf.setDefaultPageSize(new PageSize(595, 14400));Document document = HtmlConverter.convertToDocument(html, pdf, props);EndPosition endPosition = new EndPosition();LineSeparator separator = new LineSeparator(endPosition);document.add(separator);document.getRenderer().close();PdfPage page = pdf.getPage(1);float y = endPosition.getY() - 36;page.setMediaBox(new Rectangle(0, y, 595, 14400 - y));document.close();return bao;}/*** 定义操作区域*/class EndPosition implements ILineDrawer {// y坐标protected float y;/*** @return* @Description: 获取y坐标*/public float getY() {return y;}/*** @param pdfCanvas:操作画布* @param rect:操作区域* @Description: 操作画布特定区域*/@Overridepublic void draw(PdfCanvas pdfCanvas, Rectangle rect) {this.y = rect.getY();}/*** @return* @Description: 获取行颜色*/@Overridepublic Color getColor() {return null;}/*** @return* @Description: 获取行宽*/@Overridepublic float getLineWidth() {return 0;}/*** @param color* @Description: 设置行颜色*/@Overridepublic void setColor(Color color) {}/*** @param lineWidth:宽度* @Description: 设置行宽*/@Overridepublic void setLineWidth(float lineWidth) {}}public static void main(String args[]) throws IOException {String htmlStr = "

 2021年12月6日,工信部发布关于规范旅居车辆《公告》申报要求的通知。

\n" +"

\"\"

\n" +"

  各车辆生产企业及检验检测机构:

\n" +"

  为进一步规范旅居车辆《公告》产品准入申报工作,经请示工业和信息化部装备工业一司同意,现将旅居车辆产品准入申报相关要求通知如下:

\n" +"

  一、相关申报要求

\n" +"

  1、申报《公告》产品准入的旅居车辆产品(含旅居挂车)应满足相关国家强制性标准的技术要求。同时,旅居车辆的内部空间应设计合理,能够满足旅居生活功能的要求。至少应具备独立的卫生设施使用空间;车内高度(车厢地板到车厢内顶蓬的距离)不低于1750mm;相关设备设施应在车内固定,方便操作使用。

\n" +"

  2、旅居车辆(含旅居挂车)申报产品准入时,企业应提供车辆内部专用装置、设施的具体情况说明。包括(但不限于):内部生活设施固定方式;供排水系统布置;车辆配备的报警装置(烟雾、气体等)及应急逃生口位置等。

\n" +"

  3、旅居车辆(含旅居挂车)申报产品准入时,企业应提供相应的内部装置照片和图纸。包括:车内专用装置设施布置简图、照片;车辆内部空间布置尺寸简图、车门尺寸标注简图。

\n" +"

  二、实施要求

\n" +"

  1、自2022年1月1日起,申报《公告》(第352批)的新产品应满足以上要求;

\n" +"

  2、对于已《公告》的旅居车辆产品,应在2022年3月31日前完成相关车辆信息的补充和整改工作。

";PdfUtil pdfUtil = new PdfUtil();ByteArrayOutputStream stream = pdfUtil.html2Pdf(htmlStr);FileOutputStream fileOutputStream = new FileOutputStream("D://test.pdf");fileOutputStream.write(stream.toByteArray());} }

当Linux服务器上没有字体报错怎么办?

        当我将需求搞定以后,上Linux上测试时老报Font Provider contains zero fonts. At least one font shall be present。遇到这种情况我就很奇怪,Linux上没有字体吗?明明有加itextpdf的font-asian-7.1.2.jar,经过后续的排查发现原来测试服务器上头并没有加任何的字体,于是从网上找到了相关命令yum -y install fontconfig,结果下载一堆乱七八糟的字体,一个简体都没有(该结果导致最后导出来的pdf中一个中文都没有),没办法。通过领导的提示,从win10本地环境下的fonts文件夹中拿了ttc与ttf(ttf是ttc的集合体)楷体字体,后测试发现,加载ttc不好使,于是换ttf。

        原以为到这里就结束了,但是因为我在做手动加载的时候指定的是绝对路径,这样导致的后果就是路径写死,需要改成相对路径。

如何根据相对路径读取字体?

        当我想改成相对路径时才发现,我们当前的项目是利用Jenkins打包,并且是打的压缩包,而不是一个整体的jar,所以这个tar.gz中包含bin,conf和lib。验证的时候堪称泪如雨下,因为我们是利用Jenkins打包,每次都是通过git的版本部署,所以我在验证的时候,改一下,提交一个版本,测一下,再改。到现在为止已经打了几十个标签!!!全都是测试的时候,没法在本地测试,上Linux测试不成,继续改的结果。

defaultFontProvider.addFont(this.getClass().getClassLoader().getResource("../conf/simkai.ttf").getPath());

        在利用resource获取路径时,该路径时bin目录,所以需要返回上一个目录,再找conf中的字体,这个simkai.ttf就是放在resources下的字体文件,打包完毕就放在conf下。这样加载就没有问题了,但是无法在conf文件夹下再创建文件夹,所以根据getPath()可以获取路径,但是无法加载到itextpdf的font提供容器中,我也很奇怪,试了好几次都是,所以没有办法才扔到根目录。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部