<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>html2pdf</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.13.1</version>
</dependency>
<!-- 解决中文乱码,但是有限 -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>font-asian</artifactId>
<version>7.1.13</version>
</dependency>
import cn.hutool.core.io.file.FileReader;
import com.itextpdf.html2pdf.ConverterProperties;
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.html2pdf.attach.impl.OutlineHandler;
import com.itextpdf.io.font.otf.GlyphLine;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.WriterProperties;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.AreaBreak;
import com.itextpdf.layout.element.IBlockElement;
import com.itextpdf.layout.element.IElement;
import com.itextpdf.layout.font.FontProvider;
import com.itextpdf.layout.property.AreaBreakType;
import com.itextpdf.layout.property.Property;
import com.itextpdf.layout.splitting.DefaultSplitCharacters;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.ResourceUtils;
import java.io.*;
import java.util.List;
/**
* 导出PDF工具类
*/
@Slf4j
public class PDFU {
public static void main(String[] args) throws FileNotFoundException {
File file = ResourceUtils.getFile("D:\\fornt_workspace\\new_file.html");
String a = FileReader.create(file).readString();
a = a.replace("field","a");
a = a.replace("<div class=\"pagebreaker\"></div>","");
createPDF(a);
}
/**
* 使用 iText 生成 PDF 文档
* @param htmlTmpStr html 模板文件字符串
*/
public static ByteArrayOutputStream createPDF(String htmlTmpStr) {
htmlTmpStr = htmlTmpStr.replace("field","a");
htmlTmpStr = htmlTmpStr.replace("<div class=\"pagebreaker\"></div>","");
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
PdfWriter writer = new PdfWriter(outputStream, new WriterProperties().setFullCompressionMode(Boolean.TRUE));
PdfDocument doc = new PdfDocument(writer);
try {
doc.setDefaultPageSize(PageSize.A4);
FontProvider fontProvider = new FontProvider();
// 如果需求小的话可以使用这个解决中文乱码
// PdfFont pdfFont = PdfFontFactory.createFont("STSongStd-Light", "UniGB-UCS2-H", false);
// fontProvider.addFont(pdfFont.getFontProgram());
// 设置中文字体文件的路径,可以在classpath目录下
fontProvider.addDirectory("/usr/share/fonts/windows_fonts");
fontProvider.addSystemFonts();
ConverterProperties properties = new ConverterProperties();
properties.setFontProvider(fontProvider);
// PDF目录
properties.setOutlineHandler(OutlineHandler.createStandardHandler());
// 将html转为pdf代码块,按div生成页pdf
Document document = new Document(doc);
// 这个为了解决生成的pdf产生位移的问题
document.setMargins(0,0,0,0);
document.setProperty(Property.SPLIT_CHARACTERS, new DefaultSplitCharacters() {
@Override
public boolean isSplitCharacter(GlyphLine text, int glyphPos) {
return true;//解决word-break: break-all;不兼容的问题,解决纯英文或数字不自动换行的问题
}
});
document.setFontProvider(fontProvider);
List<IElement> iElements = HtmlConverter.convertToElements(htmlTmpStr, properties);
int size = iElements.size();
for (int i = 0; i < size; i++) {
IElement iElement = iElements.get(i);
document.add((IBlockElement) iElement);
if (!(i == size - 1)) { // 不是最后一页
// 添加新的一页
document.add(new AreaBreak(AreaBreakType.NEXT_PAGE));
}
}
document.close();
// 测试生成文件使用
// String FileNamePath = "D:\\file\\ll.pdf";
// FileOutputStream fis = new FileOutputStream(FileNamePath);
// fis.write(outputStream.toByteArray());
// result = outputStream.toByteArray();
}catch (Throwable e){
throw new RuntimeException("模板转换pdf失败,请重新填写或直接上传附件", e);
}
finally {
try {
doc.close();
writer.close();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("模板转换pdf失败,请重新填写或直接上传附件", e);
}
}
return outputStream;
}
/**
* 根据文件相对路径返回一个 BufferedReader 流
*
* @param filePath
* @return
* @throws IOException
*/
public static BufferedReader returnReaderStream(String filePath) throws IOException {
return new BufferedReader(new InputStreamReader(new ClassPathResource(filePath).getInputStream()));
}
/**
* 根据文件相对路径返回一个 BufferedReader 流
*
* @param filePath
* @return
* @throws IOException
*/
public static InputStream returnInputStream(String filePath) throws IOException {
return new ClassPathResource(filePath).getInputStream();
}
}
// 如果需求小的话可以使用这个解决中文乱码
// PdfFont pdfFont = PdfFontFactory.createFont("STSongStd-Light", "UniGB-UCS2-H", false);
// fontProvider.addFont(pdfFont.getFontProgram());
?font-asian 就是这个字体包,如果使用场景过多,可以把字体打进镜像
MAINTAINER xx@gmail.com
ENV TZ=Asia/Shanghai
ENV JAVA_OPTS="-Xms512m -Xmx1024m -Djava.security.egd=file:/dev/./urandom"
RUN ln -sf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN mkdir -p /usr/share/fonts/windows_fonts
COPY ./src/main/resources/fonts/* /usr/share/fonts/windows_fonts/
##安装字体
#RUN apt-get update && apt-get install -y fontconfig
#RUN fc-cache -f -v
# 安装字体
RUN yum install -y fontconfig
# 更新字体缓存
RUN fc-cache -f -v
#设置环境变量
ENV LANG=en_US.UTF-8 \
LANGUAGE=en_US:en \
LC_ALL=en_US.UTF-8
RUN mkdir -p /xx
WORKDIR /xx
EXPOSE 6666
ADD ./target/xx.jar ./
CMD java $JAVA_OPTS -jar xx.jar
需要把字体包放在resources/fonts下
加入字体文件,打包别忘了加上
在docker环境下,不知道为什么??fontProvider.addSystemFonts();? 获取系统字体是加载不到加入的字体文件的,但是查看系统字体是存在的,便使用
?? ??? ??? ?// 设置中文字体文件的路径
?? ??? ??? ?fontProvider.addDirectory("/usr/share/fonts/windows_fonts");
?? ??? ??? ?fontProvider.addSystemFonts();
直接制定了字体文件,以防万一又加了系统字体
catch (Throwable e){
throw new RuntimeException("模板转换pdf失败,请重新填写或直接上传附件", e);
}
?因为我这里是新增sql,但是回滚默认没有支持Throwable ,我就直接转换成了Exception,失败就不会新增sql了
a = a.replace("field","a");
a = a.replace("<div class=\"pagebreaker\"></div>","");
?前端给的html中,<field>标签,itext7不识别,跟前端约定好了 ,直接替换,在<field>的样式的隐藏属性就生效了
<div class=\"pagebreaker\">每一页都会,都带着的话,每次生成会都带一个空白页
String orginMd5 = SecureUtil.md5(htmlorg);
String updateMd5 = SecureUtil.md5(htmlupdate);
if(orginMd5.equals(updateMd5)){
//如果一致,结束
return ;
}
?这里是 每次校验模板的html是否变化。。。👿
参考的原文章的大佬的文章?
iText7 HTML转PDF(页眉、页码、水印) + 浏览器在线预览_c# itext7 htmltopdf-CSDN博客