引入依赖
com.itextpdf
itextpdf
5.5.13
com.itextpdf
itext-asian
5.2.0
编写了几个实现类,可灵活用于处理pdf导出的功能,使用建造者模式编写,标题和内如可以使用默认,也可以通过 PdfFontBuilder 构建字体, PdfCellBuilder构建表格单元格进行特殊的处理。
类中含有的功能,这些功能沟可以传入自定义参数或者字体:
可以基于该工具基类,构建自己的PdfUtil来方便调用。也可以扩展方便自己的调用。
以下是测试的mian函数,列举了几个简单的例子。
public static void main(String[] args) throws DocumentException, IOException, IllegalAccessException {
StatsDayExcelDTO statsDayExcelDTO = new StatsDayExcelDTO();
statsDayExcelDTO.setIndex(1);
statsDayExcelDTO.setDate(new Date());
statsDayExcelDTO.setRealMerNo("111");
statsDayExcelDTO.setRechargeAmt("1.00");
statsDayExcelDTO.setInAmt("1.00");
statsDayExcelDTO.setPaidNum(2);
statsDayExcelDTO.setPaidAmt("2000");
statsDayExcelDTO.setPaidFailNum(0);
statsDayExcelDTO.setPaidFailAmt("0.00");
statsDayExcelDTO.setPaidRefundNum(0);
statsDayExcelDTO.setPaidRefundAmt("0.00");
statsDayExcelDTO.setOutAmt("2000");
statsDayExcelDTO.setBalance("52000");
Font font9 = PdfFontBuilder.builder().fontSize(4).build();
Font font9t = PdfFontBuilder.builder().fontSize(4).fontStyle(Font.BOLD).build();
List titles = Arrays.asList("标题1", "标题2", "标题3", "标题4");
PdfBuilder.builder("E:\\test.pdf").title("11111")
.title(BaseColor.RED, "11111")
.smallTitle("11111111")
.smallTitle(BaseColor.DARK_GRAY, "11111111")
.blank()
.text("1111111111")
.blank()
.text(3,BaseColor.BLUE,"搜集了各方面资料总结了下面几点")
.blank()
// 新建表格-类,传入List,使用默认单元格样式和字体
.table(PdfTableBuilder.builder(titles.size())
.titleRow(titles)
.row(titles)
.row(titles)
.row(titles)
.build())
.blank()
// 新建表格-类,传入对象,使用默认单元格样式和字体
.table(PdfTableBuilder.builder(statsDayExcelDTO.getClass())
.titleRow(statsDayExcelDTO.getClass())
.row(statsDayExcelDTO)
.row(statsDayExcelDTO)
.row(statsDayExcelDTO)
.build())
// 新建表格-类,传入字体
.table(PdfTableBuilder.builder(statsDayExcelDTO.getClass())
.titleRow(font9t, statsDayExcelDTO.getClass())
.row(font9, statsDayExcelDTO)
.row(font9, statsDayExcelDTO)
.row(font9, statsDayExcelDTO)
.build())
.sign("E:\\sign.png")
.build();
}
表格处理时,传入的是对象,需要结合EasyExcel的 @ExcelProperty来使用,因为excel和pdf一般都都会有的,所有没有再自定义注解来获取标题名称,直接使用EasyExcel的内容。下面是测试main中使用的类。
package com.ah.ums.dto.gw.excel;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* 代付日结算报表
*
* @author cxchen0
*/
@Data
public class StatsDayExcelDTO implements Serializable {
@ExcelIgnore
private static final long serialVersionUID = 3368348957393656788L;
@ExcelProperty("序号")
private Integer index;
@ExcelProperty("日期")
@DateTimeFormat("yyyy-MM-dd")
private Date date;
@ExcelProperty("商户号")
private String realMerNo;
@ExcelProperty("充值总额")
private String rechargeAmt;
@ExcelProperty("收入总额")
private String inAmt;
@ExcelProperty("代付总数")
private Integer paidNum;
@ExcelProperty("代付总额")
private String paidAmt;
@ExcelProperty("代付退款总数")
private Integer paidRefundNum;
@ExcelProperty("代付退款总额")
private String paidRefundAmt;
@ExcelProperty("代付失败总数")
private Integer paidFailNum;
@ExcelProperty("代付失败总额")
private String paidFailAmt;
@ExcelProperty("支出总额")
private String outAmt;
@ExcelProperty("余额")
private String balance;
}
package com.ah.ums.service.pdf;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Font;
import com.itextpdf.text.pdf.BaseFont;
import com.mysql.cj.util.LRUCache;
/**
* 基类
* @author chenjian
* @version 1.0
* @date 2023/6/15
*/
public abstract class PdfBase {
/**
* 默认标题字体大小
*/
protected static final float CELL_PADDING = 6F;
/**
* 默认标题字体大小
*/
protected static final int TITLE_FONT_SIZE = 16;
/**
* 默认小标题字体大小
*/
protected static final int SMALL_TITLE_FONT_SIZE = 13;
/**
* 默认内容字体大小
*/
protected static final int TEXT_FONT_SIZE = 9;
protected static BaseFont BASE_FONT;
static {
try {
BASE_FONT = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 缓存自定义字体,最多存放128个
*/
protected static final LRUCache cacheMap = new LRUCache<>(128);
/**
* 构造画笔类
*/
public static class PdfFontBuilder {
/**
* 单元格 字体大小
*/
private Integer fontSize = TEXT_FONT_SIZE;
/**
* 字体样式 0-Font.NORMAL, 1-Font.NORMAL, 2-Font.NORMAL, 3-Font.NORMAL, 4-Font.NORMAL, 5-Font.NORMAL, 6-Font.NORMAL, 7-Font.NORMAL, 8-Font.NORMAL, 9-Font.NORMAL
*/
/**
* 字体样式
*
* Font.NORMAL (0) 正常
* Font.BOLD (1) 加粗
* Font.ITALIC (2) 倾斜
* Font.UNDERLINE (3) 下划线
* Font.STRIKETHRU (4)
* Font.BOLDITALIC (5) 加粗倾斜
*
*/
private Integer fontStyle = Font.NORMAL;
/**
* 字体颜色
*/
private BaseColor fontColor = BaseColor.BLACK;
/**
* 构造类
*/
public static PdfFontBuilder builder() {
return new PdfFontBuilder();
}
/**
* 构造函数,默认纸张A4
*/
private PdfFontBuilder() {
}
@Override
public String toString() {
return "PdfFont[" + fontSize + "," + fontStyle + "," + fontColor + "]";
}
public PdfFontBuilder fontSize(int fontSize) {
this.fontSize = fontSize;
return this;
}
public PdfFontBuilder fontStyle(int fontStyle) {
this.fontStyle = fontStyle;
return this;
}
public PdfFontBuilder fontColor(BaseColor fontColor) {
this.fontColor = fontColor;
return this;
}
public Font build() {
Font font;
if (cacheMap.containsKey(this.toString())) {
font = cacheMap.get(this.toString());
} else {
font = new Font(BASE_FONT, fontSize, fontStyle, fontColor);
cacheMap.put(this.toString(), font);
}
return font;
}
}
}
package com.ah.ums.service.pdf;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
/**
* PDF表格处理
*
* @author chenjian
* @version 1.0
* @date 2023/6/15
*/
public class PdfTableBuilder extends PdfBase{
/**
* 表格列数
*/
private int colSize;
/**
* 表格
*/
private PdfPTable table;
/**
* 构造类
* @return com.ah.ums.service.pdf.PdfTableBuilder
*/
public static PdfTableBuilder builder(int colSize) {
return new PdfTableBuilder(colSize);
}
/**
* 构造类
* @return com.ah.ums.service.pdf.PdfTableBuilder
*/
public static PdfTableBuilder builder(Class clazz) {
return new PdfTableBuilder(clazz);
}
/**
* 构造函数
*/
private PdfTableBuilder(Class clazz) {
Field[] fields = clazz.getDeclaredFields();
int size = 0;
for (Field field : fields) {
if ("serialVersionUID".equals(field.getName())){
continue;
}
size++;
}
this.colSize = size;
table = new PdfPTable(colSize);
}
/**
* 构造函数,默认纸张A4
*/
private PdfTableBuilder(int colSize) {
this.colSize = colSize;
table = new PdfPTable(colSize);
}
public PdfPTable build() {
return table;
}
public PdfTableBuilder titleRow(Collection titles) {
titleRow(PdfCellBuilder.builder().borderColor(BaseColor.BLACK).bgColor(BaseColor.LIGHT_GRAY).build(),
PdfFontBuilder.builder().fontStyle(Font.BOLD).build(),
titles);
return this;
}
public PdfTableBuilder titleRow(Font font, Collection titles) {
titleRow(PdfCellBuilder.builder().borderColor(BaseColor.BLACK).bgColor(BaseColor.LIGHT_GRAY).build(),
font,
titles);
return this;
}
public PdfTableBuilder titleRow(PdfPCell cell, Collection titles) {
titleRow(cell, PdfFontBuilder.builder().fontStyle(Font.BOLD).build(), titles);
return this;
}
public PdfTableBuilder titleRow(PdfPCell cell, Font font, Collection titles) {
// 根据列数和属性数量,决定处理个数
int size = Math.min(colSize, titles.size());
int handleCount = 0;
Iterator iterator = titles.iterator();
while (iterator.hasNext()) {
if (handleCount >= size) {
break;
}
String title = iterator.next();
title = StrUtil.isNotEmpty(title) ? title : "";
table.addCell(titleCell(cell, font, title));
handleCount++;
}
table.completeRow();
return this;
}
/**
*
* @param clazz 必须包含 @ExcelProperty注解
* @return com.ah.ums.service.pdf.PdfTableBuilder
*/
public PdfTableBuilder titleRow(Class clazz) {
titleRow(PdfCellBuilder.builder().borderColor(BaseColor.BLACK).bgColor(BaseColor.LIGHT_GRAY).build(),
PdfFontBuilder.builder().fontStyle(Font.BOLD).build(),
clazz);
return this;
}
public PdfTableBuilder titleRow(Font font, Class clazz) {
titleRow(PdfCellBuilder.builder().borderColor(BaseColor.BLACK).bgColor(BaseColor.LIGHT_GRAY).build(), font, clazz);
return this;
}
public PdfTableBuilder titleRow(PdfPCell cell, Class clazz) {
titleRow(cell, PdfFontBuilder.builder().fontStyle(Font.BOLD).build(), clazz);
return this;
}
public PdfTableBuilder titleRow(PdfPCell cell, Font font, Class clazz) {
Field[] fields = clazz.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
// TODO: 2023/6/16
Field field = fields[i];
if ("serialVersionUID".equals(field.getName())){
continue;
}
ExcelProperty annotation = field.getAnnotation(ExcelProperty.class);
String data = ObjectUtil.isNotEmpty(annotation) ? annotation.value()[0] : field.getName();
table.addCell(titleCell(cell, font, data));
}
table.completeRow();
return this;
}
public PdfTableBuilder row(Collection list) {
row(PdfCellBuilder.builder().build(), PdfFontBuilder.builder().build(), list);
return this;
}
public PdfTableBuilder row(Font font, Collection list) {
row(PdfCellBuilder.builder().build(), font, list);
return this;
}
public PdfTableBuilder row(PdfPCell cell, Collection list) {
row(cell, PdfFontBuilder.builder().build(), list);
return this;
}
public PdfTableBuilder row(PdfPCell cell, Font font, Collection list) {
// 根据列数和属性数量,决定处理个数
int size = Math.min(colSize, list.size());
int handleCount = 0;
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
if (handleCount >= size) {
break;
}
String title = iterator.next();
title = StrUtil.isNotEmpty(title) ? title : "";
table.addCell(cell(cell, font, title));
handleCount++;
}
table.completeRow();
return this;
}
public PdfTableBuilder row(T obj) throws IllegalAccessException {
row(PdfCellBuilder.builder().build(), PdfFontBuilder.builder().build(), obj);
return this;
}
public PdfTableBuilder row(Font font, T obj) throws IllegalAccessException {
row(PdfCellBuilder.builder().build(), font, obj);
return this;
}
public PdfTableBuilder row(PdfPCell cell, T obj) throws IllegalAccessException {
row(cell, PdfFontBuilder.builder().build(), obj);
return this;
}
public PdfTableBuilder row(PdfPCell cell, Font font, T obj) throws IllegalAccessException {
Class clazz = obj.getClass();
Field[] fields = clazz.getDeclaredFields();
// 根据列数和属性数量,决定处理个数
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
if ("serialVersionUID".equals(field.getName())) {
continue;
}
field.setAccessible(true);
Object f = field.get(obj);
DateTimeFormat annotation = field.getAnnotation(DateTimeFormat.class);
String data;
if (ObjectUtil.isNotEmpty(annotation)) {
String format = annotation.value();
if (f instanceof Date) {
data = DateUtil.format((Date)f, format);
} else if (f instanceof LocalDateTime) {
data = DateUtil.format((LocalDateTime) f, format);
} else {
data = "";
}
} else {
data = ObjectUtil.isNotEmpty(f) ? f.toString() : "";
}
data = StrUtil.isNotEmpty(data) ? data : "";
table.addCell(cell(cell, font, data));
}
table.completeRow();
return this;
}
/**
* 获取单元格
* @param cell 单元格
* @param font 字体
* @param text 内容
* @return com.itextpdf.text.pdf.PdfPCell
*/
private PdfPCell titleCell(PdfPCell cell, Font font, String text) {
cell.setPhrase(new Phrase(text, font));
return cell;
}
/**
* 获取单元格
* @param cell pdf单元格
* @param font 字体
* @param text 内容
* @return com.itextpdf.text.pdf.PdfPCell
*/
private PdfPCell cell(PdfPCell cell, Font font, String text) {
cell.setPhrase(new Phrase(text, font));
return cell;
}
public static class PdfCellBuilder {
/**
* 单元格 padding大小
*/
private Float padding = CELL_PADDING;
/**
* 单元格 水平位置
*
* Element.ALIGN_LEFT (0) 居左
* Element.ALIGN_CENTER (1) 居中
* Element.ALIGN_RIGHT (2) 居右
* Element.ALIGN_JUSTIFIED (3) 自适应
*
*/
private Integer horizontalAlign = Element.ALIGN_CENTER;
/** 单元格 垂直位置:Element.ALIGN_TOP-居上,Element.ALIGN_MIDDLE-居中,Element.ALIGN_BOTTOM-居下 */
/**
* 单元格 垂直位置
*
* Element.ALIGN_TOP (4) 居上
* Element.ALIGN_MIDDLE (5) 居中
* Element.ALIGN_BOTTOM (6) 居下
*
*/
private Integer verticalAlign = Element.ALIGN_MIDDLE;
/**
* 单元格 边框颜色
*/
private BaseColor borderColor;
/**
* 单元格 字体颜色
*/
private BaseColor bgColor;
/**
* 构造类
*/
public static PdfCellBuilder builder() {
return new PdfCellBuilder();
}
/**
* 构造函数,默认纸张A4
*/
private PdfCellBuilder() {
}
public PdfCellBuilder padding(float padding) {
this.padding = padding;
return this;
}
public PdfCellBuilder horizontalAlign(Integer horizontalAlign) {
this.horizontalAlign = horizontalAlign;
return this;
}
public PdfCellBuilder verticalAlign(Integer verticalAlign) {
this.verticalAlign = verticalAlign;
return this;
}
public PdfCellBuilder borderColor(BaseColor borderColor) {
this.borderColor = borderColor;
return this;
}
public PdfCellBuilder bgColor(BaseColor bgColor) {
this.bgColor = bgColor;
return this;
}
/**
* 构造函数,默认纸张A4
*/
public PdfPCell build() {
// 创建单元格
PdfPCell cell = new PdfPCell();
// 表格padding
cell.setPadding(padding);
// 设置单元格的水平居中
cell.setHorizontalAlignment(horizontalAlign);
// 设置单元格的垂直居中
cell.setVerticalAlignment(verticalAlign);
cell.setBorderColor(borderColor);
cell.setBackgroundColor(bgColor);
return cell;
}
}
}
package com.ah.ums.service.pdf;
import com.ah.ums.dto.gw.excel.StatsDayExcelDTO;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.text.pdf.draw.LineSeparator;
import lombok.extern.slf4j.Slf4j;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
/**
* PDF建造者模式
* @author chenjian
* @version 1.0
* @date 2023/6/15
*/
@Slf4j
public class PdfBuilder extends PdfBase {
/**
* 空行
*/
private static final Paragraph BLANK = new Paragraph(" ");
/**
* 粗线
*/
private static final LineSeparator BOLD_LINE = new LineSeparator(2f, 100, BaseColor.BLACK, Element.ALIGN_CENTER, 0f);
/**
* 粗线
*/
private static final LineSeparator LINE = new LineSeparator(1f, 100, BaseColor.BLACK, Element.ALIGN_CENTER, 0f);
/** 文档对象 */
private Document document;
/**
* 构造类,使用默认纸张A4
* @param filePath 文件路径
* @return com.ah.ums.service.pdf.PdfBuilder
*/
public static PdfBuilder builder(String filePath) throws DocumentException, FileNotFoundException {
return new PdfBuilder(filePath);
}
/**
* 构造类
* @param filePath 文件路径
* @param pageSize 指定纸张
* @return com.ah.ums.service.pdf.PdfBuilder
*/
public static PdfBuilder builder(String filePath, Rectangle pageSize) throws DocumentException, FileNotFoundException {
return new PdfBuilder(filePath, pageSize);
}
/**
* 构造函数,默认纸张A4
*/
private PdfBuilder(String filePath) throws FileNotFoundException, DocumentException {
init(filePath, PageSize.A4);
}
/**
* 构造函数,传入纸张
*/
private PdfBuilder(String filePath, Rectangle pageSize) throws FileNotFoundException, DocumentException {
init(filePath, pageSize);
}
/**
* 初始化Pdf
* @param filePath pdf文档地址
* @param pageSize 文档页大小
* @return void
*/
private void init(String filePath, Rectangle pageSize) throws FileNotFoundException, DocumentException {
document = new Document(pageSize);
// 为document创建一个监听,并把PDF流写到文件中
// 文件的输出路径+文件的实际名称
PdfWriter.getInstance(document, new FileOutputStream(filePath));
// 打开文档
document.open();
log.debug("{}", document);
}
/**
* 写文档标题
* @param title
* @return com.ah.ums.service.pdf.PdfBuilder
*/
public PdfBuilder title(String title) throws DocumentException {
title(BaseColor.BLACK, title);
return this;
}
/**
* 写文档标题待颜色
* @param color 自定义颜色
* @param title
* @return com.ah.ums.service.pdf.PdfBuilder
*/
public PdfBuilder title(BaseColor color, String title) throws DocumentException {
document.add(new Paragraph(title, PdfFontBuilder.builder().fontSize(TITLE_FONT_SIZE).fontStyle(Font.BOLD).fontColor(color).build()));
return this;
}
/**
* 写文档小标题
* @param title
* @return com.ah.ums.service.pdf.PdfBuilder
*/
public PdfBuilder smallTitle(String title) throws DocumentException {
smallTitle(BaseColor.BLACK, title);
return this;
}
/**
* 写文档小标题
* @param color 自定义颜色
* @param title
* @return com.ah.ums.service.pdf.PdfBuilder
*/
public PdfBuilder smallTitle(BaseColor color, String title) throws DocumentException {
document.add(new Paragraph(title, PdfFontBuilder.builder().fontSize(SMALL_TITLE_FONT_SIZE).fontStyle(Font.BOLD).fontColor(color).build()));
return this;
}
/**
* 空行
* @return com.ah.ums.service.pdf.PdfBuilder
*/
public PdfBuilder blank() throws DocumentException {
document.add(BLANK);
return this;
}
/**
* 粗横线
* @return com.ah.ums.service.pdf.PdfBuilder
*/
public PdfBuilder boldLine() throws DocumentException {
document.add(BOLD_LINE);
return this;
}
/**
* 横线
* @return com.ah.ums.service.pdf.PdfBuilder
*/
public PdfBuilder line() throws DocumentException {
document.add(LINE);
return this;
}
/**
* 写文本内容
* @param text 文本内容
* @return com.ah.ums.service.pdf.PdfBuilder
*/
public PdfBuilder text(String text) throws DocumentException {
document.add(new Paragraph(text, PdfFontBuilder.builder().build()));
return this;
}
/**
* 指定字体大小写入
* @param fontSize 字体大小
* @param text 文本内容
* @return com.ah.ums.service.pdf.PdfBuilder
*/
public PdfBuilder text(int fontSize, String text) throws DocumentException {
document.add(new Paragraph(text, PdfFontBuilder.builder().fontSize(fontSize).build()));
return this;
}
/**
* 指定字体大小写入
* @param fontSize 字体大小
* @param color 自定义颜色
* @param text 文本内容
* @return com.ah.ums.service.pdf.PdfBuilder
*/
public PdfBuilder text(int fontSize, BaseColor color, String text) throws DocumentException {
document.add(new Paragraph(text, PdfFontBuilder.builder().fontSize(fontSize).fontColor(color).build()));
return this;
}
/**
* 指定字体大小写入
* @param fontSize 字体大小
* @param fontStyle 字体样式
* @param color 自定义颜色
* @param text 文本内容
* @return com.ah.ums.service.pdf.PdfBuilder
*/
public PdfBuilder text(int fontSize, int fontStyle, BaseColor color, String text) throws DocumentException {
document.add(new Paragraph(text,
PdfFontBuilder.builder()
.fontSize(fontSize)
.fontStyle(fontStyle)
.fontColor(color)
.build()));
return this;
}
/**
* 指定字体大小写入
* @param font 外部传入字体
* @param text 文本内容
* @return com.ah.ums.service.pdf.PdfBuilder
*/
public PdfBuilder text(Font font, String text) throws DocumentException {
document.add(new Paragraph(text, font));
return this;
}
/**
* 签章
* @param imgPath 签章路径
* @return com.ah.ums.service.pdf.PdfBuilder
*/
public PdfBuilder sign(String imgPath) throws DocumentException, IOException {
sign(150, imgPath);
return this;
}
/**
* 签章
* @param scale 缩放
* @param imgPath 签章路径
* @return com.ah.ums.service.pdf.PdfBuilder
*/
public PdfBuilder sign(int scale,String imgPath) throws DocumentException, IOException {
// 获取图片
Image img = Image.getInstance(imgPath);
// 靠右
img.setAlignment(Image.RIGHT);
img.scaleToFit(scale, scale);
img.setIndentationRight(50);
//img.setAbsolutePosition(420,100);
document.add(img);
return this;
}
/**
* 写入表格
* @param pdfPTable 表格
* @return com.ah.ums.service.pdf.PdfBuilder
*/
public PdfBuilder table(PdfPTable pdfPTable) throws DocumentException {
document.add(pdfPTable);
return this;
}
public void build() {
document.close();
}
}