Browse Source

fix:[模板管理]优化

master
15881625488@163.com 1 month ago
parent
commit
b2a67a0e29
2 changed files with 528 additions and 0 deletions
  1. +61
    -0
      hxhq-modules/hxhq-system/src/main/java/com/hxhq/business/form/study/StudyFormFillExportForm.java
  2. +467
    -0
      hxhq-modules/hxhq-system/src/main/java/com/hxhq/business/utils/StudyFormFillUtil.java

+ 61
- 0
hxhq-modules/hxhq-system/src/main/java/com/hxhq/business/form/study/StudyFormFillExportForm.java View File

@ -0,0 +1,61 @@
package com.hxhq.business.form.study;
/**
* @author tanfei
*/
public class StudyFormFillExportForm {
/** 表单id */
private Long studyFormFillId;
/** url */
private String url;
/** lang */
private String lang;
/** version */
private String version;
/** jcgjlx */
private Integer jcgjlx;
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getLang() {
return lang;
}
public void setLang(String lang) {
this.lang = lang;
}
public Integer getJcgjlx() {
return jcgjlx;
}
public void setJcgjlx(Integer jcgjlx) {
this.jcgjlx = jcgjlx;
}
public Long getStudyFormFillId() {
return studyFormFillId;
}
public void setStudyFormFillId(Long studyFormFillId) {
this.studyFormFillId = studyFormFillId;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}

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

@ -0,0 +1,467 @@
package com.hxhq.business.utils;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hxhq.business.domain.*;
import com.hxhq.business.utils.lang.TemplateUtil;
import com.hxhq.business.utils.pdf.PdfBaseUtil;
import com.hxhq.business.utils.pdf.PdfExportUtil;
import com.hxhq.common.core.text.Convert;
import com.hxhq.common.core.utils.DateUtils;
import com.hxhq.common.core.utils.StringUtils;
import com.hxhq.common.security.utils.SecurityUtils;
import com.hxhq.system.api.model.LoginUser;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
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.List;
import java.util.Random;
import java.util.StringJoiner;
/**
* 试验方法pdf导出
*
* @author HanLong
*/
@Component
public class StudyFormFillUtil {
private static final Logger log = LoggerFactory.getLogger(StudyFormFillUtil.class);
public static String language = "zh";
/**
* 资源映射路径 前缀
*/
@Value("${file.prefix}")
public String localFilePrefix;
/**
* 域名或本机访问地址
*/
@Value("${file.domain}")
public String domain;
/**
* 上传文件存储在本地的根路径
*/
@Value("${file.path}")
private String localFilePath;
/**
* 复制原有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);
}
}
/**
* 导出table
*
* @param headerText
* @param fileDir
* @return
*/
public static String export(String version,String lang, String headerText, String srcPdf, String fileDir, List<StudyFormFillJcgj> jcgjList, List<StudyFormFillQmxx> qmxxList) {
language = lang;
Document document = null;
FileOutputStream fos = null;
String filePath = "";
String fileName = "";
try {
// 1. 生成文件名
fileName = generateFileName();
// 2. 确保目录存在
File dir = new File(fileDir);
if (!dir.exists()) {
dir.mkdirs();
}
// 3. 完整文件路径
filePath = Paths.get(fileDir, fileName).toString();
// 创建PDF文档 设置文档边距避免内容遮挡页眉页脚
// 1. 读取原有PDF获取页面尺寸保证新文档与原文档格式一致
PdfReader srcReader = new PdfReader(srcPdf);
// 取第一页尺寸作为新文档尺寸
Rectangle pageSize = srcReader.getPageSize(1);
// 2. 初始化DocumentiText 5的核心高层类
document = new Document(pageSize);
fos = new FileOutputStream(filePath);
// 3. 关联PdfWriter绑定Document和输出流5.5.11必须先创建Writer再open Document
PdfWriter writer = PdfWriter.getInstance(document, fos);
// 设置页面事件每页添加文字页眉
String sign = "hxhq";
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser != null) {
sign = loginUser.getSysUser().getNickName() + " " + DateUtils.getTime();
}
writer.setPageEvent(new TextHeaderEvent(sign+" "+version, headerText, false));
// 4. 设置PDF属性
document.addTitle("华西海圻");
document.addAuthor("华西海圻");
document.addCreator("华西海圻");
document.addCreationDate();
document.open();
// 5. 复制原有PDF的所有页面到新Document中
copyOriginalPagesToDocument(document, writer, srcReader);
// 7. 表格设置到新的一页
document.newPage();
addQmxx(document, qmxxList, lang);
addJcgj(document, jcgjList, lang);
} catch (Exception 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 fileName;
}
/**
* 签名信息
* 申请表单
*
* @param document
* @param studyFormFillQmxxList
* @throws IOException
* @throws DocumentException
*/
public static void addQmxx(Document document, List<StudyFormFillQmxx> studyFormFillQmxxList, String lang) throws IOException, DocumentException {
language = lang;
PdfBaseUtil.addUnderlinedTitle(document, getName("签名信息"), 10, true);
// 9. 表头
BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
Font headerFont = new Font(bfChinese, 10, Font.NORMAL);
Font contentFont = new Font(bfChinese, 10, Font.NORMAL);
// 8. 创建表格
PdfPTable table = new PdfPTable(4);
table.setWidthPercentage(100);
table.setSpacingBefore(10);
String[] headers = {getName("签名人"), getName("签名意义"), getName("签名时间"), getName("备注原因")};
for (String header : headers) {
PdfPCell cell = new PdfPCell(new Phrase(header, headerFont));
cell.setPadding(8);
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
cell.setBackgroundColor(BaseColor.WHITE);
cell.setBorderWidth(1);
table.addCell(cell);
}
if (studyFormFillQmxxList.size() > 0) {
int rowNum = 0;
for (StudyFormFillQmxx studyFormFillQmxx : studyFormFillQmxxList) {
// 交替行颜色
if (rowNum % 2 == 0) {
table.getDefaultCell().setBackgroundColor(BaseColor.WHITE);
} else {
table.getDefaultCell().setBackgroundColor(BaseColor.WHITE);
}
table.addCell(PdfBaseUtil.createCell(studyFormFillQmxx.getQmrMc(), contentFont));
table.addCell(PdfBaseUtil.createCell("en".equals(language) ? studyFormFillQmxx.getQmyyEn() : studyFormFillQmxx.getQmyy(), contentFont));
table.addCell(PdfBaseUtil.createCell(PdfExportUtil.parseDateToStr(studyFormFillQmxx.getCreateTime()), contentFont));
table.addCell(PdfBaseUtil.createCell(studyFormFillQmxx.getRemark(), contentFont));
rowNum++;
}
}
document.add(table);
}
/**
* 稽查轨迹
* 申请表单
*
* @param document
* @param studyFormFillJcgjList
* @throws IOException
* @throws DocumentException
*/
public static void addJcgj(Document document, List<StudyFormFillJcgj> studyFormFillJcgjList, String lang) throws IOException, DocumentException {
language = lang;
PdfBaseUtil.addUnderlinedTitle(document, getName("稽查轨迹"), 10, true);
for (StudyFormFillJcgj jcgj : studyFormFillJcgjList) {
StringJoiner result = new StringJoiner(", ");
if ("en".equals(lang)) {
PdfBaseUtil.addUnderlinedTitle(document, PdfExportUtil.parseDateToStr(jcgj.getCreateTime()) + " " + jcgj.getJcmcEn(), 10, false);
if (StringUtils.isNoneBlank(jcgj.getJcnrEn())) {
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonArray = mapper.readTree(jcgj.getJcnrEn());
for (JsonNode node : jsonArray) {
if (node.get("name") != null) {
String name = node.get("name").asText();
String value = node.get("value") != null ? node.get("value").asText() : "";
result.add(name + ":" + value);
}
}
}
} else {
PdfBaseUtil.addUnderlinedTitle(document, PdfExportUtil.parseDateToStr(jcgj.getCreateTime()) + " " + jcgj.getJcmc(), 10, false);
if (StringUtils.isNoneBlank(jcgj.getJcnr())) {
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonArray = mapper.readTree(jcgj.getJcnr());
for (JsonNode node : jsonArray) {
if (node.get("name") != null) {
String name = node.get("name").asText();
String value = node.get("value") != null ? node.get("value").asText() : "";
result.add(name + ":" + value);
}
}
}
}
if (StringUtils.isNoneBlank(jcgj.getRemark())) {
result.add(getName("备注") + ":" + jcgj.getRemark());
}
if (StringUtils.isNoneBlank(jcgj.getQmrMc())) {
result.add(getName("签名人") + ":" + jcgj.getQmrMc());
}
PdfBaseUtil.addUnderlinedTitle(document, result.toString(), 10, false);
}
}
/**
* 获取名称
*
* @param name
* @return
*/
public static String getName(String name) {
return "en".equals(language) ? TemplateUtil.getEn(name) : name;
}
/**
* 创建表格
*/
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 Font footerFont;
private String signText;
private String headerText;
private BaseFont baseFont;
private Boolean showHaderLine = true;
private int totalPages = 0;
private PdfTemplate total;
public TextHeaderEvent(String signText, String headerText, Boolean showHaderLine) throws Exception {
try {
this.showHaderLine = showHaderLine;
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 = 15; // 顶部边距
float fontSize = 12; // 字体大小
// 计算文字宽度用于居中
float textWidth = baseFont.getWidthPoint(signText, fontSize);
// 计算居中位置
float textX = (pageSize.getLeft() + pageSize.getRight()) / 2;
float textY = pageHeight - topMargin;
// 获取画布
PdfContentByte canvas = writer.getDirectContent();
int currentPage = writer.getPageNumber();
float y = document.bottom() - 20;
// 在每一页都重新计算确保位置准确
String pageText = signText+ " 第 " + 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);
// 添加页眉文字
if (StringUtils.isNoneBlank(headerText)) {
PdfContentByte cb2 = writer.getDirectContent();
ColumnText.showTextAligned(cb2, Element.ALIGN_LEFT,
new Phrase(headerText, footerFont), startX, textY, 0);
// canvas.beginText();
// canvas.setFontAndSize(baseFont, fontSize);
// canvas.setTextMatrix(textX, textY);
// canvas.showText(headerText);
// canvas.endText();
if (showHaderLine) {
// 添加页眉分隔线可选
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("10");
float textWidth = baseFont.getWidthPoint(signText, fontSize) + 50;
float textHeight = baseFont.getAscentPoint(signText, fontSize) -
baseFont.getDescentPoint(signText, fontSize);
// 计算间距
float stepX = textWidth + 70;
float stepY = textHeight + 100;
// 添加重复水印
Integer two = 2;
for (float x = textWidth / two; x < width; x += stepX) {
for (float y = textHeight / two; 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.lineTo(pageWidth, yPos);
canvas.stroke();
}
}
}

Loading…
Cancel
Save