使用itextpdf将html内容转PDF文档,并签章
依赖com.itextpdf
<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>
第一步:将指定的html内容转化成pdf文档
/*** 将指定的html内容转化成pdf文档之后,写入到指定的输出流.*/public static void write(String htmlContent, OutputStream os) {if (htmlContent == null || htmlContent.length() == 0) {return;}if (os == null) {return;}htmlContent = getIntactHtml(htmlContent);doWrite(htmlContent, os);}/*** html完整内容的前缀标识*/private static final String INTACT_FLAG = "<html>";/*** html模板,当待转换的html只是片断时,需将其插入到模板的body内.*/private static final String TEMPLATE_HTML = "<html><head><style>h2,h3,h4{text-align: center}</style></head><body style=\"font-family:微软雅黑;\">${content}</body></html>";/*** 根据提供的html内容,获取完整的html内容.** @param htmlContent html内容* @return 完整的html内容*/private static String getIntactHtml(String htmlContent) {boolean intact = htmlContent.trim().toLowerCase().startsWith(INTACT_FLAG);if (!intact) {htmlContent = TEMPLATE_HTML.replaceFirst("\\$\\{content}", htmlContent);}return htmlContent;}// pdf密码private static final byte[] PASSWORD_BYTES = "password".getBytes();/*** 实施写操作.** @param htmlContent html内容* @param os outputStream*/private static void doWrite(String htmlContent, OutputStream os) {InputStream is = new ByteArrayInputStream(htmlContent.getBytes(Charset.forName("UTF-8")));Document document = new Document();PdfWriter writer = null;try {writer = PdfWriter.getInstance(document, os);// 不可打印writer.setEncryption(null, PASSWORD_BYTES, PdfWriter.ALLOW_PRINTING, STANDARD_ENCRYPTION_40);// 不可更改writer.setEncryption(null, PASSWORD_BYTES, PdfWriter.ALLOW_MODIFY_CONTENTS, STANDARD_ENCRYPTION_40);// 不可复制writer.setEncryption(null, PASSWORD_BYTES, PdfWriter.ALLOW_COPY, STANDARD_ENCRYPTION_40);// 不可注释writer.setEncryption(null, PASSWORD_BYTES, PdfWriter.ALLOW_MODIFY_ANNOTATIONS, STANDARD_ENCRYPTION_40);// 不可填写表单域writer.setEncryption(null, PASSWORD_BYTES, PdfWriter.ALLOW_FILL_IN, STANDARD_ENCRYPTION_40);// 不可页面提取writer.setEncryption(null, PASSWORD_BYTES, PdfWriter.ALLOW_SCREENREADERS, STANDARD_ENCRYPTION_40);// 不可文档组合writer.setEncryption(null, PASSWORD_BYTES, PdfWriter.ALLOW_ASSEMBLY, STANDARD_ENCRYPTION_40);// 不可签名writer.setEncryption(null, PASSWORD_BYTES, PdfWriter.ALLOW_DEGRADED_PRINTING, STANDARD_ENCRYPTION_40);// 标题document.addTitle("title");// 作者document.addAuthor("author");// 关键字document.addKeywords("keywords");// 主题document.addSubject("subject");document.open();// html设置<body style="font-family:微软雅黑;">// 或加载字体/*XMLWorkerFontProvider fontProvider = new XMLWorkerFontProvider() {@Overridepublic Font getFont(String fontname, String encoding, boolean embedded, float size, int style, BaseColor color) {//你的字体文件的位置//这里把所有字体都设置为宋体了,可以根据fontname的值设置字体String yaHeiFontName = "msyh.ttc";//如果是ttc需要这一行,ttf不需要yaHeiFontName += ",1";Font font = null;try {font = new Font(BaseFont.createFont(yaHeiFontName, BaseFont.IDENTITY_H, BaseFont.EMBEDDED));font.setStyle(style);font.setColor(color);if (size > 0) {font.setSize(size);}} catch (DocumentException | IOException e) {}return font;}};*/XMLWorkerHelper.getInstance().parseXHtml(writer, document, is, Charset.forName(CommonConstants.DEFAULT_ENCODING));} catch (DocumentException | IOException e) {throw new BizException(10061);} finally {IOUtils.closeQuietly(is);if (null != writer) {writer.flush(); }document.close();}}
第二步:签名
private static final String KEYSTORE = "keystore.p12";// keystore密码private static final char[] PASSWORD = "xxxyyy".toCharArray();/*** @param src 需要签章的pdf文件路径* @param dest 签完章的pdf文件路径* chain 证书链* pk 签名私钥* digestAlgorithm 摘要算法名称,例如SHA-1* provider 密钥算法提供者,可以为null* cryptoStandard 数字签名格式,itext有2种* reason 签名的原因,显示在pdf签名属性中,随便填* location 签名的地点,显示在pdf签名属性中,随便填* @throws GeneralSecurityException* @throws IOException* @throws DocumentException*/public static void sign(String src, String dest) throws GeneralSecurityException, IOException, DocumentException {// Creating the reader and the stamper,开始pdf readerPdfReader reader = new PdfReader(src, PASSWORD_BYTES);// 目标文件输出流FileOutputStream os = new FileOutputStream(dest);// 创建签章工具PdfStamper ,最后一个boolean参数// false的话,pdf文件只允许被签名一次,多次签名,最后一次有效// true的话,pdf可以被追加签名,验签工具可以识别出每次签名之后文档是否被修改PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0', null, true);// 获取数字签章属性对象,设定数字签章的属性PdfSignatureAppearance appearance = stamper.getSignatureAppearance();String reason = "reason";String location = "location";appearance.setReason(reason);appearance.setLocation(location);// 设置签名的位置,页码,签名域名称,多次追加签名的时候,签名预名称不能一样// 签名的位置,是图章相对于pdf页面的位置坐标,原点为pdf页面左下角// 四个参数的分别是,图章左下角x,图章左下角y,图章右上角x,图章右上角y//appearance.setVisibleSignature(new Rectangle(450, 747, 550, 847), 1, "sig1");// 读取图章图片,这个image是itext包的image//Image image = Image.getInstance(new ClassPathResource(SIGNATURE).getFile().getAbsolutePath());//appearance.setSignatureGraphic(image);appearance.setCertificationLevel(PdfSignatureAppearance.NOT_CERTIFIED);// 设置图章的显示方式,如下选择的是只显示图章(还有其他的模式,可以图章和签名描述一同显示)appearance.setRenderingMode(PdfSignatureAppearance.RenderingMode.GRAPHIC);// 这里的itext提供了2个用于签名的接口,可以自己实现,后边着重说这个实现// 摘要算法ExternalDigest digest = new BouncyCastleDigest();// 签名算法String provider = null;String digestAlgorithm = DigestAlgorithms.SHA1;KeyStore ks = KeyStore.getInstance("PKCS12");InputStream inputStream = new ClassPathResource(KEYSTORE).getInputStream();ks.load(inputStream, PASSWORD);String alias = ks.aliases().nextElement();PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);ExternalSignature signature = new PrivateKeySignature(pk, digestAlgorithm, provider);// 调用itext签名方法完成pdf签章MakeSignature.CryptoStandard cryptoStandard = MakeSignature.CryptoStandard.CMS;Certificate[] chain = ks.getCertificateChain(alias);MakeSignature.signDetached(appearance, digest, signature, chain, null, null, null, 0, cryptoStandard);// Closes the document. No more content can be written after the document is closed.stamper.close();inputStream.close();}
集成示例
@RequestMapping(path = "pdf-get", method = RequestMethod.GET)public void getPdfContract(HttpServletResponse response) throws IOException {String fileName = "contract.pdf";response.setCharacterEncoding("UTF-8");response.setContentType("application/octet-stream");response.setHeader("Content-disposition", "attachment;filename=" + fileName);response.flushBuffer();File file = new File(fileName);// 需要填充的数据Object data = null; ItextpdfUtils.generatePDFFromHtmlContent(template.getContent(), data, file);FileInputStream fileInputStream = new FileInputStream(file);byte b[] = new byte[1024];int j;ServletOutputStream os = response.getOutputStream();while ((j = fileInputStream.read(b)) != -1) {os.write(b, 0, j);os.flush();}fileInputStream.close();os.close();FileUtils.deleteQuietly(file);}/*** 把html形式的合同模板转换为PDF** @param content 合同模板内容-未设值* @param object 数据(对象/Map)*/public static void generatePDFFromHtmlContent(String content, Object object, File file) {File copyFile = new File("copy-" + file.getName());FileOutputStream os = null;try {if (!copyFile.exists()) {boolean result = copyFile.createNewFile();if (result) {LOG.info("The named copy file does not exist and was successfully created");} else {LOG.info("The named copy file already exists");}}// 如需要,可以使用freemarker对html文本进行数据填充,FreemarkerUtils可自行编写// content = FreemarkerUtils.parseString(content, object);os = new FileOutputStream(copyFile);// HTML转PDFItextpdfUtils.write(content, os);// 数字签名ItextpdfUtils.sign(copyFile.getAbsolutePath(), file.getAbsolutePath());} catch (IOException | GeneralSecurityException | DocumentException e) {LOG.error(e.getMessage());} finally {IOUtils.closeQuietly(os);FileUtils.deleteQuietly(copyFile);}}
使用itextpdf将html内容转PDF文档,并签章相关推荐
- 为什么大家都在用 PDF? PDF 文档怎么修改?
"为什么我们用 PDF,不用 PPT?相近的功能,明明是 PPT 更方便修改呀!" 以 PDF 文档的格式将方案.报表.图文呈现给客户,似乎是职场上约定俗成的规则.这像是一个&qu ...
- 用Python提取解析pdf文档中内容
用Python提取解析pdf文档中内容 文章目录: 参考: 1.https://blog.csdn.net/tmaczt/article/details/82876018 # Tika库 2.http ...
- Java使用PDFBox开发包实现对PDF文档内容编辑与保存
pdfbox开发包下载地址:http://pdfbox.apache.org/ 程序实现了PDF文档的创建,读入,与修改PDF内容并保存. 可能有个前提,PDF文档不是加密的,如果加密怎么办,我没研究 ...
- 使用HttpHandler解析并展示PDF文档内容
前言 如果我们想将服务端的PDF文档内容展示给客户端,往往会通过URL直接访问的方式.这样一来,PDF文档就会毫无保留的保存到客户端去,通过浏览器的PDF插件,客户端可以随意拷贝PDF的副本.(如下图 ...
- java中operationBox_Java使用PDFBox开发包实现对PDF文档内容编辑与保存
pdfbox开发包下载地址:http://pdfbox.apache.org/ 程序实现了PDF文档的创建,读入,与修改PDF内容并保存. 可能有个前提,PDF文档不是加密的,如果加密怎么办,我没研究 ...
- 怎样在页面上查找请求内容_怎样快速裁剪删除PDF文档的页面内容?
有时在编辑PDF文档时,有大段的内容需要删除,且又不是整页无法直接通过删除页面解决,特别是扫描件无法直接用delete键清除时,有什么办法能快速解决呢?如何直接裁切不需要或保留需要的内容部分呢? 首先 ...
- HttpHandler解析并展示PDF文档内容
2019独角兽企业重金招聘Python工程师标准>>> HttpHandler 解析并展示 PDF 文档内容 如果我们想将服务端的 PDF 文档内容展示给客户端,往往会通过 URL ...
- 编辑PDF文档内容有哪些方法
PDF文件采用的是字型嵌入系统,能将字型随文件一起进行传输,所以文档在浏览查看以及传输上要优于word文档文档格式,但是这种文档在编辑的时候就没那样简单了,要是在遇到PDF格式的文档需要编辑该怎样去处 ...
- java操作office和pdf文件java读取word,excel和pdf文档内容
在平常应用程序中,对office和pdf文档进行读取数据是比较常见的功能,尤其在很多web应用程序中.所以今天我们就简单来看一下Java对word.excel.pdf文件的读取.本篇博客只是讲解简单应 ...
最新文章
- [认证授权] 5.OIDC(OpenId Connect)身份认证授权(扩展部分)
- w ndows8怎么连接网络,(Wndows8.1优化设置全面解析.doc
- 引:善用backtrace解决大问题
- 今天我开通了51cto的博客
- 2018年工业机器人销量排位_报告显示中国工业机器人销量排名世界前三
- 保存最大的前20项暴力--Heritage of skywalkert
- docker学习记录 docker 脚本----gitlab,nexus3(二)
- centos6安装mysql并远程连接_Linux中Mysql不支持远程连接解决办法
- 【二分答案】【中位数】codeforces 394 bun
- 基于TCP/IP的IEC60870-5-104远动通信协议
- 在线教育开源源码:消费者如何规避线上教育“陷阱”营销?
- html 编辑cad图,cad制图是什么
- Three.js点击地图动态标注
- 第七章 1什么是活动目录?活动目录有那些优点?
- 项目实战|史上最简单的springboot 整合elk教程,实现日志收集(带视频哦)
- 什么是计算机网络AP,无线AP是什么
- python可以数独游戏吗_简单实现python数独游戏
- 中国网络教育行业市场需求及十四五发展新挑战研究报告2021-2027年
- VMware上安装centOS,能ping通本地,但是ping不了外网怎么办
- 数据治理管理平台的5种能力