|
|
@@ -5,19 +5,466 @@ import com.goafanti.common.constant.AFTConstants;
|
|
|
import com.goafanti.common.utils.DateUtils;
|
|
|
import com.goafanti.common.utils.excel.FileUtils;
|
|
|
import com.goafanti.expenseAccount.bo.MainExpenseAccount;
|
|
|
+import com.itextpdf.text.Document;
|
|
|
+import com.itextpdf.text.Font;
|
|
|
import com.itextpdf.text.*;
|
|
|
import com.itextpdf.text.pdf.BaseFont;
|
|
|
+import com.itextpdf.text.pdf.PdfPCell;
|
|
|
+import com.itextpdf.text.pdf.PdfPTable;
|
|
|
import com.itextpdf.text.pdf.PdfWriter;
|
|
|
+import org.apache.poi.ss.usermodel.*;
|
|
|
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
|
|
+import org.apache.poi.xwpf.usermodel.*;
|
|
|
import org.springframework.http.MediaType;
|
|
|
|
|
|
+import javax.imageio.ImageIO;
|
|
|
import javax.servlet.http.HttpServletResponse;
|
|
|
-import java.io.FileNotFoundException;
|
|
|
-import java.io.FileOutputStream;
|
|
|
-import java.io.IOException;
|
|
|
+import java.awt.image.BufferedImage;
|
|
|
+import java.io.*;
|
|
|
import java.util.Date;
|
|
|
|
|
|
public class PDFUtils {
|
|
|
|
|
|
+ /**
|
|
|
+ * 将多个图片合并为一个PDF文件
|
|
|
+ *
|
|
|
+ * @param imagesDir 图片目录路径
|
|
|
+ * @param pdfFilePath 输出PDF文件路径
|
|
|
+ * @throws IOException
|
|
|
+ * @throws DocumentException
|
|
|
+ */
|
|
|
+ public static void mergeImagesToPDF(String imagesDir, String pdfFilePath)
|
|
|
+ throws IOException, DocumentException {
|
|
|
+ Document document = new Document(PageSize.A4);
|
|
|
+ PdfWriter.getInstance(document, new FileOutputStream(pdfFilePath));
|
|
|
+ document.open();
|
|
|
+
|
|
|
+ File dir = new File(imagesDir);
|
|
|
+ File[] imageFiles = dir.listFiles((d, name) -> name.toLowerCase().endsWith(".png") ||
|
|
|
+ name.toLowerCase().endsWith(".jpg") ||
|
|
|
+ name.toLowerCase().endsWith(".jpeg"));
|
|
|
+
|
|
|
+ if (imageFiles != null) {
|
|
|
+ // 按文件名排序确保页面顺序正确
|
|
|
+ java.util.Arrays.sort(imageFiles, (f1, f2) -> {
|
|
|
+ String name1 = f1.getName().replaceAll("[^0-9]", "");
|
|
|
+ String name2 = f2.getName().replaceAll("[^0-9]", "");
|
|
|
+ if (name1.isEmpty() || name2.isEmpty()) {
|
|
|
+ return f1.getName().compareTo(f2.getName());
|
|
|
+ }
|
|
|
+ return Integer.parseInt(name1) - Integer.parseInt(name2);
|
|
|
+ });
|
|
|
+
|
|
|
+ // 将每个图片添加到PDF中
|
|
|
+ for (File imageFile : imageFiles) {
|
|
|
+ BufferedImage bufferedImage = ImageIO.read(imageFile);
|
|
|
+ if (bufferedImage != null) {
|
|
|
+ // 计算图片在页面中的尺寸
|
|
|
+ float documentWidth = document.getPageSize().getWidth() - document.leftMargin() - document.rightMargin();
|
|
|
+ float documentHeight = document.getPageSize().getHeight() - document.topMargin() - document.bottomMargin();
|
|
|
+
|
|
|
+ // 按比例缩放图片
|
|
|
+ float imageWidth = bufferedImage.getWidth();
|
|
|
+ float imageHeight = bufferedImage.getHeight();
|
|
|
+ float scale = Math.min(documentWidth / imageWidth, documentHeight / imageHeight);
|
|
|
+
|
|
|
+ Image image = Image.getInstance(imageFile.getAbsolutePath());
|
|
|
+ image.scaleAbsolute(imageWidth * scale, imageHeight * scale);
|
|
|
+
|
|
|
+ // 居中显示图片
|
|
|
+ image.setAlignment(Element.ALIGN_CENTER);
|
|
|
+
|
|
|
+ // 添加图片到PDF
|
|
|
+ document.add(image);
|
|
|
+
|
|
|
+ // 如果不是最后一个图片,则添加新页面
|
|
|
+ if (imageFile != imageFiles[imageFiles.length - 1]) {
|
|
|
+ document.newPage();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ document.close();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 删除临时目录及其内容
|
|
|
+ *
|
|
|
+ * @param dir 临时目录
|
|
|
+ */
|
|
|
+ private static void deleteTempDirectory(File dir) {
|
|
|
+ if (dir.exists() && dir.isDirectory()) {
|
|
|
+ File[] files = dir.listFiles();
|
|
|
+ if (files != null) {
|
|
|
+ for (File file : files) {
|
|
|
+ if (file.isDirectory()) {
|
|
|
+ deleteTempDirectory(file);
|
|
|
+ } else {
|
|
|
+ file.delete();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ dir.delete();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将Word文档转换为图片后再导出为PDF并提供下载
|
|
|
+ *
|
|
|
+ * @param wordFilePath Word文件路径
|
|
|
+ * @param response HttpServletResponse对象
|
|
|
+ * @param pdfFileName 生成的PDF文件名
|
|
|
+ * @param uploadPath 上传路径
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ public static void convertWordToImagesToPDFForDownload(String wordFilePath,
|
|
|
+ javax.servlet.http.HttpServletResponse response,
|
|
|
+ String pdfFileName,
|
|
|
+ String uploadPath) throws Exception {
|
|
|
+ String realFileName = uploadPath + "/tmp/" + System.currentTimeMillis() + ".pdf";
|
|
|
+
|
|
|
+ // 转换Word为图片再导出为PDF
|
|
|
+ convertWordToImagesToPDF(wordFilePath, realFileName);
|
|
|
+
|
|
|
+ // 设置响应头,用于文件下载
|
|
|
+ com.goafanti.common.utils.excel.FileUtils.setAttachmentResponseHeader(
|
|
|
+ response, pdfFileName, pdfFileName + ".pdf");
|
|
|
+
|
|
|
+ // 提供文件下载
|
|
|
+ com.goafanti.common.utils.excel.FileUtils.writeBytes(
|
|
|
+ realFileName, response.getOutputStream());
|
|
|
+
|
|
|
+ // 删除临时文件
|
|
|
+ com.goafanti.common.utils.excel.FileUtils.deleteFile(realFileName);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将Word文档转换为PDF文件
|
|
|
+ *
|
|
|
+ * @param wordFilePath Word文件路径
|
|
|
+ * @param pdfFilePath 生成的PDF文件路径
|
|
|
+ * @throws IOException
|
|
|
+ * @throws DocumentException
|
|
|
+ */
|
|
|
+ public static void convertWordToPDF(String wordFilePath, String pdfFilePath)
|
|
|
+ throws IOException, DocumentException {
|
|
|
+
|
|
|
+ Document document = new Document(PageSize.A4);
|
|
|
+
|
|
|
+ try (InputStream in = new FileInputStream(wordFilePath)) {
|
|
|
+ // 创建PDF写入器
|
|
|
+ FileOutputStream outputStream = new FileOutputStream(pdfFilePath);
|
|
|
+ PdfWriter.getInstance(document, outputStream);
|
|
|
+
|
|
|
+ document.open();
|
|
|
+
|
|
|
+ // 处理Word文档内容
|
|
|
+ processWordDocument(wordFilePath, document);
|
|
|
+
|
|
|
+ document.close();
|
|
|
+ outputStream.close();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将XLSX文件转换为PDF文件
|
|
|
+ *
|
|
|
+ * @param xlsxFilePath XLSX文件路径
|
|
|
+ * @param pdfFilePath 生成的PDF文件路径
|
|
|
+ * @throws IOException
|
|
|
+ * @throws DocumentException
|
|
|
+ */
|
|
|
+ public static void convertXlsxToPDF(String xlsxFilePath, String pdfFilePath)
|
|
|
+ throws IOException, DocumentException {
|
|
|
+
|
|
|
+ Document document = new Document(PageSize.A4.rotate()); // 使用横向页面以适应更多列
|
|
|
+
|
|
|
+ try (InputStream in = new FileInputStream(xlsxFilePath)) {
|
|
|
+ Workbook workbook = new XSSFWorkbook(in);
|
|
|
+
|
|
|
+ // 创建PDF写入器
|
|
|
+ FileOutputStream outputStream = new FileOutputStream(pdfFilePath);
|
|
|
+ PdfWriter.getInstance(document, outputStream);
|
|
|
+
|
|
|
+ document.open();
|
|
|
+
|
|
|
+ // 处理Excel工作簿内容
|
|
|
+ processExcelWorkbook(workbook, document);
|
|
|
+
|
|
|
+ document.close();
|
|
|
+ outputStream.close();
|
|
|
+ workbook.close();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将Word文档转换为PDF并提供下载
|
|
|
+ *
|
|
|
+ * @param wordFilePath Word文件路径
|
|
|
+ * @param response HttpServletResponse对象
|
|
|
+ * @param pdfFileName 生成的PDF文件名
|
|
|
+ * @param uploadPath 上传路径
|
|
|
+ * @throws IOException
|
|
|
+ * @throws DocumentException
|
|
|
+ */
|
|
|
+ public static void convertWordToPDFForDownload(String wordFilePath,
|
|
|
+ HttpServletResponse response,
|
|
|
+ String pdfFileName,
|
|
|
+ String uploadPath)
|
|
|
+ throws IOException, DocumentException {
|
|
|
+
|
|
|
+ String realFileName = uploadPath + "/tmp/" + System.currentTimeMillis() + ".pdf";
|
|
|
+ Document document = new Document(PageSize.A4);
|
|
|
+
|
|
|
+ try (InputStream in = new FileInputStream(wordFilePath)) {
|
|
|
+ // 设置响应头,用于文件下载
|
|
|
+ FileUtils.setAttachmentResponseHeader(response, pdfFileName, pdfFileName + ".pdf");
|
|
|
+
|
|
|
+ // 创建PDF写入器
|
|
|
+ FileOutputStream outputStream = new FileOutputStream(realFileName);
|
|
|
+ PdfWriter.getInstance(document, outputStream);
|
|
|
+
|
|
|
+ document.open();
|
|
|
+
|
|
|
+ // 处理Word文档内容
|
|
|
+ processWordDocument(wordFilePath, document);
|
|
|
+
|
|
|
+ document.close();
|
|
|
+ outputStream.close();
|
|
|
+
|
|
|
+ // 提供文件下载
|
|
|
+ FileUtils.writeBytes(realFileName, response.getOutputStream());
|
|
|
+ FileUtils.deleteFile(realFileName);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理Word文档并将其内容添加到PDF文档中
|
|
|
+ *
|
|
|
+ * @param wordFilePath Word文件路径
|
|
|
+ * @param document PDF文档对象
|
|
|
+ * @throws IOException
|
|
|
+ * @throws DocumentException
|
|
|
+ */
|
|
|
+ private static void processWordDocument(String wordFilePath, Document document)
|
|
|
+ throws IOException, DocumentException {
|
|
|
+
|
|
|
+ try (InputStream in = new FileInputStream(wordFilePath)) {
|
|
|
+ XWPFDocument xwpfDocument = new XWPFDocument(in);
|
|
|
+ // 获取文档中的所有段落
|
|
|
+ java.util.List<XWPFParagraph> paragraphs = xwpfDocument.getParagraphs();
|
|
|
+ for (XWPFParagraph paragraph : paragraphs) {
|
|
|
+ // 创建PDF段落
|
|
|
+ Paragraph pdfParagraph = new Paragraph();
|
|
|
+ paragraph.getRuns().forEach(run -> {
|
|
|
+ System.out.println(run.getPictureText());
|
|
|
+ System.out.println(run.getFontSize());
|
|
|
+ });
|
|
|
+ // 设置段落对齐方式
|
|
|
+ switch (paragraph.getAlignment()) {
|
|
|
+ case CENTER:
|
|
|
+ pdfParagraph.setAlignment(Element.ALIGN_CENTER);
|
|
|
+ break;
|
|
|
+ case RIGHT:
|
|
|
+ pdfParagraph.setAlignment(Element.ALIGN_RIGHT);
|
|
|
+ break;
|
|
|
+ case LEFT:
|
|
|
+ case BOTH:
|
|
|
+ default:
|
|
|
+ pdfParagraph.setAlignment(Element.ALIGN_LEFT);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ // 处理段落中的所有文本块(XWPFRun)
|
|
|
+ for (XWPFRun run : paragraph.getRuns()) {
|
|
|
+ String text = run.getText(0);
|
|
|
+ if (text != null) {
|
|
|
+ // 创建带样式的PDF字体
|
|
|
+ Font pdfFont = createPDFFontFromRun(run);
|
|
|
+ Chunk chunk = new Chunk(text, pdfFont);
|
|
|
+ pdfParagraph.add(chunk);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 只有当段落有内容时才添加到文档中
|
|
|
+ if (pdfParagraph.size() > 0 && !pdfParagraph.getContent().toString().trim().isEmpty()) {
|
|
|
+ document.add(pdfParagraph);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理表格(如果有)
|
|
|
+ java.util.List<XWPFTable> tables = xwpfDocument.getTables();
|
|
|
+ for (XWPFTable table : tables) {
|
|
|
+ // 处理表格中的每一行
|
|
|
+ java.util.List<XWPFTableRow> rows = table.getRows();
|
|
|
+ for (XWPFTableRow row : rows) {
|
|
|
+ StringBuilder rowText = new StringBuilder();
|
|
|
+ java.util.List<XWPFTableCell> cells = row.getTableCells();
|
|
|
+ for (XWPFTableCell cell : cells) {
|
|
|
+ String cellText = cell.getText();
|
|
|
+ rowText.append(cellText).append(" | ");
|
|
|
+ }
|
|
|
+ if (rowText.length() > 0) {
|
|
|
+ document.add(new Paragraph(rowText.toString()));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理Excel工作簿并将其内容添加到PDF文档中
|
|
|
+ *
|
|
|
+ * @param workbook Excel工作簿对象
|
|
|
+ * @param document PDF文档对象
|
|
|
+ * @throws DocumentException
|
|
|
+ */
|
|
|
+ private static void processExcelWorkbook(Workbook workbook, Document document)
|
|
|
+ throws DocumentException {
|
|
|
+
|
|
|
+ // 添加文档标题(文件名)
|
|
|
+ document.add(new Paragraph("Excel文档转换", PDFUtils.getTitleFont()));
|
|
|
+ document.add(Chunk.NEWLINE);
|
|
|
+
|
|
|
+ // 处理每个工作表
|
|
|
+ for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
|
|
|
+ Sheet sheet = workbook.getSheetAt(i);
|
|
|
+
|
|
|
+ // 添加工作表名称
|
|
|
+ Paragraph sheetTitle = new Paragraph("工作表: " + sheet.getSheetName(), PDFUtils.getBigFont());
|
|
|
+ document.add(sheetTitle);
|
|
|
+ document.add(Chunk.NEWLINE);
|
|
|
+
|
|
|
+ // 计算需要的列数
|
|
|
+ int columnCount = 0;
|
|
|
+ for (Row row : sheet) {
|
|
|
+ int lastCellNum = row.getLastCellNum();
|
|
|
+ if (lastCellNum > columnCount) {
|
|
|
+ columnCount = lastCellNum;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (columnCount > 0) {
|
|
|
+ // 创建表格
|
|
|
+ PdfPTable table = new PdfPTable(columnCount);
|
|
|
+ table.setWidthPercentage(100);
|
|
|
+ float[] columnWidths = new float[columnCount];
|
|
|
+ for (int j = 0; j < columnCount; j++) {
|
|
|
+ columnWidths[j] = 1f;
|
|
|
+ }
|
|
|
+ table.setWidths(columnWidths);
|
|
|
+
|
|
|
+ // 处理行数据
|
|
|
+ int rowCount = 0;
|
|
|
+ for (Row row : sheet) {
|
|
|
+ // 处理每行的单元格
|
|
|
+ for (int colIndex = 0; colIndex < columnCount; colIndex++) {
|
|
|
+ Cell cell = row.getCell(colIndex);
|
|
|
+ String cellValue = getCellValue(cell);
|
|
|
+
|
|
|
+ PdfPCell pdfCell = new PdfPCell(new Phrase(cellValue, PDFUtils.getFont()));
|
|
|
+ pdfCell.setPadding(3);
|
|
|
+
|
|
|
+ // 设置表头样式
|
|
|
+ if (rowCount == 0) {
|
|
|
+ pdfCell.setBackgroundColor(BaseColor.LIGHT_GRAY);
|
|
|
+ pdfCell.setHorizontalAlignment(Element.ALIGN_CENTER);
|
|
|
+ }
|
|
|
+
|
|
|
+ table.addCell(pdfCell);
|
|
|
+ }
|
|
|
+ rowCount++;
|
|
|
+
|
|
|
+ // 限制处理的行数,避免内容过多
|
|
|
+ if (rowCount > 100) {
|
|
|
+ PdfPCell pdfCell = new PdfPCell(new Phrase("... (内容过多,省略剩余部分)", PDFUtils.getFont()));
|
|
|
+ pdfCell.setColspan(columnCount);
|
|
|
+ pdfCell.setHorizontalAlignment(Element.ALIGN_CENTER);
|
|
|
+ table.addCell(pdfCell);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ document.add(table);
|
|
|
+ }
|
|
|
+
|
|
|
+ document.add(Chunk.NEWLINE);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取单元格的值
|
|
|
+ *
|
|
|
+ * @param cell Excel单元格
|
|
|
+ * @return 单元格内容字符串
|
|
|
+ */
|
|
|
+ private static String getCellValue(Cell cell) {
|
|
|
+ if (cell == null) {
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (cell.getCellType()) {
|
|
|
+ case Cell.CELL_TYPE_STRING:
|
|
|
+ return cell.getStringCellValue();
|
|
|
+ case Cell.CELL_TYPE_NUMERIC:
|
|
|
+ if (DateUtil.isCellDateFormatted(cell)) {
|
|
|
+ return cell.getDateCellValue().toString();
|
|
|
+ } else {
|
|
|
+ // 避免科学计数法显示数字
|
|
|
+ return String.valueOf(cell.getNumericCellValue());
|
|
|
+ }
|
|
|
+ case Cell.CELL_TYPE_BOOLEAN:
|
|
|
+ return String.valueOf(cell.getBooleanCellValue());
|
|
|
+ case Cell.CELL_TYPE_FORMULA:
|
|
|
+ return cell.getCellFormula();
|
|
|
+ default:
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据Word文档中的Run样式创建PDF字体
|
|
|
+ *
|
|
|
+ * @param run Word文档中的文本块
|
|
|
+ * @return PDF字体
|
|
|
+ */
|
|
|
+ private static Font createPDFFontFromRun(XWPFRun run) {
|
|
|
+ // 获取字体大小,默认为12
|
|
|
+ int fontSize = 12;
|
|
|
+ if (run.getFontSize() != -1) {
|
|
|
+ fontSize = run.getFontSize();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置字体样式
|
|
|
+ int fontStyle = Font.NORMAL;
|
|
|
+ if (run.isBold() && run.isItalic()) {
|
|
|
+ fontStyle = Font.BOLDITALIC;
|
|
|
+ } else if (run.isBold()) {
|
|
|
+ fontStyle = Font.BOLD;
|
|
|
+ } else if (run.isItalic()) {
|
|
|
+ fontStyle = Font.ITALIC;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建字体
|
|
|
+ Font font = PDFUtils.getFont(fontSize);
|
|
|
+ font.setStyle(fontStyle);
|
|
|
+
|
|
|
+ // 处理字体颜色
|
|
|
+ if (run.getColor() != null) {
|
|
|
+ // 注意:Word中的颜色格式与PDF中的颜色格式可能不同
|
|
|
+ // 这里简化处理,实际应用中可能需要转换颜色格式
|
|
|
+ }
|
|
|
+
|
|
|
+ return font;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
|
|
|
public void pushRd(OutWordRdDetails data, HttpServletResponse response,String uploadPath) {
|
|
|
String attName = data.getRdName()+new Date().getTime() + ".pdf";
|
|
|
@@ -68,6 +515,13 @@ public class PDFUtils {
|
|
|
document.add(Chunk.NEWLINE);
|
|
|
}
|
|
|
|
|
|
+ private static void addPDFDocument(Document document, String value) throws DocumentException {
|
|
|
+ Phrase phrase = new Phrase(value, getFont());
|
|
|
+ phrase.setLeading(40);
|
|
|
+ if(value!=null)document.add(phrase);
|
|
|
+ document.add(Chunk.NEWLINE);
|
|
|
+ }
|
|
|
+
|
|
|
private void addPDFContent(Document document, String value) throws DocumentException {
|
|
|
Phrase phrase = new Phrase(value, getFont());
|
|
|
phrase.setLeading(25);
|
|
|
@@ -163,4 +617,9 @@ public class PDFUtils {
|
|
|
document.add(tile2);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
}
|