437 lines
15 KiB
Java
437 lines
15 KiB
Java
package com.example.sso.dao;
|
||
|
||
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.geom.Rectangle;
|
||
import com.itextpdf.kernel.pdf.PdfDocument;
|
||
import com.itextpdf.kernel.pdf.PdfWriter;
|
||
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
|
||
import com.itextpdf.layout.Canvas;
|
||
import com.itextpdf.layout.Document;
|
||
import com.itextpdf.layout.element.Image;
|
||
import com.itextpdf.layout.element.Paragraph;
|
||
import com.itextpdf.layout.properties.TextAlignment;
|
||
import com.itextpdf.layout.properties.VerticalAlignment;
|
||
import com.itextpdf.kernel.events.PdfDocumentEvent;
|
||
import com.itextpdf.kernel.events.IEventHandler;
|
||
import com.itextpdf.kernel.events.Event;
|
||
|
||
import java.io.File;
|
||
import java.io.IOException;
|
||
import java.util.ArrayList;
|
||
import java.util.List;
|
||
|
||
public class Photo {
|
||
// 使用 ThreadLocal 存储每个线程的独立变量
|
||
private static final ThreadLocal<PdfDocument> pdfDocThreadLocal = new ThreadLocal<>();
|
||
private static final ThreadLocal<Document> documentThreadLocal = new ThreadLocal<>();
|
||
private static final ThreadLocal<String> currentPdfPathThreadLocal = new ThreadLocal<>();
|
||
private static final ThreadLocal<PdfFont> chineseFontThreadLocal = new ThreadLocal<>();
|
||
|
||
// 存储每页的页脚文本(使用ThreadLocal确保线程安全)
|
||
private static final ThreadLocal<List<FooterText>> footerTextsThreadLocal = new ThreadLocal<>();
|
||
|
||
// 页脚文本类
|
||
private static class FooterText {
|
||
String text;
|
||
float x;
|
||
float y;
|
||
DeviceRgb color;
|
||
|
||
FooterText(String text, float x, float y, DeviceRgb color) {
|
||
this.text = text;
|
||
this.x = x;
|
||
this.y = y;
|
||
this.color = color;
|
||
}
|
||
}
|
||
|
||
// 页脚事件处理器
|
||
private static class FooterEventHandler implements IEventHandler {
|
||
@Override
|
||
public void handleEvent(Event event) {
|
||
PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
|
||
PdfCanvas canvas = new PdfCanvas(docEvent.getPage());
|
||
Rectangle pageSize = docEvent.getPage().getPageSize();
|
||
|
||
// 获取当前线程的字体和页脚文本
|
||
PdfFont chineseFont = chineseFontThreadLocal.get();
|
||
List<FooterText> footerTexts = footerTextsThreadLocal.get();
|
||
|
||
if (chineseFont == null || footerTexts == null || footerTexts.isEmpty()) {
|
||
canvas.release();
|
||
return;
|
||
}
|
||
|
||
// 创建Canvas用于绘制
|
||
Canvas pageCanvas = new Canvas(canvas, pageSize);
|
||
|
||
// 绘制所有页脚文本
|
||
for (FooterText footerText : footerTexts) {
|
||
Paragraph paragraph = new Paragraph(footerText.text)
|
||
.setFont(chineseFont)
|
||
.setFontSize(12);
|
||
|
||
if (footerText.color != null) {
|
||
paragraph.setFontColor(footerText.color);
|
||
}
|
||
|
||
// 在指定位置绘制文本
|
||
pageCanvas.showTextAligned(
|
||
paragraph,
|
||
footerText.x,
|
||
footerText.y,
|
||
TextAlignment.LEFT,
|
||
VerticalAlignment.BOTTOM
|
||
);
|
||
}
|
||
|
||
canvas.release();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 开始创建PDF
|
||
*/
|
||
public static void startPDF(String pdfPath) throws IOException {
|
||
// 获取当前线程的变量
|
||
PdfDocument pdfDoc = pdfDocThreadLocal.get();
|
||
Document document = documentThreadLocal.get();
|
||
|
||
// 如果已经存在,先关闭
|
||
if (pdfDoc != null || document != null) {
|
||
closePDF();
|
||
}
|
||
|
||
// 创建新的PDF文档
|
||
currentPdfPathThreadLocal.set(pdfPath);
|
||
PdfWriter writer = new PdfWriter(pdfPath);
|
||
pdfDoc = new PdfDocument(writer);
|
||
|
||
// 注册页脚事件处理器
|
||
FooterEventHandler footerHandler = new FooterEventHandler();
|
||
pdfDoc.addEventHandler(PdfDocumentEvent.END_PAGE, footerHandler);
|
||
|
||
// 使用标准A4纸
|
||
document = new Document(pdfDoc, PageSize.A4, false);
|
||
document.setMargins(0, 0, 0, 0);
|
||
|
||
// 初始化中文字体
|
||
PdfFont chineseFont = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H");
|
||
|
||
// 初始化页脚文本列表
|
||
footerTextsThreadLocal.set(new ArrayList<>());
|
||
|
||
// 保存到ThreadLocal
|
||
pdfDocThreadLocal.set(pdfDoc);
|
||
documentThreadLocal.set(document);
|
||
chineseFontThreadLocal.set(chineseFont);
|
||
|
||
System.out.println(Thread.currentThread().getName() + " 开始创建PDF: " + pdfPath);
|
||
}
|
||
|
||
/**
|
||
* 设置页脚文本(会在每一页底部显示)
|
||
*/
|
||
public static void setFooterText(String text) throws IOException {
|
||
Document document = documentThreadLocal.get();
|
||
PdfFont chineseFont = chineseFontThreadLocal.get();
|
||
|
||
if (document == null) {
|
||
throw new IllegalStateException("请先调用 startPDF() 方法");
|
||
}
|
||
|
||
if (chineseFont == null) {
|
||
chineseFont = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H");
|
||
chineseFontThreadLocal.set(chineseFont);
|
||
}
|
||
|
||
// 获取页脚文本列表
|
||
List<FooterText> footerTexts = footerTextsThreadLocal.get();
|
||
if (footerTexts == null) {
|
||
footerTexts = new ArrayList<>();
|
||
footerTextsThreadLocal.set(footerTexts);
|
||
}
|
||
|
||
// 清空原有页脚,添加新的页脚文本
|
||
footerTexts.clear();
|
||
footerTexts.add(new FooterText(text, 50F, 30F, (DeviceRgb) DeviceRgb.BLACK));
|
||
|
||
System.out.println(Thread.currentThread().getName() + " 已设置页脚文本: " + text);
|
||
}
|
||
|
||
/**
|
||
* 添加图片章节
|
||
*/
|
||
public static void appendImageSection(String imagePath) throws IOException {
|
||
Document document = documentThreadLocal.get();
|
||
if (document == null) {
|
||
throw new IllegalStateException("请先调用 startPDF() 方法");
|
||
}
|
||
|
||
// 添加图片
|
||
if (imagePath != null && new File(imagePath).exists()) {
|
||
ImageData imageData = ImageDataFactory.create(imagePath);
|
||
Image image = new Image(imageData);
|
||
|
||
image.setHorizontalAlignment(com.itextpdf.layout.properties.HorizontalAlignment.CENTER);
|
||
image.setMarginTop(5);
|
||
image.setMarginBottom(5);
|
||
image.setHeight(200);
|
||
image.setWidth(200);
|
||
|
||
document.add(image);
|
||
}
|
||
|
||
System.out.println(Thread.currentThread().getName() + " 已添加图片章节");
|
||
}
|
||
|
||
/**
|
||
* 添加文本章节
|
||
*/
|
||
public static void appendTextSection(String text) throws IOException {
|
||
Document document = documentThreadLocal.get();
|
||
PdfFont chineseFont = chineseFontThreadLocal.get();
|
||
|
||
if (document == null) {
|
||
throw new IllegalStateException("请先调用 startPDF() 方法");
|
||
}
|
||
|
||
if (chineseFont == null) {
|
||
chineseFont = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H");
|
||
chineseFontThreadLocal.set(chineseFont);
|
||
}
|
||
|
||
document.add(new Paragraph(text)
|
||
.setFont(chineseFont)
|
||
.setFontSize(20)
|
||
.setBold()
|
||
.setMarginTop(20));
|
||
|
||
System.out.println(Thread.currentThread().getName() + " 已添加文本章节");
|
||
}
|
||
|
||
public static void TextAlignment(String text) throws IOException {
|
||
Document document = documentThreadLocal.get();
|
||
PdfFont chineseFont = chineseFontThreadLocal.get();
|
||
|
||
if (document == null) {
|
||
throw new IllegalStateException("请先调用 startPDF() 方法");
|
||
}
|
||
|
||
if (chineseFont == null) {
|
||
chineseFont = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H");
|
||
chineseFontThreadLocal.set(chineseFont);
|
||
}
|
||
|
||
// 创建段落并设置居中对齐
|
||
Paragraph paragraph = new Paragraph(text)
|
||
.setFont(chineseFont)
|
||
.setFontSize(20)
|
||
.setBold()
|
||
.setMarginTop(20)
|
||
.setTextAlignment(TextAlignment.CENTER);
|
||
|
||
document.add(paragraph);
|
||
System.out.println(Thread.currentThread().getName() + " 已添加文本章节");
|
||
}
|
||
|
||
public static void appendTextSections(String text) throws IOException {
|
||
Document document = documentThreadLocal.get();
|
||
PdfFont chineseFont = chineseFontThreadLocal.get();
|
||
|
||
if (document == null) {
|
||
throw new IllegalStateException("请先调用 startPDF() 方法");
|
||
}
|
||
|
||
if (chineseFont == null) {
|
||
chineseFont = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H");
|
||
chineseFontThreadLocal.set(chineseFont);
|
||
}
|
||
|
||
List<FooterText> footerTexts = footerTextsThreadLocal.get();
|
||
if (footerTexts == null) {
|
||
footerTexts = new ArrayList<>();
|
||
footerTextsThreadLocal.set(footerTexts);
|
||
}
|
||
|
||
// 添加白色文本
|
||
footerTexts.add(new FooterText(text, 475F, 25f, (DeviceRgb) DeviceRgb.WHITE));
|
||
|
||
System.out.println(Thread.currentThread().getName() + " 已添加白色页脚文本: " + text);
|
||
}
|
||
|
||
public static void appendTextSections1(String text) throws IOException {
|
||
Document document = documentThreadLocal.get();
|
||
PdfFont chineseFont = chineseFontThreadLocal.get();
|
||
|
||
if (document == null) {
|
||
throw new IllegalStateException("请先调用 startPDF() 方法");
|
||
}
|
||
|
||
if (chineseFont == null) {
|
||
chineseFont = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H");
|
||
chineseFontThreadLocal.set(chineseFont);
|
||
}
|
||
|
||
List<FooterText> footerTexts = footerTextsThreadLocal.get();
|
||
if (footerTexts == null) {
|
||
footerTexts = new ArrayList<>();
|
||
footerTextsThreadLocal.set(footerTexts);
|
||
}
|
||
|
||
// 添加黑色文本
|
||
footerTexts.add(new FooterText(text, 310f, 25f, null));
|
||
|
||
System.out.println(Thread.currentThread().getName() + " 已添加黑色页脚文本: " + text);
|
||
}
|
||
|
||
public static void appendTextSectionss(String text) throws IOException {
|
||
Document document = documentThreadLocal.get();
|
||
PdfFont chineseFont = chineseFontThreadLocal.get();
|
||
|
||
if (document == null) {
|
||
throw new IllegalStateException("请先调用 startPDF() 方法");
|
||
}
|
||
|
||
if (chineseFont == null) {
|
||
chineseFont = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H");
|
||
chineseFontThreadLocal.set(chineseFont);
|
||
}
|
||
|
||
List<FooterText> footerTexts = footerTextsThreadLocal.get();
|
||
if (footerTexts == null) {
|
||
footerTexts = new ArrayList<>();
|
||
footerTextsThreadLocal.set(footerTexts);
|
||
}
|
||
|
||
// 添加白色文本
|
||
footerTexts.add(new FooterText(text, 400F, 50F, (DeviceRgb) DeviceRgb.WHITE));
|
||
|
||
System.out.println(Thread.currentThread().getName() + " 已添加白色页脚文本: " + text);
|
||
}
|
||
|
||
public static void appendTextSectionss1(String text) throws IOException {
|
||
Document document = documentThreadLocal.get();
|
||
PdfFont chineseFont = chineseFontThreadLocal.get();
|
||
|
||
if (document == null) {
|
||
throw new IllegalStateException("请先调用 startPDF() 方法");
|
||
}
|
||
|
||
if (chineseFont == null) {
|
||
chineseFont = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H");
|
||
chineseFontThreadLocal.set(chineseFont);
|
||
}
|
||
|
||
List<FooterText> footerTexts = footerTextsThreadLocal.get();
|
||
if (footerTexts == null) {
|
||
footerTexts = new ArrayList<>();
|
||
footerTextsThreadLocal.set(footerTexts);
|
||
}
|
||
|
||
// 添加黑色文本
|
||
footerTexts.add(new FooterText(text, 310, 50, null));
|
||
|
||
System.out.println(Thread.currentThread().getName() + " 已添加黑色页脚文本: " + text);
|
||
}
|
||
|
||
/**
|
||
* 添加分页符
|
||
*/
|
||
public static void addPageBreak() {
|
||
Document document = documentThreadLocal.get();
|
||
if (document != null) {
|
||
document.add(new com.itextpdf.layout.element.AreaBreak());
|
||
System.out.println(Thread.currentThread().getName() + " 已添加分页符");
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 关闭并保存PDF
|
||
*/
|
||
public static void closePDF() {
|
||
// 获取当前线程的变量
|
||
Document document = documentThreadLocal.get();
|
||
PdfDocument pdfDoc = pdfDocThreadLocal.get();
|
||
String currentPdfPath = currentPdfPathThreadLocal.get();
|
||
PdfFont chineseFont = chineseFontThreadLocal.get();
|
||
|
||
if (document != null) {
|
||
document.close();
|
||
documentThreadLocal.remove();
|
||
}
|
||
|
||
if (pdfDoc != null) {
|
||
pdfDoc.close();
|
||
pdfDocThreadLocal.remove();
|
||
}
|
||
|
||
if (chineseFont != null) {
|
||
chineseFontThreadLocal.remove();
|
||
}
|
||
|
||
if (currentPdfPath != null) {
|
||
System.out.println(Thread.currentThread().getName() + " PDF已保存: " + currentPdfPath);
|
||
currentPdfPathThreadLocal.remove();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 快速使用示例
|
||
*/
|
||
public static void createPDFWithMultipleSections(String pdfPath) throws IOException {
|
||
startPDF(pdfPath);
|
||
|
||
try {
|
||
// 添加各种内容
|
||
appendTextSection("这是文档的第一部分\n包含一些介绍性的文字");
|
||
appendImageSection("image1.jpg");
|
||
appendTextSection("这是图片1的描述文字");
|
||
appendImageSection("image2.png");
|
||
appendTextSection("这是图片2的描述文字");
|
||
} finally {
|
||
// 确保资源被释放
|
||
closePDF();
|
||
}
|
||
}
|
||
|
||
public static void createSimpleChinesePDF() throws IOException {
|
||
// 这个方法不使用ThreadLocal变量,因为它自己创建PDF
|
||
// 1. 创建PDF
|
||
PdfWriter writer = new PdfWriter("D:\\下载模板\\a.pdf");
|
||
PdfDocument pdfDoc = new PdfDocument(writer);
|
||
Document document = new Document(pdfDoc);
|
||
|
||
// 2. 加载中文字体(必须要有font-asian依赖)
|
||
PdfFont chineseFont = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H");
|
||
|
||
// 3. 添加中文内容
|
||
Paragraph title = new Paragraph("中文标题")
|
||
.setFont(chineseFont)
|
||
.setFontSize(20)
|
||
.setBold();
|
||
document.add(title);
|
||
|
||
Paragraph content = new Paragraph("这是中文内容,可以正常显示。")
|
||
.setFont(chineseFont)
|
||
.setFontSize(12);
|
||
document.add(content);
|
||
|
||
// 4. 关闭文档
|
||
document.close();
|
||
pdfDoc.close();
|
||
|
||
System.out.println("PDF创建完成");
|
||
}
|
||
|
||
/**
|
||
* 测试多线程并发
|
||
*/
|
||
|
||
}
|