| @ -0,0 +1,266 @@ | |||||
| package com.hxhq.business.utils; | |||||
| import com.hxhq.business.domain.StudyMethod; | |||||
| import com.hxhq.business.domain.StudyMethodRead; | |||||
| import com.hxhq.common.core.utils.DateUtils; | |||||
| import com.hxhq.common.security.utils.SecurityUtils; | |||||
| 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.*; | |||||
| import java.util.List; | |||||
| /** | |||||
| * OpenPDF工具类 - 支持保存到本地文件 | |||||
| */ | |||||
| @Component | |||||
| public class StudyMethodFileUtil { | |||||
| private static final Logger log = LoggerFactory.getLogger(StudyMethodFileUtil.class); | |||||
| /** | |||||
| * 资源映射路径 前缀 | |||||
| */ | |||||
| @Value("${file.prefix}") | |||||
| public String localFilePrefix; | |||||
| /** | |||||
| * 域名或本机访问地址 | |||||
| */ | |||||
| @Value("${file.domain}") | |||||
| public String domain; | |||||
| /** | |||||
| * 上传文件存储在本地的根路径 | |||||
| */ | |||||
| @Value("${file.path}") | |||||
| private String localFilePath; | |||||
| public String exportStudyMethodFile(StudyMethod studyMethod, List<StudyMethodRead> list) { | |||||
| String fileUrl = studyMethod.getFileUrl(); | |||||
| fileUrl = fileUrl.replaceFirst(localFilePrefix, ""); | |||||
| int indexOf = fileUrl.lastIndexOf("/"); | |||||
| String path = fileUrl.substring(0, indexOf); | |||||
| String exportFileName = exportTable(SecurityUtils.getNickName() + DateUtils.dateTimeNow(DateUtils.YYYY_MM_DD_HH_MM_SS), list, | |||||
| localFilePath + fileUrl, localFilePath + File.separator + path); | |||||
| return localFilePrefix + path + File.separator + exportFileName; | |||||
| } | |||||
| /** | |||||
| * 复制原有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 exportTable(String headerText, List<StudyMethodRead> list, String SRC_PDF, String fileDir) { | |||||
| 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(SRC_PDF); | |||||
| Rectangle pageSize = srcReader.getPageSize(1); // 取第一页尺寸作为新文档尺寸 | |||||
| // 2. 初始化Document(iText 5的核心高层类) | |||||
| document = new Document(pageSize); | |||||
| fos = new FileOutputStream(filePath); | |||||
| // 3. 关联PdfWriter,绑定Document和输出流(5.5.11必须先创建Writer再open Document) | |||||
| PdfWriter writer = PdfWriter.getInstance(document, fos); | |||||
| // 设置页面事件,每页添加文字页眉 | |||||
| writer.setPageEvent(new TextHeaderEvent(headerText)); | |||||
| // 4. 设置PDF属性 | |||||
| document.addTitle("华西海圻"); | |||||
| document.addAuthor("华西海圻"); | |||||
| document.addCreator("华西海圻"); | |||||
| document.addCreationDate(); | |||||
| document.open(); | |||||
| // 5. 复制原有PDF的所有页面到新Document中 | |||||
| copyOriginalPagesToDocument(document, writer, srcReader); | |||||
| // 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); | |||||
| // 7. 表格设置到新的一页 | |||||
| document.newPage(); | |||||
| // 8. 创建表格 | |||||
| PdfPTable table = new PdfPTable(4); | |||||
| table.setWidthPercentage(100); | |||||
| table.setSpacingBefore(10); | |||||
| // 9. 表头 | |||||
| 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); | |||||
| } | |||||
| // 10. 表格数据 | |||||
| int rowNum = 0; | |||||
| for (StudyMethodRead studyMethodRead : list) { | |||||
| // 交替行颜色 | |||||
| if (rowNum % 2 == 0) { | |||||
| table.getDefaultCell().setBackgroundColor(BaseColor.WHITE); | |||||
| } else { | |||||
| table.getDefaultCell().setBackgroundColor(BaseColor.WHITE); | |||||
| } | |||||
| table.addCell(createCell(studyMethodRead.getQmrMc(), contentFont)); | |||||
| table.addCell(createCell(studyMethodRead.getQmyy(), contentFont)); | |||||
| table.addCell(createCell(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, studyMethodRead.getCreateTime()), contentFont)); | |||||
| table.addCell(createCell(studyMethodRead.getRemark(), 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 fileName; | |||||
| } | |||||
| /** | |||||
| * 创建表格 | |||||
| */ | |||||
| 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 = 15; // 顶部边距 | |||||
| float fontSize = 10; // 字体大小 | |||||
| // 计算文字宽度(用于居中) | |||||
| 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(); | |||||
| } | |||||
| } | |||||
| } | |||||