当前位置: 首页 > news >正文

itext7 html转pdf实现

公司最近做一个交易所项目,里面涉及一个需求就是将html模板,在填充数据后转换为pdf,这样防止数据更改,下面是具体实现

1 pom文件

     <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>html2pdf</artifactId>
            <version>2.0.2</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>font-asian</artifactId>
            <version>7.1.2</version>
        </dependency>             

2 html转pdf

itext7进行html转换使用类:com.itextpdf.html2pdf.HtmlConverter
  它主要有三类操作:convertToPdf直接转换为pdf文件
           convertToDocument转为document文档,这样有利于进行pdf页面调整
           convertToElements拆解pdf标签
我这里因为html转换后会有多页,这里通过convertToDocument调整页面大小,在一页上显示所有内容;
同时我使用ByteArrayOutputStream类,这个的好处是不在本地生成文件,减少磁盘操作,但是这种方式也有人说效率不高,使用者可以斟酌后使用.
因为spring boot存在打包后resources目录文件获取不到的问题,所以我将pdf依赖的字体文件放到项目的根路径下(跟src目录同级).
package com.ssth.exchanage.excenter.common.uitls;

import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

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;

public class PDFUtil {
	private static final String FONT = "./pdf/font/NotoSansCJKsc-Regular.otf";

	/**
	 * @Description 将html转换为pdf文件
	 * @param html html页面字符串
	 * @return
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	public ByteArrayOutputStream html2Pdf(String html) throws FileNotFoundException, IOException {
		ConverterProperties props = new ConverterProperties();
		DefaultFontProvider defaultFontProvider = new DefaultFontProvider(false, false, false);
		defaultFontProvider.addFont(font);
		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;

		/**
		 * @Description: 获取y坐标
		 * @return
		 */
		public float getY() {
			return y;
		}

		/**
		 * @Description: 操作画布特定区域
		 * @param pdfCanvas:操作画布
		 * @param rect:操作区域
		 */
		@Override
		public void draw(PdfCanvas pdfCanvas, Rectangle rect) {
			this.y = rect.getY();
		}

		/**
		 * @Description: 获取行颜色
		 * @return
		 */
		@Override
		public Color getColor() {
			return null;
		}

		/**
		 * @Description: 获取行宽
		 * @return
		 */
		@Override
		public float getLineWidth() {
			return 0;
		}

		/**
		 * @Description: 设置行颜色
		 * @param color
		 */
		@Override
		public void setColor(Color color) {
		}

		/**
		 * @Description: 设置行宽
		 * @param lineWidth:宽度
		 */
		@Override
		public void setLineWidth(float lineWidth) {
		}
	}
}

3 流响应

核心是通过ByteArrayOutputStream.writeTo(HttpServletResponse.getOutputStream())方法

package com.huishi;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Service;
import com.ssth.exchanage.excenter.common.exception.ResException;
import com.ssth.exchanage.excenter.common.uitls.DateUtil;
import com.ssth.exchanage.excenter.common.uitls.PDFUtil;
import com.ssth.exchanage.excenter.controller.response.RecordApplyParamRep;
import com.ssth.exchanage.excenter.service.ProductRecordService;

@Service
public class ProductRecordServiceImp implements ProductRecordService {

	/**
	 * @Description 打印备案申请书
	 * @param res http响应
	 */
	@Override
	public void printRecord(HttpServletResponse res){
		try {
		  String htmlStr = FileUtil.readFile(null);
		  PDFUtil pdfUtil = new PDFUtil();
		  ByteArrayOutputStream stream = pdfUtil.html2Pdf(htmlStr);
		  res.setHeader("Expires", "0"); 
		  res.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
	          res.setHeader("Pragma", "public");
		  res.setContentType("application/pdf");
		  OutputStream os = res.getOutputStream();
		  stream.writeTo(os);
	          os.flush();
	          os.close();
		} catch (IOException e) {
		  log.error("printRecord {}",e.getMessage());
		  throw new ResException("-1","服务内部错误,请稍后再试!");
		}
	}
}

备注:

itext7解决中文显示问题有两种解决方式:

1 引入对应的语言包,火狐浏览器预览生成的pdf可能存在部分中文乱码问题,同时因为加载了语言包,生成的pdf更大
使用NotoSansCJKsc-Regular.otf,同时在pom中引入com.itextpdf.font-asian包.
2 设置字体:通过默认字体生成,pdf文件和html大小几乎相同,不存在浏览器预览乱码问题 
PdfFont font = PdfFontFactory.createFont("STSongStd-Light", "UniGB-UCS2-H", false);

 

使用示例链接: https://github.com/liulei3/html2pdf 

参考文件:

html转pdf: https://developers.itextpdf.com/content/itext-7-examples/itext-7-converting-html-pdf

流响应:https://developers.itextpdf.com/content/best-itext-questions-stackoverview/general-questions-about-itext/itext7-how-can-i-serve-pdf-browser-without-storing-file-server-side

转载于:https://www.cnblogs.com/chengmuyu/p/9081770.html

相关文章:

  • django常见问题
  • mysql 查询表的字段数目
  • docker run 与docker start的区别
  • qsort用法
  • Python3学习笔记-构造函数与析构函数
  • SQL Server查询优化方法(查询速度慢的原因很多,常见如下几种)
  • Java入门 | 如何傻瓜式的安装JDK和配置环境变量?
  • git 比较 change to be committed
  • MySQL DDL--ghost工具学习
  • Vue父子组件传值 | 父传子 | 子传父
  • 【转】奇异值分解(SVD)原理详解及推导
  • MaxCompute studio FAQ
  • dubbo-admin2.8.4部署
  • 时间选择控件YearPicker(基于React,antd)
  • MicroPython支持图形化编辑了:Python Editor带你轻松玩转MicroPython
  • .pyc 想到的一些问题
  • 【剑指offer】让抽象问题具体化
  • 230. Kth Smallest Element in a BST
  • 30天自制操作系统-2
  • Android系统模拟器绘制实现概述
  • gcc介绍及安装
  • Git学习与使用心得(1)—— 初始化
  • JavaScript 奇技淫巧
  • Spark VS Hadoop:两大大数据分析系统深度解读
  • uva 10370 Above Average
  • 不上全站https的网站你们就等着被恶心死吧
  • 高性能JavaScript阅读简记(三)
  • 关键词挖掘技术哪家强(一)基于node.js技术开发一个关键字查询工具
  • 记一次和乔布斯合作最难忘的经历
  • 融云开发漫谈:你是否了解Go语言并发编程的第一要义?
  • 我的面试准备过程--容器(更新中)
  • 用Node EJS写一个爬虫脚本每天定时给心爱的她发一封暖心邮件
  • 原创:新手布局福音!微信小程序使用flex的一些基础样式属性(一)
  • Prometheus VS InfluxDB
  • ​总结MySQL 的一些知识点:MySQL 选择数据库​
  • # Pytorch 中可以直接调用的Loss Functions总结:
  • #在 README.md 中生成项目目录结构
  • $emit传递多个参数_PPC和MIPS指令集下二进制代码中函数参数个数的识别方法
  • (二)Eureka服务搭建,服务注册,服务发现
  • (附源码)ssm捐赠救助系统 毕业设计 060945
  • (六) ES6 新特性 —— 迭代器(iterator)
  • (六)什么是Vite——热更新时vite、webpack做了什么
  • (论文阅读31/100)Stacked hourglass networks for human pose estimation
  • (免费领源码)Java#ssm#MySQL 创意商城03663-计算机毕业设计项目选题推荐
  • (十)【Jmeter】线程(Threads(Users))之jp@gc - Stepping Thread Group (deprecated)
  • (一)Thymeleaf用法——Thymeleaf简介
  • (译) 理解 Elixir 中的宏 Macro, 第四部分:深入化
  • (转载)VS2010/MFC编程入门之三十四(菜单:VS2010菜单资源详解)
  • .NET 8 编写 LiteDB vs SQLite 数据库 CRUD 接口性能测试(准备篇)
  • .net refrector
  • .NET 读取 JSON格式的数据
  • .NET/C# 解压 Zip 文件时出现异常:System.IO.InvalidDataException: 找不到中央目录结尾记录。
  • .NET企业级应用架构设计系列之应用服务器
  • ??javascript里的变量问题
  • @Data注解的作用