Browse Source

feat:[pdf导出]

master
15881625488@163.com 3 months ago
parent
commit
b92e52d6a9
6 changed files with 616 additions and 372 deletions
  1. +13
    -0
      hxhq-modules/hxhq-system/src/main/java/com/hxhq/business/controller/MjyController.java
  2. +404
    -0
      hxhq-modules/hxhq-system/src/main/java/com/hxhq/business/utils/Pdf/PdfBaseUtil.java
  3. +65
    -0
      hxhq-modules/hxhq-system/src/main/java/com/hxhq/business/utils/Pdf/PdfExportUtil.java
  4. +79
    -0
      hxhq-modules/hxhq-system/src/main/java/com/hxhq/business/utils/Pdf/Resource/Drug.java
  5. +55
    -0
      hxhq-modules/hxhq-system/src/main/java/com/hxhq/business/utils/Pdf/Template/Sp/Sp001.java
  6. +0
    -372
      hxhq-modules/hxhq-system/src/main/java/com/hxhq/business/utils/PdfUtil.java

+ 13
- 0
hxhq-modules/hxhq-system/src/main/java/com/hxhq/business/controller/MjyController.java View File

@ -2,12 +2,14 @@ package com.hxhq.business.controller;
import java.util.List; import java.util.List;
import com.alibaba.fastjson2.JSONObject;
import com.hxhq.business.domain.MjyJcgj; import com.hxhq.business.domain.MjyJcgj;
import com.hxhq.business.domain.MjyTz; import com.hxhq.business.domain.MjyTz;
import com.hxhq.business.dto.mjy.ListDto; import com.hxhq.business.dto.mjy.ListDto;
import com.hxhq.business.form.mjy.*; import com.hxhq.business.form.mjy.*;
import com.hxhq.business.service.IMjyJcgjService; import com.hxhq.business.service.IMjyJcgjService;
import com.hxhq.business.service.IMjyTzService; import com.hxhq.business.service.IMjyTzService;
import com.hxhq.business.utils.Pdf.PdfExportUtil;
import com.hxhq.common.security.annotation.RequiresPermissions; import com.hxhq.common.security.annotation.RequiresPermissions;
import com.hxhq.common.security.utils.SecurityUtils; import com.hxhq.common.security.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -94,6 +96,17 @@ public class MjyController extends BaseController
} }
/** /**
* 导出
*/
@RequiresPermissions("business:resource:mjy:xq")
@GetMapping(value = "/exportDetail")
public AjaxResult exportDetail(Long id)
{
return AjaxResult.success(PdfExportUtil.export("com.hxhq.business.utils.Pdf.Resource.Drug","exportDetail", mjyService.queryInfo(id)));
}
/**
* 解档 * 解档
*/ */
@PostMapping("/jd") @PostMapping("/jd")

+ 404
- 0
hxhq-modules/hxhq-system/src/main/java/com/hxhq/business/utils/Pdf/PdfBaseUtil.java View File

@ -0,0 +1,404 @@
package com.hxhq.business.utils.Pdf;
import com.hxhq.common.core.exception.ServiceException;
import com.hxhq.common.core.text.Convert;
import com.hxhq.common.core.utils.DateUtils;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import com.itextpdf.text.pdf.draw.LineSeparator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.*;
/**
* pdf导出基类
* @author tanfei
*/
@Component
public class PdfBaseUtil {
private static final Logger logger = LoggerFactory.getLogger(PdfBaseUtil.class);
private static final String fileDir="D:/hxhq/uploadPath";
/**
* 生成PDF文件完整路径按年月日创建文件夹
* @return 完整文件路径/data/files/2024/01/17/document_20240117123045.pdf
*/
public static String getFilePath() {
// 1. 获取当前年月日并创建文件夹
Date now = new Date();
SimpleDateFormat yearFormat = new SimpleDateFormat("yyyy");
SimpleDateFormat monthFormat = new SimpleDateFormat("MM");
SimpleDateFormat dayFormat = new SimpleDateFormat("dd");
SimpleDateFormat timestampFormat = new SimpleDateFormat("yyyyMMddHHmmss");
String year = yearFormat.format(now);
String month = monthFormat.format(now);
String day = dayFormat.format(now);
String timestamp = timestampFormat.format(now)+UUID.randomUUID();
// 2. 构建文件夹路径
String folderPath = fileDir + File.separator + year + File.separator + month + File.separator + day;
// 3. 确保目录存在
File dir = new File(folderPath);
if (!dir.exists()) {
dir.mkdirs();
}
// 4. 生成文件名
String fileName = "document_" + timestamp + ".pdf";
// 5. 完整文件路径
return Paths.get(folderPath, fileName).toString();
}
/**
* 添加带下划线的标题
* @param document PDF文档对象
* @param titleText 标题文本
* @param fontSize 字体大小
*/
public static void addUnderlinedTitle(Document document, String titleText, float fontSize)
throws DocumentException, IOException {
// 创建中文字体
BaseFont baseFont = BaseFont.createFont(
"STSong-Light",
"UniGB-UCS2-H",
BaseFont.EMBEDDED
);
Font titleFont = new Font(baseFont, fontSize, Font.NORMAL, BaseColor.BLACK);
Font linFont = new Font(baseFont, fontSize, Font.NORMAL, BaseColor.BLACK);
// 创建标题段落
Paragraph titleParagraph = new Paragraph(titleText, titleFont);
titleParagraph.setAlignment(Element.ALIGN_LEFT);
// 添加下划线
LineSeparator underline = new LineSeparator(linFont);
underline.setPercentage(100); // 宽度占50%
underline.setLineWidth(1); // 线粗
underline.setAlignment(Element.ALIGN_LEFT);
// 添加到文档
document.add(titleParagraph);
document.add(underline);
// 添加一些间距
document.add(new Paragraph(titleText)); // 空行
}
/**
* 初始化
*
* @param document
* @param fos
* @param filePath
* @param signText
*/
public static Document init(Document document, FileOutputStream fos, String filePath, String signText, String headerText) {
try {
// 创建PDF文档 设置文档边距避免内容遮挡页眉页脚
float topMargin = 70; // 顶部边距为页眉留出空间
float bottomMargin = 60; // 底部边距为页脚留出空间
float leftMargin = 50; // 左边距
float rightMargin = 50; // 右边距
document = new Document(PageSize.A4,
leftMargin, rightMargin, topMargin, bottomMargin);
fos = new FileOutputStream(filePath);
PdfWriter writer = PdfWriter.getInstance(document, fos);
// 设置页面事件每页添加文字页眉
writer.setPageEvent(new PdfBaseUtil.TextHeaderEvent(signText,headerText));
// 5. 设置PDF属性
document.addTitle("华西海圻");
document.addAuthor("华西海圻");
document.addCreator("华西海圻");
document.addCreationDate();
document.open();
return document;
} catch (Exception e) {
logger.error("生成失败", e);
throw new ServiceException("生成失败: " + e.getMessage());
}
}
/**创建表单
* @param document
* @param data
* @param count
* @throws DocumentException
* @throws IOException
*/
public static void addFormTableColumns(Document document, Map<String, String> data, Integer count)
throws DocumentException, IOException {
// 创建3列表格
PdfPTable table = new PdfPTable(count);
table.setWidthPercentage(100);
table.setSpacingBefore(10);
table.setSpacingAfter(10);
// 设置等宽列
float[] widths = new float[count];
for (int i = 0; i < count; i++) {
widths[i] = 1.0f; // 等宽
}
table.setWidths(widths);
// 创建字体
BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
Font labelFont = new Font(baseFont, 10, Font.NORMAL, BaseColor.BLACK);
Font valueFont = new Font(baseFont, 10, Font.NORMAL, BaseColor.BLACK);
// 将数据转换为List
List<Map.Entry<String, String>> entries = new ArrayList<>(data.entrySet());
// 每3个字段一组每组一行
for (int i = 0; i < entries.size(); i += count) {
// 创建一行
for (int j = 0; j < count; j++) {
int index = i + j;
if (index < entries.size()) {
Map.Entry<String, String> entry = entries.get(index);
// 创建单元格内容
Phrase cellContent = new Phrase();
cellContent.add(new Chunk(entry.getKey() + ":", labelFont));
cellContent.add(new Chunk(com.hxhq.common.core.utils.StringUtils.isBlank(entry.getValue()) ? "" : entry.getValue(), valueFont));
PdfPCell cell = new PdfPCell(cellContent);
cell.setBorder(Rectangle.NO_BORDER); // 无边框
cell.setPadding(4);
cell.setHorizontalAlignment(Element.ALIGN_LEFT);
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell.setMinimumHeight(20); // 最小高度
table.addCell(cell);
} else {
// 添加空单元格保持布局
PdfPCell emptyCell = new PdfPCell();
emptyCell.setBorder(Rectangle.NO_BORDER);
emptyCell.setMinimumHeight(20);
table.addCell(emptyCell);
}
}
}
document.add(table);
}
/**创建表格
* @param content
* @param font
* @return
*/
public static PdfPCell createCell(String content, Font font) {
PdfPCell cell = new PdfPCell(new Phrase(content, font));
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell.setPadding(6);
cell.setMinimumHeight(25);
return cell;
}
/**
* 生成文件名
*/
public static String generateFileName() {
Random random = new Random();
String timestamp = DateUtils.dateTimeNow("yyyyMMddHHmmss");
return String.format("%s_%s.pdf", timestamp, random.nextInt(1000));
}
/**
* 页面事件处理类 - 每页添加文字页眉
*/
static class TextHeaderEvent extends PdfPageEventHelper {
private Font footerFont;
private String signText;
private String headerText;
private BaseFont baseFont;
private int totalPages = 0;
private PdfTemplate total;
public TextHeaderEvent(String signText,String headerText) throws Exception {
try {
this.signText = signText;
this.headerText = headerText;
// 创建字体支持中文
this.baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
footerFont = new Font(baseFont, 10, Font.NORMAL, BaseColor.GRAY);
} catch (Exception e) {
footerFont = new Font(Font.FontFamily.HELVETICA, 10, Font.NORMAL, BaseColor.GRAY);
}
}
@Override
public void onOpenDocument(PdfWriter writer, Document document) {
total = writer.getDirectContent().createTemplate(100, 16);
}
@Override
public void onCloseDocument(PdfWriter writer, Document document) {
totalPages = writer.getPageNumber();
String totalPagesStr = String.valueOf(totalPages);
// 重新创建合适宽度的模板
BaseFont baseFont = footerFont.getBaseFont();
float actualWidth = baseFont.getWidthPoint(totalPagesStr, footerFont.getSize());
total.beginText();
total.setFontAndSize(baseFont, footerFont.getSize());
total.setTextMatrix(0, 0);
total.showText(totalPagesStr);
total.endText();
}
@Override
public void onEndPage(PdfWriter writer, Document document) {
try {
PdfContentByte cb = writer.getDirectContent();
// 获取页面尺寸
Rectangle pageSize = document.getPageSize();
float pageWidth = pageSize.getWidth();
float pageHeight = pageSize.getHeight();
// 设置页眉参数
float topMargin = 30; // 顶部边距
float fontSize = 12; // 字体大小
// 计算文字宽度用于居中
float textWidth = baseFont.getWidthPoint(signText, fontSize);
// 计算居中位置
float textX = (pageWidth - textWidth) / 2;
float textY = pageHeight - topMargin;
// 获取画布
PdfContentByte canvas = writer.getDirectContent();
int currentPage = writer.getPageNumber();
float y = document.bottom() - 20;
// 在每一页都重新计算确保位置准确
String pageText = "第 " + currentPage + " 页 / 共 ";
BaseFont baseFont = footerFont.getBaseFont();
// 计算页面文本宽度
float pageTextWidth = baseFont.getWidthPoint(pageText, footerFont.getSize());
// 临时用估计的总页数计算位置等文档关闭后会被替换
String tempTotal = String.valueOf(writer.getPageNumber() + 5); // 估计值
float totalWidth = baseFont.getWidthPoint(tempTotal, footerFont.getSize());
// 计算起始位置
float totalTextWidth = pageTextWidth + totalWidth +
baseFont.getWidthPoint(" 页", footerFont.getSize());
float startX = (document.getPageSize().getWidth() - totalTextWidth) / 2;
// 写入当前页信息
ColumnText.showTextAligned(cb, Element.ALIGN_LEFT,
new Phrase(pageText, footerFont), startX, y, 0);
// 添加总页数模板
cb.addTemplate(total, startX + pageTextWidth, y);
// 写入"页"
ColumnText.showTextAligned(cb, Element.ALIGN_LEFT,
new Phrase(" 页", footerFont), startX + pageTextWidth + totalWidth, y, 0);
PdfContentByte content = writer.getDirectContentUnder(); // 在水印层添加
// 设置透明度
PdfGState gs = new PdfGState();
float opacity = Convert.toFloat("0.3");
gs.setFillOpacity(opacity);
content.setGState(gs);
// 设置字体和颜色
content.setColorFill(BaseColor.RED);
content.setFontAndSize(baseFont, fontSize);
float width = pageSize.getWidth();
float height = pageSize.getHeight();
// 重复铺满水印
addRepeatedWatermark(content, width, height, signText);
// 添加页眉文字
canvas.beginText();
canvas.setFontAndSize(baseFont, fontSize);
canvas.setTextMatrix(textX, textY);
canvas.showText(headerText);
canvas.endText();
// 添加页眉分隔线可选
addHeaderLine(canvas, pageWidth, textY - 10);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 添加水印
* @param content
* @param width
* @param height
* @param signText
*/
private void addRepeatedWatermark(PdfContentByte content, float width, float height, String signText) {
// 计算文字尺寸
float fontSize = Convert.toFloat("8");
float textWidth = baseFont.getWidthPoint(signText, fontSize);
float textHeight = baseFont.getAscentPoint(signText, fontSize) -
baseFont.getDescentPoint(signText, fontSize);
// 计算间距
float stepX = textWidth + 200;
float stepY = textHeight + 200;
// 添加重复水印
for (float x = textWidth/2 ; x < width; x += stepX) {
for (float y = textHeight/2 ; y < height; y += stepY) {
content.beginText();
content.showTextAligned(
Element.ALIGN_CENTER,
signText,
x,
y,
fontSize
);
content.endText();
}
}
}
/**
* 添加页眉线
* @param canvas
* @param pageWidth
* @param yPos
*/
private void addHeaderLine(PdfContentByte canvas, float pageWidth, float yPos) {
canvas.setLineWidth(0.5f);
canvas.moveTo(50, yPos);
canvas.lineTo(pageWidth - 50, yPos);
canvas.stroke();
}
}
}

+ 65
- 0
hxhq-modules/hxhq-system/src/main/java/com/hxhq/business/utils/Pdf/PdfExportUtil.java View File

@ -0,0 +1,65 @@
package com.hxhq.business.utils.Pdf;
import com.hxhq.common.core.exception.ServiceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
* pdf导出
*/
@Component
public class PdfExportUtil {
private static final Logger logger = LoggerFactory.getLogger(PdfExportUtil.class);
public static Object invokeMethod(String className, String methodName, Object... params)
throws Exception {
// 加载类
Class<?> clazz = Class.forName(className);
// 创建实例
Object instance = clazz.getDeclaredConstructor().newInstance();
// 改为不预先获取参数类型而是在查找方法时动态匹配
Method method = null;
for (Method m : clazz.getMethods()) {
if (m.getName().equals(methodName) &&
m.getParameterCount() == params.length) {
method = m;
}
}
if (method == null) {
throw new NoSuchMethodException("找不到匹配的方法: " + methodName);
}
// 调用方法
return method.invoke(instance, params);
}
public static void main(String[] args) throws Exception {
String result = export(
"com.hxhq.business.utils.Pdf.Template.Sp.Sp001",
"exportDetail",
"麻精药导出",
"张三 2025-12-12 14:52:52"
);
}
/**
* 导出
*
* @param className
* @param methodName
* @param params
* @return
*/
public static String export(String className, String methodName, Object... params) {
try {
return (String) invokeMethod(className, methodName, params);
} catch (Exception ex) {
logger.error(ex.getMessage());
throw new ServiceException(ex.getMessage());
}
}
}

+ 79
- 0
hxhq-modules/hxhq-system/src/main/java/com/hxhq/business/utils/Pdf/Resource/Drug.java View File

@ -0,0 +1,79 @@
package com.hxhq.business.utils.Pdf.Resource;
import com.alibaba.fastjson2.JSONObject;
import com.hxhq.business.domain.Mjy;
import com.hxhq.business.utils.Pdf.PdfBaseUtil;
import com.hxhq.common.security.utils.SecurityUtils;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Document;
import com.itextpdf.text.Element;
import com.itextpdf.text.pdf.draw.LineSeparator;
import org.apache.http.client.utils.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* 麻精药详情
*
* @author tanfei
*/
public class Drug {
private static final Logger logger = LoggerFactory.getLogger(Drug.class.getName());
/**
* 导出
*
* @param mjy
* @return
*/
public static String exportDetail(Mjy mjy) {
Document document = null;
FileOutputStream fos = null;
String filePath = PdfBaseUtil.getFilePath();
try {
document = PdfBaseUtil.init(document, fos, filePath, SecurityUtils.getNickName(), mjy.getMc());
// 基本信息
PdfBaseUtil.addUnderlinedTitle(document, "基本信息", 10);
Map<String, String> formData1 = new LinkedHashMap<>();
formData1.put("名称", mjy.getMc());
formData1.put("编号", mjy.getBh());
formData1.put("浓度", mjy.getNd() + mjy.getNddw());
formData1.put("库存量", mjy.getKc() + mjy.getKcdw());
formData1.put("失效日期", DateUtils.formatDate(mjy.getSxrq()));
formData1.put("存储条件", mjy.getCctj());
formData1.put("存储位置", mjy.getCcwz());
PdfBaseUtil.addFormTableColumns(document, formData1, 2);
// 表单信息
PdfBaseUtil.addUnderlinedTitle(document, "表单信息", 10);
Map<String, String> formData3 = new LinkedHashMap<>();
formData3.put("所属表单", "");
formData3.put("所属试验信息", mjy.getMdIds());
formData3.put("表单所属人", mjy.getBdId().toString());
PdfBaseUtil.addFormTableColumns(document, formData3, 2);
logger.info("生成成功:{}", filePath);
} catch (Exception e) {
logger.error("生成失败", e);
throw new RuntimeException("生成失败: " + e.getMessage());
} finally {
if (document != null) {
document.close();
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
logger.error("关闭文件流失败", e);
}
}
}
return filePath;
}
}

+ 55
- 0
hxhq-modules/hxhq-system/src/main/java/com/hxhq/business/utils/Pdf/Template/Sp/Sp001.java View File

@ -0,0 +1,55 @@
package com.hxhq.business.utils.Pdf.Template.Sp;
import com.hxhq.business.utils.Pdf.PdfBaseUtil;
import com.itextpdf.text.Document;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* 色谱001
* @author tanfei
*/
public class Sp001 {
private static final Logger logger = LoggerFactory.getLogger(Sp001.class.getName());
/**导出
* @param headerText
* @param signText
* @return
*/
public static String exportDetail( String headerText,String signText) {
Document document = null;
FileOutputStream fos = null;
String filePath = PdfBaseUtil.getFilePath();
try {
document=PdfBaseUtil.init(document,fos,filePath,signText,headerText);
Map<String, String> formData = new LinkedHashMap<>();
formData.put("姓名","张三");
formData.put("性别", "男");
formData.put("手机","15882062878");
// 生成table
PdfBaseUtil.addFormTableColumns(document, formData,3);
logger.info("生成成功:{}", filePath);
} catch (Exception e) {
logger.error("生成失败", e);
throw new RuntimeException("生成失败: " + e.getMessage());
} finally {
if (document != null) {
document.close();
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
logger.error("关闭文件流失败", e);
}
}
}
return filePath;
}
}

+ 0
- 372
hxhq-modules/hxhq-system/src/main/java/com/hxhq/business/utils/PdfUtil.java View File

@ -1,372 +0,0 @@
package com.hxhq.business.utils;
import com.hxhq.common.core.utils.DateUtils;
import com.itextpdf.text.*;
import com.itextpdf.text.Font;
import com.itextpdf.text.pdf.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.*;
import java.util.List;
/**
* OpenPDF工具类 - 支持保存到本地文件
*/
@Component
public class PdfUtil {
private static final Logger log = LoggerFactory.getLogger(PdfUtil.class);
public static void main(String[] args) {
/* String fileDir="d:/";
exportForm("张三 2025-12-12 14:52:52",fileDir);
exportTable("张三 2025-12-12 14:52:52",fileDir);*/
/*try {
appendWithPdfStamper("D:\\hxhq\\uploadPath\\2026\\01\\08\\20260108135814A001.pdf", "D:\\hxhq\\uploadPath\\2026\\01\\08\\output.pdf",
"这是使用iText 5追加的内容。");
} catch (Exception e) {
e.printStackTrace();
}*/
exportTable("张三 2025-12-12 14:52:52","D:\\hxhq\\uploadPath\\2026\\01\\08");
}
/**
* 复制原有PDF的所有页面到新Document中
*/
private static void copyOriginalPagesToDocument(Document doc, PdfWriter writer, PdfReader reader) throws DocumentException {
int pageCount = reader.getNumberOfPages();
PdfContentByte canvas = writer.getDirectContent(); // 获取直接内容画布
for (int i = 1; i <= pageCount; i++) {
doc.newPage(); // 新建一页与原PDF页面一一对应
// 5.5.11中通过PdfImportedPage导入原有页面
PdfImportedPage importedPage = writer.getImportedPage(reader, i);
// 将原有页面绘制到新文档的当前页
canvas.addTemplate(importedPage, 0, 0);
}
}
/**
* 导出form
* @param headerText
* @param fileDir
* @return
*/
public static String exportForm(String headerText,String fileDir) {
Document document = null;
FileOutputStream fos = null;
String filePath = "";
try {
// 1. 生成文件名
String fileName = generateFileName();
// 2. 确保目录存在
File dir = new File(fileDir);
if (!dir.exists()) {
dir.mkdirs();
}
// 3. 完整文件路径
filePath = Paths.get(fileDir, fileName).toString();
// 创建PDF文档 设置文档边距避免内容遮挡页眉页脚
float topMargin = 70; // 顶部边距为页眉留出空间
float bottomMargin = 60; // 底部边距为页脚留出空间
float leftMargin = 50; // 左边距
float rightMargin = 50; // 右边距
document = new Document(PageSize.A4,
leftMargin, rightMargin, topMargin, bottomMargin);
fos = new FileOutputStream(filePath);
PdfWriter writer = PdfWriter.getInstance(document, fos);
// 设置页面事件每页添加文字页眉
writer.setPageEvent(new TextHeaderEvent(headerText));
// 5. 设置PDF属性
document.addTitle("华西海圻");
document.addAuthor("华西海圻");
document.addCreator("华西海圻");
document.addCreationDate();
document.open();
Map<String, String> formData = new LinkedHashMap<>();
formData.put("姓名","张三");
formData.put("性别", "男");
formData.put("手机","15882062878");
// 生成table
addFormTableColumns(document, formData,3);
log.info("生成成功:{}", filePath);
} catch (Exception e) {
log.error("生成失败", e);
throw new RuntimeException("生成失败: " + e.getMessage());
} finally {
if (document != null) {
document.close();
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
log.error("关闭文件流失败", e);
}
}
}
return filePath;
}
/**
* 导出table
* @param headerText
* @param fileDir
* @return
*/
public static String exportTable( String headerText,String fileDir) {
Document document = null;
FileOutputStream fos = null;
String filePath = "";
try {
// 1. 生成文件名
String fileName = generateFileName();
// 2. 确保目录存在
File dir = new File(fileDir);
if (!dir.exists()) {
dir.mkdirs();
}
// 3. 完整文件路径
filePath = Paths.get(fileDir, fileName).toString();
// 创建PDF文档 设置文档边距避免内容遮挡页眉页脚
float topMargin = 70; // 顶部边距为页眉留出空间
float bottomMargin = 60; // 底部边距为页脚留出空间
float leftMargin = 50; // 左边距
float rightMargin = 50; // 右边距
document = new Document(PageSize.A4,
leftMargin, rightMargin, topMargin, bottomMargin);
fos = new FileOutputStream(filePath);
PdfWriter writer = PdfWriter.getInstance(document, fos);
// 设置页面事件每页添加文字页眉
writer.setPageEvent(new TextHeaderEvent(headerText));
// 5. 设置PDF属性
document.addTitle("华西海圻");
document.addAuthor("华西海圻");
document.addCreator("华西海圻");
document.addCreationDate();
document.open();
// 6. 设置中文字体
BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
Font headerFont = new Font(bfChinese, 12, Font.BOLD);
Font contentFont = new Font(bfChinese, 10, Font.NORMAL);
// 9. 创建表格
PdfPTable table = new PdfPTable(3);
table.setWidthPercentage(100);
table.setSpacingBefore(10);
// 10. 表头
String[] headers = {"签名人", "签名意义", "签名时间"};
for (String header : headers) {
PdfPCell cell = new PdfPCell(new Phrase(header, headerFont));
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
cell.setBackgroundColor(BaseColor.WHITE);
cell.setPadding(8);
cell.setBorderWidth(1);
table.addCell(cell);
}
// 11. 表格数据
int rowNum = 0;
for (int i = 0; i < 300; i ++) {
// 交替行颜色
if (rowNum % 2 == 0) {
table.getDefaultCell().setBackgroundColor(BaseColor.WHITE);
} else {
table.getDefaultCell().setBackgroundColor(BaseColor.WHITE);
}
table.addCell(createCell("1", contentFont));
table.addCell(createCell("2", contentFont));
table.addCell(createCell("3", contentFont));
rowNum++;
}
document.add(table);
log.info("生成成功:{}", filePath);
} catch (Exception e) {
log.error("生成失败", e);
throw new RuntimeException("生成失败: " + e.getMessage());
} finally {
if (document != null) {
document.close();
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
log.error("关闭文件流失败", e);
}
}
}
return filePath;
}
/**
* 创建表单
*/
public static void addFormTableColumns(Document document, Map<String, String> data, Integer count)
throws DocumentException, IOException {
// 创建3列表格
PdfPTable table = new PdfPTable(count);
table.setWidthPercentage(100);
table.setSpacingBefore(10);
table.setSpacingAfter(10);
// 设置等宽列
table.setWidths(new float[]{1, 1, 1});
// 创建字体
BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
Font labelFont = new Font(baseFont, 10, Font.NORMAL, BaseColor.BLACK);
Font valueFont = new Font(baseFont, 10, Font.NORMAL, BaseColor.BLACK);
// 将数据转换为List
List<Map.Entry<String, String>> entries = new ArrayList<>(data.entrySet());
// 每3个字段一组每组一行
for (int i = 0; i < entries.size(); i += count) {
// 创建一行
for (int j = 0; j < count; j++) {
int index = i + j;
if (index < entries.size()) {
Map.Entry<String, String> entry = entries.get(index);
// 创建单元格内容
Phrase cellContent = new Phrase();
cellContent.add(new Chunk(entry.getKey() + ":", labelFont));
cellContent.add(new Chunk(com.hxhq.common.core.utils.StringUtils.isBlank(entry.getValue()) ? "" : entry.getValue(), valueFont));
PdfPCell cell = new PdfPCell(cellContent);
cell.setBorder(Rectangle.NO_BORDER); // 无边框
cell.setPadding(4);
cell.setHorizontalAlignment(Element.ALIGN_LEFT);
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell.setMinimumHeight(20); // 最小高度
table.addCell(cell);
} else {
// 添加空单元格保持布局
PdfPCell emptyCell = new PdfPCell();
emptyCell.setBorder(Rectangle.NO_BORDER);
emptyCell.setMinimumHeight(20);
table.addCell(emptyCell);
}
}
}
document.add(table);
}
/**
* 创建表格
*/
private static PdfPCell createCell(String content, Font font) {
PdfPCell cell = new PdfPCell(new Phrase(content, font));
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell.setPadding(6);
cell.setMinimumHeight(25);
return cell;
}
/**
* 生成文件名
*/
private static String generateFileName() {
Random random= new Random();
String timestamp = DateUtils.dateTimeNow("yyyyMMddHHmmss");
return String.format("%s_%s.pdf", timestamp,random.nextInt(1000));
}
/**
* 页面事件处理类 - 每页添加文字页眉
*/
static class TextHeaderEvent extends PdfPageEventHelper {
private String headerText;
private BaseFont baseFont;
public TextHeaderEvent(String headerText) throws Exception {
this.headerText = headerText;
// 创建字体支持中文
this.baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
}
@Override
public void onEndPage(PdfWriter writer, Document document) {
try {
// 获取页面尺寸
Rectangle pageSize = document.getPageSize();
float pageWidth = pageSize.getWidth();
float pageHeight = pageSize.getHeight();
// 设置页眉参数
float topMargin = 30; // 顶部边距
float fontSize = 12; // 字体大小
// 计算文字宽度用于居中
float textWidth = baseFont.getWidthPoint(headerText, fontSize);
// 计算居中位置
float textX = (pageWidth - textWidth) / 2;
float textY = pageHeight - topMargin;
// 获取画布
PdfContentByte canvas = writer.getDirectContent();
// 添加页眉文字
canvas.beginText();
canvas.setFontAndSize(baseFont, fontSize);
canvas.setTextMatrix(textX, textY);
canvas.showText(headerText);
canvas.endText();
// 添加页眉分隔线可选
addHeaderLine(canvas, pageWidth, textY - 10);
} catch (Exception e) {
e.printStackTrace();
}
}
private void addHeaderLine(PdfContentByte canvas, float pageWidth, float yPos) {
canvas.setLineWidth(0.5f);
canvas.moveTo(50, yPos);
canvas.lineTo(pageWidth - 50, yPos);
canvas.stroke();
}
}
}

Loading…
Cancel
Save