springBoot+itext处理富文本转pdf
pom文件引入依赖
<!-- itext5 start -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13.2</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>com.itextpdf.tool</groupId>
<artifactId>xmlworker</artifactId>
<version>5.5.11</version>
</dependency>
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-pdf-itext5</artifactId>
<version>9.0.3</version>
</dependency>
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>core-renderer</artifactId>
<version>R8</version>
</dependency>
<!-- itext5 end -->
html转PDF方法
import com.itextpdf.text.pdf.BaseFont;
import com.lowagie.text.DocumentException;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;
import java.io.*;
/**
* @auth zhang
* @date 2021年06月06日:14:10
*/
public class HtmlToPdf {
/**
* 生成 PDF 文件-保存为流
* @param out 输出流
* @param html HTML字符串
* @throws IOException IO异常
* @throws DocumentException Document异常
*/
public static InputStream createPDF(OutputStream out, String html) throws IOException, DocumentException {
ITextRenderer renderer = new ITextRenderer();
html=html.replace(" ","");
html=html.replace("­","");
html=html.replace("“","");
html=html.replace("”","");
html=html.replaceAll("font-family:(.*?);","font-family: SimSun;");
System.out.println("html:::"+html);
renderer.setDocumentFromString(html);
// 解决中文支持问题
ITextFontResolver fontResolver = renderer.getFontResolver();
if (System.getProperty("os.name").contains("Window")) {
try {
fontResolver.addFont("C:/Windows/Fonts/simsun.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
} catch (com.itextpdf.text.DocumentException e) {
e.printStackTrace();
}
} else {
try {
fontResolver.addFont("/usr/share/fonts/win/simsun.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
} catch (com.itextpdf.text.DocumentException e) {
e.printStackTrace();
}
}
renderer.layout();
try {
renderer.createPDF(out);
} catch (com.itextpdf.text.DocumentException e) {
e.printStackTrace();
}
//转换流
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byteArrayOutputStream = (ByteArrayOutputStream) out;
InputStream resultInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
return resultInputStream;
}
/**
* 生成 PDF 文件-保存到本地
* @param out 输出流
* @param html HTML字符串
* @throws IOException IO异常
* @throws DocumentException Document异常
*/
public static void createPDFByLocal(OutputStream out, String html) throws IOException, DocumentException {
ITextRenderer renderer = new ITextRenderer();
html=html.replace(" ","");
html=html.replace("­","");
html=html.replace("“","");
html=html.replace("”","");
System.out.println("html:::"+html);
renderer.setDocumentFromString(html);
// 解决中文支持问题
ITextFontResolver fontResolver = renderer.getFontResolver();
if (System.getProperty("os.name").contains("Window")) {
try {
fontResolver.addFont("C:/Windows/Fonts/simsun.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
} catch (com.itextpdf.text.DocumentException e) {
e.printStackTrace();
}
} else {
try {
fontResolver.addFont("/usr/share/fonts/win/simsun.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
} catch (com.itextpdf.text.DocumentException e) {
e.printStackTrace();
}
}
renderer.layout();
try {
renderer.createPDF(out);
} catch (com.itextpdf.text.DocumentException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException, DocumentException {
String fileName="D:\\text\\"+"测试"+System.currentTimeMillis()+".pdf";
File file = new File(fileName);
FileOutputStream outputStream = new FileOutputStream(file);
// OutputStream outputStream=new ByteArrayOutputStream();
String customHtml="<p style=\"text-align: center; margin: 0cm; font-size: 10.5pt; font-family: 'Times New Roman', serif;\" align=\"center\"><strong><span style=\"font-size: 22pt; font-family: 宋体; color: #c00000;\">­­­­­Xx</span></strong><strong><span style=\"font-size: 22pt; font-family: 宋体; color: #c00000;\">测试一下</span></strong></p>\n" +
"<p style=\"margin: 0cm 0cm 15.6pt; text-align: center; font-size: 10.5pt; font-family: 'Times New Roman', serif;\" align=\"center\"><strong><span style=\"font-size: 22pt; font-family: 宋体; color: #c00000;\">20xx</span></strong><strong><span style=\"font-size: 22pt; font-family: 宋体; color: black;\">XXXXXXXXXXXXXXXXXX书</span></strong></p>\n";
customHtml=customHtml.replaceAll("font-family:(.*?);","font-family: SimSun;");
String html = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
"<!DOCTYPE html[\n" +
"<!ENTITY nbsp \" \">\n" +
"]><html>\n" +
"<head>\n" +
"<style type=\"text/css\">\n" +
"body {\n" +
"\tfont-family: SimSun;\n" +
"}\n" +
"</style>\n" +
"</head>\n" +
"<body>\n" +
customHtml
+
"</body>\n" +
"</html>\n";
createPDFByLocal(outputStream,html);
}
}
处理不换行
创建包
新增Breaker.java类
package org.xhtmlrenderer.layout;
/*
* Breaker.java
* Copyright (c) 2004, 2005 Torbj�rn Gannholm,
* Copyright (c) 2005 Wisconsin Court System
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
import org.xhtmlrenderer.css.constants.IdentValue;
import org.xhtmlrenderer.css.style.CalculatedStyle;
import org.xhtmlrenderer.render.FSFont;
/**
* A utility class that scans the text of a single inline box, looking for the
* next break point.
*
* @author Torbj�rn Gannholm
*/
public class Breaker {
public static void breakFirstLetter(LayoutContext c, LineBreakContext context,
int avail, CalculatedStyle style) {
FSFont font = style.getFSFont(c);
context.setEnd(getFirstLetterEnd(context.getMaster(), context.getStart()));
context.setWidth(c.getTextRenderer().getWidth(
c.getFontContext(), font, context.getCalculatedSubstring()));
if (context.getWidth() > avail) {
context.setNeedsNewLine(true);
context.setUnbreakable(true);
}
}
private static int getFirstLetterEnd(String text, int start) {
int i = start;
while (i < text.length()) {
char c = text.charAt(i);
int type = Character.getType(c);
if (type == Character.START_PUNCTUATION ||
type == Character.END_PUNCTUATION ||
type == Character.INITIAL_QUOTE_PUNCTUATION ||
type == Character.FINAL_QUOTE_PUNCTUATION ||
type == Character.OTHER_PUNCTUATION) {
i++;
} else {
break;
}
}
if (i < text.length()) {
i++;
}
return i;
}
public static void breakText(LayoutContext c,
LineBreakContext context, int avail, CalculatedStyle style) {
FSFont font = style.getFSFont(c);
IdentValue whitespace = style.getWhitespace();
// ====== handle nowrap
if (whitespace == IdentValue.NOWRAP) {
context.setEnd(context.getLast());
context.setWidth(c.getTextRenderer().getWidth(
c.getFontContext(), font, context.getCalculatedSubstring()));
return;
}
//check if we should break on the next newline
if (whitespace == IdentValue.PRE ||
whitespace == IdentValue.PRE_WRAP ||
whitespace == IdentValue.PRE_LINE) {
int n = context.getStartSubstring().indexOf(WhitespaceStripper.EOL);
if (n > -1) {
context.setEnd(context.getStart() + n + 1);
context.setWidth(c.getTextRenderer().getWidth(
c.getFontContext(), font, context.getCalculatedSubstring()));
context.setNeedsNewLine(true);
context.setEndsOnNL(true);
} else if (whitespace == IdentValue.PRE) {
context.setEnd(context.getLast());
context.setWidth(c.getTextRenderer().getWidth(
c.getFontContext(), font, context.getCalculatedSubstring()));
}
}
//check if we may wrap
if (whitespace == IdentValue.PRE ||
(context.isNeedsNewLine() && context.getWidth() <= avail)) {
return;
}
context.setEndsOnNL(false);
String currentString = context.getStartSubstring();
int left = 0;
// int right = currentString.indexOf(WhitespaceStripper.SPACE, left + 1);
int right = getStrRight(currentString, left);
int lastWrap = 0;
int graphicsLength = 0;
int lastGraphicsLength = 0;
while (right > 0 && graphicsLength <= avail) {
lastGraphicsLength = graphicsLength;
graphicsLength += c.getTextRenderer().getWidth(
c.getFontContext(), font, currentString.substring(left, right));
lastWrap = left;
left = right;
// right = currentString.indexOf(WhitespaceStripper.SPACE, left + 1);
right = getStrRight(currentString, left + 1);
}
if (graphicsLength <= avail) {
//try for the last bit too!
lastWrap = left;
lastGraphicsLength = graphicsLength;
graphicsLength += c.getTextRenderer().getWidth(
c.getFontContext(), font, currentString.substring(left));
}
if (graphicsLength <= avail) {
context.setWidth(graphicsLength);
context.setEnd(context.getMaster().length());
//It fit!
return;
}
context.setNeedsNewLine(true);
if (lastWrap != 0) {//found a place to wrap
context.setEnd(context.getStart() + lastWrap);
context.setWidth(lastGraphicsLength);
} else {//unbreakable string
if (left == 0) {
left = currentString.length();
}
context.setEnd(context.getStart() + left);
context.setUnbreakable(true);
if (left == currentString.length()) {
context.setWidth(c.getTextRenderer().getWidth(
c.getFontContext(), font, context.getCalculatedSubstring()));
} else {
context.setWidth(graphicsLength);
}
}
return;
}
private static boolean isChinese(char c) {
Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
|| ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
|| ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
|| ub == Character.UnicodeBlock.GENERAL_PUNCTUATION
|| ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
|| ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS) {
return true;
}
return false;
}
private static int getStrRight(String s, int left) {
if (left >= s.length())
return -1;
char[] ch = s.toCharArray();
for (int i = left; i < ch.length; i++) {
if (isChinese(ch[i]) || ' ' == ch[i]) {
return i == 0 ? i + 1 : i;
}
}
return -1;
}
}
ps:如果遇到大小写等生成失败的错误时,在标签上添加:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">```