「Java工具类」pdf导出工具类java导出pdf文件工具类
介绍语
本号主要是Java常用关键技术点,通用工具类的分享;以及springboot+springcloud+Mybatisplus+druid+mysql+redis+swagger+maven+docker等集成框架的技术分享;datax、kafka、flink等大数据处理框架的技术分享。文章会不断更新,欢迎码友关注点赞收藏转发!
望各位码友点击关注,冲1000粉。后面会录制一些视频教程,图文和视频结合,比如:图书介绍网站系统、抢购系统、大数据中台系统等。技术才是程序猿的最爱,码友们冲啊
如果码友觉得代码太长,可以从头到尾快速扫射一遍,了解大概即可。觉得有用后再转发收藏,以备不时之需。
正文:
pdf工具类,前面excel导出的时候一个码有问有没有pdf的工具类,我翻看了一下项目,没找到。以前有一个项目是有pdf导出的,主要是导出一些发函有公章的文件,还有需求是导出报销发票有公章等的文件,都是定制化的,耦合太大了,有些项目是要求导出网页的内容,这个是前端直接导出pdf,根本不需要后端支持。所以我自己整理写了一个工具类,抛砖引玉,有需求的码友可以自己根据公司需求定制pdf的生成工具类。这里只是给出一个非常基本的工具类,仅提供导出,仅供参考。
使用例子
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
public class PdfUtilTest {
@Test
public void createTest(){
List<PdfChapter> pdfChapters = new ArrayList<>();
pdfChapters.add(createContent());
pdfChapters.add(createContent());
pdfChapters.add(createContent());
PdfUtil.getInstance().init().create("test14.pdf").chapters(pdfChapters).build();
}
private PdfChapter createContent(){
PdfChapter pdfChapter = new PdfChapter();
pdfChapter.setTitle("Pdf工具类");
pdfChapter.setOrder(1);
PdfSection section = new PdfSection();
section.setTitle("工具类例子1");
PdfText pdfText = new PdfText();
pdfText.setText("工具类内容内容");
pdfText.setImage(true);
pdfText.setImagePath("C:\\Users\\liangxn\\Desktop\\2021-11-06_002429.png");
section.getPdfTexts().add(pdfText);
pdfChapter.getSections().add(section);
return pdfChapter;
}
}
上面例子导出的pdf如下,有几页,每页的内容是一样的,含有一张图片。这里提一下,图片和内容的布局,不是那么简单的,需要根据需求定制代码。
工具类源码:
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.util.List;
/**
* pdf工具类,主要是实现了导出功能。
* 使用itextpdf包实现
*/
public class PdfUtil {
private static final Logger logger = LoggerFactory.getLogger(PdfUtil.class);
// pdf大小,设置为A4纸大小
public static final Rectangle PAGE_SIZE = PageSize.A4;
// 设置内容距离纸张上右下左的距离
public static final float MARGIN_LEFT = 50;
public static final float MARGIN_RIGHT = 50;
public static final float MARGIN_TOP = 50;
public static final float MARGIN_BOTTOM = 50;
// 空格的间距大小
public static final float SPACING = 20;
// 标题对齐方式: 0表示left,1表示center
public static final int TITLE_ALIGNMENT = 1;
private static volatile PdfUtil instance = null;
// pdf文档
private Document document = null;
//文章标题字体
private Font _chapterFont = null;
//小节标题字体
private Font _sectionFont = null;
//内容字体
private Font _textFont = null;
private PdfUtil() {
}
//DCL (Double Check Lock 双端捡锁机制)
public static PdfUtil getInstance() {
if (instance == null) {
synchronized (PdfUtil.class) {
if (instance == null) {
instance = new PdfUtil();
}
}
}
return instance;
}
/**
* 初始化字体
*/
protected PdfUtil init() {
// 默认设置
_chapterFont = createFont(20, Font.BOLD, new BaseColor(0, 0, 255));
_sectionFont = createFont(16, Font.BOLD, new BaseColor(0, 0, 255));
_textFont = createFont(10, Font.NORMAL, new BaseColor(0, 0, 0));
return instance;
}
/**
* 初始化字体
*/
protected PdfUtil init(Font chapterFont, Font sectionFont, Font textFont) {
// 使用自定义的字体
_chapterFont = chapterFont;
_sectionFont = sectionFont;
_textFont = textFont;
return instance;
}
/**
* 创建pdf文件
*
* @param fileName 文件(全路径文件名)
*/
protected PdfUtil create(String fileName) {
File file = new File(fileName);
document = new Document(PAGE_SIZE, MARGIN_LEFT, MARGIN_RIGHT, MARGIN_TOP, MARGIN_BOTTOM);
FileOutputStream out = null;
try {
out = new FileOutputStream(file);
PdfWriter.getInstance(document, out);
} catch (FileNotFoundException e) {
logger.error("创建pdf文件异常", e);
} catch (DocumentException e) {
logger.error("创建pdf文件错误", e);
}
// 打开文档准备写入内容
document.open();
return instance;
}
protected PdfUtil chapters(List<PdfChapter> pdfChapters) {
try {
for (PdfChapter pdfChapter : pdfChapters) {
Chapter chapter = writeChapter(pdfChapter);
for (PdfSection pdfSection : pdfChapter.getSections()) {
Section section = writeSection(chapter, pdfSection);
for (PdfText pdfText : pdfSection.getPdfTexts()) {
if(pdfText.isImage()){
writeImage(pdfText.getImagePath());
}
if(pdfText.getText() != null){
section.add(writePhrase(pdfText.getText()));
}
}
}
document.add(chapter);
}
} catch (DocumentException e) {
e.printStackTrace();
}
return instance;
}
protected void build(){
closeDocument();
}
/**
* 写章节
*
* @param pdfChapter
*/
private Chapter writeChapter(PdfChapter pdfChapter) {
Paragraph chapterTitle = new Paragraph(pdfChapter.getTitle(), _chapterFont);
chapterTitle.setAlignment(TITLE_ALIGNMENT);
Chapter chapter = new Chapter(chapterTitle, pdfChapter.getOrder());
chapter.setNumberDepth(pdfChapter.getDepth());
return chapter;
}
/**
* 写片段
*
* @param chapter
* @param pdfSection
* @return
*/
private Section writeSection(Chapter chapter, PdfSection pdfSection) {
Section section = null;
if (chapter != null) {
Paragraph sectionTitle = new Paragraph(pdfSection.getTitle(), _sectionFont);
sectionTitle.setSpacingBefore(SPACING);
section = chapter.addSection(sectionTitle);
section.setNumberDepth(pdfSection.getDepth());
}
return section;
}
/**
* 写内容
*
* @param text
*/
private Phrase writePhrase(String text) {
return new Paragraph(text, _textFont);
}
/**
* 写图片
*
* @param image
*/
private void writeImage(String image) {
try {
//图片1
Image image1 = Image.getInstance(image);
//将图片1添加到pdf文件中
document.add(image1);
} catch (IOException e) {
logger.error("写入图片异常", e);
} catch (DocumentException e) {
logger.error("写入图片错误", e);
}
}
/**
* 功能: 返回支持中文的字体---仿宋
* <p>
* simfang.ttf 仿宋常规
* <p>
* simhei.ttf 黑体常规
*
* @param size 字体大小
* @param style 字体风格
* @param color 字体 颜色
* @return 字体格式
*/
private Font createFont(float size, int style, BaseColor color) {
BaseFont baseFont = null;
try {
// simfang.ttf文件必须放在class类文件所有的包路径下
URL resource = PdfUtil.class.getClassLoader().getResource("simfang.ttf");
if (resource == null) {
throw new MyAppRunException("无simfang.ttf字体文件");
}
logger.info("加载simfang.ttf字体, 路径:{}", resource.getPath());
baseFont = BaseFont.createFont(resource.getPath(), BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
} catch (DocumentException e) {
logger.error("加载字体错误", e);
} catch (IOException e) {
logger.error("加载字体错误", e);
}
return new Font(baseFont, size, style, color);
}
/**
* 最后关闭PDF文档
*/
private void closeDocument() {
if (document != null) {
// 执行关闭时文件会自动保存
document.close();
logger.info("文件已保存");
}
}
}
实体类:
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class PdfChapter {
private String title;
/**
* 章节序列号
*/
private int order;
/**
* 章节的层级深度 设值=1 表示带序号 1.章节一;1.1小节一...,设值=0表示不带序号
*/
private int depth = 0;
private List<PdfSection> sections = new ArrayList<>();
}
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class PdfSection {
private String title;
/**
* 否带序号 设值=1 表示带序号 1.章节一;1.1小节一...,设值=0表示不带序号
*/
private int depth = 1;
private List<PdfText> pdfTexts = new ArrayList<>();
}
import lombok.Data;
@Data
public class PdfText {
private String text;
private String imagePath;
private boolean isImage = false;
}
其他类:
/**
* 通用异常类
*/
public class MyAppRunException extends RuntimeException {
public MyAppRunException(String message) {
super(message);
}
public MyAppRunException(String message, Throwable cause) {
super(message, cause);
}
public MyAppRunException(Throwable cause) {
super(cause);
}
protected MyAppRunException(String message,
Throwable cause,
boolean enableSuppression,
boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
maven依赖
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13.2</version>
</dependency>
外话,pdf的需求基本都是需要定制的,不是一个工具类能搞定的。这里给出处理pdf的另一个包,这个包是apache的包,对于读pdf非常好用。需要定制pdf导出的话,还是需要多了解这两个包,然后定制自己的工具类。
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.24</version>
<type>bundle</type> <!-- 要使用bundle需要先依赖一个plugin,自行百度 -->
</dependency>
鄙人编码十年多,在项目中也积累了一些工具类,很多工具类在每个项目都有在用,很实用。大部分是鄙人封装的,有些工具类是同事封装的,有些工具类已经不记得是ctrl+c的还是自己封装的了,现在有空就会总结项目中大部分的工具类,分享给各位码友。如果文章中涉及的代码有侵权行为请通知鄙人处理。
计划是先把工具类整理出来,正所谓工欲善其事,必先利其器。项目中不管是普通单体项目还是多模块maven项目或是分布式微服务,一部分功能模块都是可以重用的,工具类模块就是其中之一。
作者:Java夜未眠
出处:https://www.cnblogs.com/liangxianning/p/17058241.html
版权声明:本博客所有文章除特别声明外,均采用「 MIT 许可协议。」许可协议进行许可
关于博主: 评论和私信会可能回复较慢,点击上面加人图标加我为好友吧
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)