需求:1.生成pdf对账单;2.pdf文件指定文字坐标处盖章;3、pdf表格分页跨行问题;
1、先看最终效果
2、maven版本,这里因为itext7是收费的,后面换成了itext5版本
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext7-core</artifactId>
<version>7.1.16</version>
</dependency>
3、直接上全部代码,数据对象自行处理
import com.github.pagehelper.util.StringUtil;
import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.io.image.ImageData;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.colors.DeviceRgb;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.canvas.parser.PdfCanvasProcessor;
import com.itextpdf.kernel.pdf.canvas.parser.listener.IPdfTextLocation;
import com.itextpdf.kernel.pdf.canvas.parser.listener.RegexBasedLocationExtractionStrategy;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.borders.SolidBorder;
import com.itextpdf.layout.element.*;
import com.itextpdf.layout.property.TabAlignment;
import com.itextpdf.layout.property.TextAlignment;
import com.itextpdf.layout.property.UnitValue;
import org.springframework.core.io.ClassPathResource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.util.*;
import java.util.List;
import java.io.IOException;
public class ToolPDFUtils {
/**
* 生成明细表头
*
* @param table
* @param font
* @return
* @throws IOException
* @throws
*/
public static final String FONT_PATH = "FZBYSJT.TTF";
public static void createWeekTable(Table table, PdfFont font) {
table.addCell(createCell("序号", font));
table.addCell(createCell("项目", font));
table.addCell(createCell("费用类别", font));
table.addCell(createCell("计费标准(未税)", font));
table.addCell(createCell("单位", font));
table.addCell(createCell("本月业务量", font));
table.addCell(createCell("单位", font));
table.addCell(createCell("金额未税/元", font));
table.addCell(createCell("税率", font));
table.addCell(createCell("金额含税/元", font));
}
/**
* 标签打印pdf
*
* @param statementResult
* @param res
*/
public static Map labelPrinting(StatementResult statementResult, HttpServletResponse res, String factoryName, SysUser sysUser) {
Map<String, String> mapResult = new HashMap<>();
List<StatementDetail> detailList = statementResult.getStatementDetailList();
String userStr = "委托代理人:";
// 上传文件路径
String filename = "/mypdf/"+".pdf";
File directory = new File(filename);
if (!directory.getParentFile().exists()) {
directory.getParentFile().mkdirs();
}
// 创建PDF文档
PdfWriter pdfWriter;
try {
pdfWriter = new PdfWriter(filename);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
PdfDocument pdfDocument = new PdfDocument(pdfWriter);
Document document = new Document(pdfDocument, PageSize.A4);
// 添加中文字体,不添加ttf,中文不会显示
PdfFont chineseFont;
try {
// 处理中文问题
chineseFont = PdfFontFactory.createFont(FONT_PATH, PdfEncodings.IDENTITY_H, true);
} catch (IOException e) {
throw new RuntimeException("Font FZBYSJT.TTF not found", e);
}
Paragraph title = new Paragraph(factoryName + statementResult.getTitle())
.setFont(chineseFont).setFontSize(20).setBold().setTextAlignment(TextAlignment.CENTER); // 设置文本居中对齐
document.add(title);
float columnWidths[] = {5, 20, 15, 10, 10, 10, 5, 10, 5, 10}; // percentage
// 自定义比例设置列宽
Table table = new Table(UnitValue.createPercentArray(columnWidths));
table.setWidth(UnitValue.createPercentValue(100));
table.addCell(createCell(1, 2, "甲方名称:", chineseFont));
table.addCell(createCell(1, 4, statementResult.getSupplierNameAcc(), chineseFont));
table.addCell(createCell(1, 2, "甲方公司代码:", chineseFont));
table.addCell(createCell(1, 2, statementResult.getSupplierCodeAcc(), chineseFont));
table.addCell(createCell(1, 2, "乙方名称:", chineseFont));
table.addCell(createCell(1, 8, statementResult.getSecondParty(), chineseFont));
if (StringUtils.isNotEmpty(statementResult.getThirdParty())) {
table.addCell(createCell(1, 2, "丁方名称:", chineseFont));
table.addCell(createCell(1, 8, statementResult.getThirdParty(), chineseFont));
}
Paragraph paragraph = new Paragraph().setFont(chineseFont).setFontSize(9);
paragraph.add(new Tab());
paragraph.addTabStops(new TabStop(20, TabAlignment.LEFT));
paragraph.add(StringUtil.isNotEmpty(statementResult.getTou()) ? statementResult.getTou() : "按照甲乙双方签署的《仓储物流服务协议》,经核对双方的实际业务量,自2023年 月1日起至2023年 月 日止,甲方应向乙方支付如下金额的仓储物流服务费,双方核对无误,乙方可据此开票。");
paragraph.add("\n");
paragraph.add("特此确认!");
paragraph.add("\n");
paragraph.add("费用明细:");
Cell cell = new Cell(1, 10).add(paragraph).setBorder(new SolidBorder(new DeviceRgb(0, 0, 0), 1));
table.addCell(cell);
//表格表头
createWeekTable(table, chineseFont);
for (int i = 0; i < detailList.size(); i++) {
table.addCell(createCell(Integer.valueOf(i + 1).toString(), chineseFont));
table.addCell(createCell(detailList.get(i).getTitle(), chineseFont));
table.addCell(createCell(String.format("%s", detailList.get(i).getExpenseName()), chineseFont));
table.addCell(createCell(String.format("%s", detailList.get(i).getBillingStandard()), chineseFont));
table.addCell(createCell(String.format("%s", detailList.get(i).getUnitName()), chineseFont));
table.addCell(createCell(String.format("%s", detailList.get(i).getServiceYewu()), chineseFont));
table.addCell(createCell(String.format("%s", detailList.get(i).getUnit()), chineseFont));
table.addCell(createCell(detailList.get(i).getAmountDetailNoTax() + "", chineseFont));
table.addCell(createCell((detailList.get(i).getTaxRate() != null ? detailList.get(i).getTaxRate() + "%" : ""), chineseFont));
table.addCell(createCell(detailList.get(i).getAmountDetailTax() + "", chineseFont));
}
table.addCell(createCell(1, 9, "合计:", chineseFont));
table.addCell(createCell(statementResult.getAmountTax().toString(), chineseFont));
table.addCell(createCell(1, 3, "合计含税金额(大写):", chineseFont));
table.addCell(createCell(1, 7, statementResult.getCapTotalAmount(), chineseFont));
Paragraph pg2 = new Paragraph().setFont(chineseFont).setFontSize(9);
pg2.add(StringUtil.isNotEmpty(statementResult.getWei()) ? statementResult.getWei() : "说明:仓储管理及物流辅助服务涉及的物料数量的核算以甲方货物在乙方仓库的出货数为准(甲方不同物料号产品的出库总件数或总方量)。");
pg2.add("\n");
pg2.add("核对无误后请在 3 个工作日内签字盖章回传。致谢!");
Cell cell2 = new Cell(1, 10).add(pg2).setBorder(new SolidBorder(new DeviceRgb(0, 0, 0), 1));
table.addCell(cell2);
table.addCell(createCell(1, 4, "甲方:" + statementResult.getSupplierNameAcc(), chineseFont));
table.addCell(createCell(1, 6, "乙方:" + statementResult.getSecondParty(), chineseFont));
table.addCell(createCell(1, 4, "委托代理人:", chineseFont));
table.addCell(createCell(1, 6, userStr, chineseFont));
table.addCell(createCell(1, 4, " 年 月 日", chineseFont));
table.addCell(createCell(1, 6, DateUtils.getYyyyMmDd(), chineseFont));
//添加到pdf
document.add(table);
document.close();
/*****************创建PDF结束*********************/
// 设置印章!!
// String targetPath = RuoYiConfig.getUploadPath() + "/" + getPath() + "/" + factoryName + statementResult.getMonth() + "_" + statementResult.getSupplierNameAcc() + "_sign_" + System.currentTimeMillis() + "_" + new Random().nextInt(1000) + ".pdf";
// try {
// signPdf(filename, targetPath, userStr);
// } catch (Exception e) {
// throw new RuntimeException(e);
// }
return mapResult;
}
/**
* 统一处理设置PdfPTable
*/
public static Table getMyPdfPTable(int numColumns, float columnWidths[]) {
// 自定义比例设置列宽
// Table table = new Table(UnitValue.createPercentArray(columnWidths));
//等分列宽
// Table table = new Table(UnitValue.createPercentArray(numColumns));
//自适应列宽
Table table = new Table(numColumns);
table.setWidth(UnitValue.createPercentValue(100));
return table;
}
/**
* 设置cell
*
* @param text
* @param font
* @return
*/
private static Cell createCell(String text, PdfFont font) {
return createCell(1, 1, text, font);
}
/**
* 设置cell
*
* @param row 行
* @param column 列
* @param font
* @param font
* @return
*/
private static Cell createCell(int row, int column, String text, PdfFont font) {
//.setKeepTogether(true)为了解决表格跨页分行问题
Paragraph paragraph = new Paragraph(text).setFont(font).setFontSize(9).setTextAlignment(TextAlignment.CENTER); // 设置文本居中对齐
return new Cell(row, column).add(paragraph).setBorder(new SolidBorder(new DeviceRgb(0, 0, 0), 1)).setKeepTogether(true);
}
/**
* /* 签字盖章
* /
*/
public static void signPdf(String sourcePath, String targetPath, String keyword) throws IOException {
PdfReader reader = new PdfReader(sourcePath);
PdfWriter writer = new PdfWriter(targetPath);
PdfDocument pdfDoc = new PdfDocument(reader, writer);
for (int i = 1; i <= pdfDoc.getNumberOfPages(); i++) {
PdfPage page = pdfDoc.getPage(i);
RegexBasedLocationExtractionStrategy strategy = new RegexBasedLocationExtractionStrategy(keyword);
PdfCanvasProcessor canvasProcessor = new PdfCanvasProcessor(strategy);
canvasProcessor.processPageContent(page);
Collection<IPdfTextLocation> locations = strategy.getResultantLocations();
for (IPdfTextLocation location : locations) {
String text = location.getText();
if (text.contains(keyword)) {
float x = location.getRectangle().getLeft();
float y = location.getRectangle().getBottom();
ClassPathResource classPathResource = new ClassPathResource("/static/signs/111.png");
InputStream inputStreamImg = classPathResource.getInputStream();
byte[] byteArray = new byte[inputStreamImg.available()];
inputStreamImg.read(byteArray);
ImageData imageData = ImageDataFactory.create(byteArray);
//这里的印章图片最好原始尺寸为120*120的,不然缩放后印章变色不好看
// imageData.setWidth(160f);
// imageData.setHeight(160f);
PdfCanvas canvas = new PdfCanvas(page.newContentStreamBefore(), page.getResources(), pdfDoc);
canvas.addImage(imageData, x + 25, y - 55, false);
}
}
}
pdfDoc.close();
}
}