PDFUtils.java 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. package com.goafanti.common.utils.pdf;
  2. import com.goafanti.RD.bo.OutWordRdDetails;
  3. import com.goafanti.common.constant.AFTConstants;
  4. import com.goafanti.common.utils.DateUtils;
  5. import com.goafanti.common.utils.excel.FileUtils;
  6. import com.goafanti.expenseAccount.bo.MainExpenseAccount;
  7. import com.itextpdf.text.Document;
  8. import com.itextpdf.text.Font;
  9. import com.itextpdf.text.*;
  10. import com.itextpdf.text.pdf.BaseFont;
  11. import com.itextpdf.text.pdf.PdfPCell;
  12. import com.itextpdf.text.pdf.PdfPTable;
  13. import com.itextpdf.text.pdf.PdfWriter;
  14. import org.apache.poi.ss.usermodel.*;
  15. import org.apache.poi.xssf.usermodel.XSSFWorkbook;
  16. import org.apache.poi.xwpf.usermodel.*;
  17. import org.springframework.http.MediaType;
  18. import javax.servlet.http.HttpServletResponse;
  19. import java.io.*;
  20. import java.util.Date;
  21. public class PDFUtils {
  22. /**
  23. * 删除临时目录及其内容
  24. *
  25. * @param dir 临时目录
  26. */
  27. private static void deleteTempDirectory(File dir) {
  28. if (dir.exists() && dir.isDirectory()) {
  29. File[] files = dir.listFiles();
  30. if (files != null) {
  31. for (File file : files) {
  32. if (file.isDirectory()) {
  33. deleteTempDirectory(file);
  34. } else {
  35. file.delete();
  36. }
  37. }
  38. }
  39. dir.delete();
  40. }
  41. }
  42. /**
  43. * 将Word文档转换为PDF文件
  44. *
  45. * @param wordFilePath Word文件路径
  46. * @param pdfFilePath 生成的PDF文件路径
  47. * @throws IOException
  48. * @throws DocumentException
  49. */
  50. public static void convertWordToPDF(String wordFilePath, String pdfFilePath)
  51. throws IOException, DocumentException {
  52. Document document = new Document(PageSize.A4);
  53. try (InputStream in = new FileInputStream(wordFilePath)) {
  54. // 创建PDF写入器
  55. FileOutputStream outputStream = new FileOutputStream(pdfFilePath);
  56. PdfWriter.getInstance(document, outputStream);
  57. document.open();
  58. // 处理Word文档内容
  59. processWordDocument(wordFilePath, document);
  60. document.close();
  61. outputStream.close();
  62. }
  63. }
  64. /**
  65. * 将XLSX文件转换为PDF文件
  66. *
  67. * @param xlsxFilePath XLSX文件路径
  68. * @param pdfFilePath 生成的PDF文件路径
  69. * @throws IOException
  70. * @throws DocumentException
  71. */
  72. public static void convertXlsxToPDF(String xlsxFilePath, String pdfFilePath)
  73. throws IOException, DocumentException {
  74. Document document = new Document(PageSize.A4.rotate()); // 使用横向页面以适应更多列
  75. try (InputStream in = new FileInputStream(xlsxFilePath)) {
  76. Workbook workbook = new XSSFWorkbook(in);
  77. // 创建PDF写入器
  78. FileOutputStream outputStream = new FileOutputStream(pdfFilePath);
  79. PdfWriter.getInstance(document, outputStream);
  80. document.open();
  81. // 处理Excel工作簿内容
  82. processExcelWorkbook(workbook, document);
  83. document.close();
  84. outputStream.close();
  85. workbook.close();
  86. }
  87. }
  88. /**
  89. * 将Word文档转换为PDF并提供下载
  90. *
  91. * @param wordFilePath Word文件路径
  92. * @param response HttpServletResponse对象
  93. * @param pdfFileName 生成的PDF文件名
  94. * @param uploadPath 上传路径
  95. * @throws IOException
  96. * @throws DocumentException
  97. */
  98. public static void convertWordToPDFForDownload(String wordFilePath,
  99. HttpServletResponse response,
  100. String pdfFileName,
  101. String uploadPath)
  102. throws IOException, DocumentException {
  103. String realFileName = uploadPath + "/tmp/" + System.currentTimeMillis() + ".pdf";
  104. Document document = new Document(PageSize.A4);
  105. try (InputStream in = new FileInputStream(wordFilePath)) {
  106. // 设置响应头,用于文件下载
  107. FileUtils.setAttachmentResponseHeader(response, pdfFileName, pdfFileName + ".pdf");
  108. // 创建PDF写入器
  109. FileOutputStream outputStream = new FileOutputStream(realFileName);
  110. PdfWriter.getInstance(document, outputStream);
  111. document.open();
  112. // 处理Word文档内容
  113. processWordDocument(wordFilePath, document);
  114. document.close();
  115. outputStream.close();
  116. // 提供文件下载
  117. FileUtils.writeBytes(realFileName, response.getOutputStream());
  118. FileUtils.deleteFile(realFileName);
  119. }
  120. }
  121. /**
  122. * 处理Word文档并将其内容添加到PDF文档中
  123. *
  124. * @param wordFilePath Word文件路径
  125. * @param document PDF文档对象
  126. * @throws IOException
  127. * @throws DocumentException
  128. */
  129. private static void processWordDocument(String wordFilePath, Document document)
  130. throws IOException, DocumentException {
  131. try (InputStream in = new FileInputStream(wordFilePath)) {
  132. XWPFDocument xwpfDocument = new XWPFDocument(in);
  133. // 获取文档中的所有段落
  134. java.util.List<XWPFParagraph> paragraphs = xwpfDocument.getParagraphs();
  135. for (XWPFParagraph paragraph : paragraphs) {
  136. // 创建PDF段落
  137. Paragraph pdfParagraph = new Paragraph();
  138. paragraph.getRuns().forEach(run -> {
  139. System.out.println(run.getPictureText());
  140. System.out.println(run.getFontSize());
  141. });
  142. // 设置段落对齐方式
  143. switch (paragraph.getAlignment()) {
  144. case CENTER:
  145. pdfParagraph.setAlignment(Element.ALIGN_CENTER);
  146. break;
  147. case RIGHT:
  148. pdfParagraph.setAlignment(Element.ALIGN_RIGHT);
  149. break;
  150. case LEFT:
  151. case BOTH:
  152. default:
  153. pdfParagraph.setAlignment(Element.ALIGN_LEFT);
  154. break;
  155. }
  156. // 处理段落中的所有文本块(XWPFRun)
  157. for (XWPFRun run : paragraph.getRuns()) {
  158. String text = run.getText(0);
  159. if (text != null) {
  160. // 创建带样式的PDF字体
  161. Font pdfFont = createPDFFontFromRun(run);
  162. Chunk chunk = new Chunk(text, pdfFont);
  163. pdfParagraph.add(chunk);
  164. }
  165. }
  166. // 只有当段落有内容时才添加到文档中
  167. if (pdfParagraph.size() > 0 && !pdfParagraph.getContent().toString().trim().isEmpty()) {
  168. document.add(pdfParagraph);
  169. }
  170. }
  171. // 处理表格(如果有)
  172. java.util.List<XWPFTable> tables = xwpfDocument.getTables();
  173. for (XWPFTable table : tables) {
  174. // 处理表格中的每一行
  175. java.util.List<XWPFTableRow> rows = table.getRows();
  176. for (XWPFTableRow row : rows) {
  177. StringBuilder rowText = new StringBuilder();
  178. java.util.List<XWPFTableCell> cells = row.getTableCells();
  179. for (XWPFTableCell cell : cells) {
  180. String cellText = cell.getText();
  181. rowText.append(cellText).append(" | ");
  182. }
  183. if (rowText.length() > 0) {
  184. document.add(new Paragraph(rowText.toString()));
  185. }
  186. }
  187. }
  188. }
  189. }
  190. /**
  191. * 处理Excel工作簿并将其内容添加到PDF文档中
  192. *
  193. * @param workbook Excel工作簿对象
  194. * @param document PDF文档对象
  195. * @throws DocumentException
  196. */
  197. private static void processExcelWorkbook(Workbook workbook, Document document)
  198. throws DocumentException {
  199. // 添加文档标题(文件名)
  200. document.add(new Paragraph("Excel文档转换", PDFUtils.getTitleFont()));
  201. document.add(Chunk.NEWLINE);
  202. // 处理每个工作表
  203. for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
  204. Sheet sheet = workbook.getSheetAt(i);
  205. // 添加工作表名称
  206. Paragraph sheetTitle = new Paragraph("工作表: " + sheet.getSheetName(), PDFUtils.getBigFont());
  207. document.add(sheetTitle);
  208. document.add(Chunk.NEWLINE);
  209. // 计算需要的列数
  210. int columnCount = 0;
  211. for (Row row : sheet) {
  212. int lastCellNum = row.getLastCellNum();
  213. if (lastCellNum > columnCount) {
  214. columnCount = lastCellNum;
  215. }
  216. }
  217. if (columnCount > 0) {
  218. // 创建表格
  219. PdfPTable table = new PdfPTable(columnCount);
  220. table.setWidthPercentage(100);
  221. float[] columnWidths = new float[columnCount];
  222. for (int j = 0; j < columnCount; j++) {
  223. columnWidths[j] = 1f;
  224. }
  225. table.setWidths(columnWidths);
  226. // 处理行数据
  227. int rowCount = 0;
  228. for (Row row : sheet) {
  229. // 处理每行的单元格
  230. for (int colIndex = 0; colIndex < columnCount; colIndex++) {
  231. Cell cell = row.getCell(colIndex);
  232. String cellValue = getCellValue(cell);
  233. PdfPCell pdfCell = new PdfPCell(new Phrase(cellValue, PDFUtils.getFont()));
  234. pdfCell.setPadding(3);
  235. // 设置表头样式
  236. if (rowCount == 0) {
  237. pdfCell.setBackgroundColor(BaseColor.LIGHT_GRAY);
  238. pdfCell.setHorizontalAlignment(Element.ALIGN_CENTER);
  239. }
  240. table.addCell(pdfCell);
  241. }
  242. rowCount++;
  243. // 限制处理的行数,避免内容过多
  244. if (rowCount > 100) {
  245. PdfPCell pdfCell = new PdfPCell(new Phrase("... (内容过多,省略剩余部分)", PDFUtils.getFont()));
  246. pdfCell.setColspan(columnCount);
  247. pdfCell.setHorizontalAlignment(Element.ALIGN_CENTER);
  248. table.addCell(pdfCell);
  249. break;
  250. }
  251. }
  252. document.add(table);
  253. }
  254. document.add(Chunk.NEWLINE);
  255. }
  256. }
  257. /**
  258. * 获取单元格的值
  259. *
  260. * @param cell Excel单元格
  261. * @return 单元格内容字符串
  262. */
  263. private static String getCellValue(Cell cell) {
  264. if (cell == null) {
  265. return "";
  266. }
  267. switch (cell.getCellType()) {
  268. case Cell.CELL_TYPE_STRING:
  269. return cell.getStringCellValue();
  270. case Cell.CELL_TYPE_NUMERIC:
  271. if (DateUtil.isCellDateFormatted(cell)) {
  272. return cell.getDateCellValue().toString();
  273. } else {
  274. // 避免科学计数法显示数字
  275. return String.valueOf(cell.getNumericCellValue());
  276. }
  277. case Cell.CELL_TYPE_BOOLEAN:
  278. return String.valueOf(cell.getBooleanCellValue());
  279. case Cell.CELL_TYPE_FORMULA:
  280. return cell.getCellFormula();
  281. default:
  282. return "";
  283. }
  284. }
  285. /**
  286. * 根据Word文档中的Run样式创建PDF字体
  287. *
  288. * @param run Word文档中的文本块
  289. * @return PDF字体
  290. */
  291. private static Font createPDFFontFromRun(XWPFRun run) {
  292. // 获取字体大小,默认为12
  293. int fontSize = 12;
  294. if (run.getFontSize() != -1) {
  295. fontSize = run.getFontSize();
  296. }
  297. // 设置字体样式
  298. int fontStyle = Font.NORMAL;
  299. if (run.isBold() && run.isItalic()) {
  300. fontStyle = Font.BOLDITALIC;
  301. } else if (run.isBold()) {
  302. fontStyle = Font.BOLD;
  303. } else if (run.isItalic()) {
  304. fontStyle = Font.ITALIC;
  305. }
  306. // 创建字体
  307. Font font = PDFUtils.getFont(fontSize);
  308. font.setStyle(fontStyle);
  309. // 处理字体颜色
  310. if (run.getColor() != null) {
  311. // 注意:Word中的颜色格式与PDF中的颜色格式可能不同
  312. // 这里简化处理,实际应用中可能需要转换颜色格式
  313. }
  314. return font;
  315. }
  316. public void pushRd(OutWordRdDetails data, HttpServletResponse response,String uploadPath) {
  317. String attName = data.getRdName()+new Date().getTime() + ".pdf";
  318. String realFileName = uploadPath+"/tmp/"+new Date().getTime() + ".pdf";
  319. response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
  320. Document document=new Document();
  321. try {
  322. FileUtils.setAttachmentResponseHeader(response, data.getRdName(),attName);
  323. FileOutputStream outputStream = new FileOutputStream(realFileName);
  324. PdfWriter.getInstance(document, outputStream);
  325. document.open();
  326. Paragraph paragraph = new Paragraph(data.getRdName(), getTitleFont());
  327. paragraph.setAlignment(1);
  328. document.add(paragraph);
  329. addPDFDocument(document,"项目起止时间: ",data.getStartEndTime());
  330. addPDFDocument(document,"公司名称: ",data.getUserName());
  331. addPDFDocument(document,"项目负责人: ",data.getConsultantName());
  332. addPDFDocument(document,"技术领域: ",data.getTechnicalField());
  333. addPDFDocument(document,"技术来源: ",data.getTechnologySource());
  334. addPDFDocument(document,"研发费用总预计: ",data.getTotalAmount().toEngineeringString()+" 万元");
  335. addPDFDocument(document,"研发目的/立项目的/实施方式",null);
  336. addPDFContent(document," "+data.getRdObjective());
  337. addPDFDocument(document,"核心技术/创新点",null);
  338. addPDFContent(document," "+data.getCoreTechnology());
  339. addPDFDocument(document,"成果",null);
  340. addPDFContent(document," "+data.getAchieveResults());
  341. document.close();
  342. outputStream.close();
  343. FileUtils.writeBytes(realFileName, response.getOutputStream());
  344. FileUtils.deleteFile(realFileName);
  345. } catch (DocumentException e) {
  346. e.printStackTrace();
  347. } catch (FileNotFoundException e) {
  348. e.printStackTrace();
  349. } catch (IOException e) {
  350. e.printStackTrace();
  351. }
  352. }
  353. private void addPDFDocument(Document document, String key, String value) throws DocumentException {
  354. if(key!=null) {
  355. document.add(new Chunk(key, getBigFont()));
  356. }
  357. Phrase phrase = new Phrase(value, getFont());
  358. phrase.setLeading(40);
  359. if(value!=null)document.add(phrase);
  360. document.add(Chunk.NEWLINE);
  361. }
  362. private static void addPDFDocument(Document document, String value) throws DocumentException {
  363. Phrase phrase = new Phrase(value, getFont());
  364. phrase.setLeading(40);
  365. if(value!=null)document.add(phrase);
  366. document.add(Chunk.NEWLINE);
  367. }
  368. private void addPDFContent(Document document, String value) throws DocumentException {
  369. Phrase phrase = new Phrase(value, getFont());
  370. phrase.setLeading(25);
  371. if(value!=null)document.add(phrase);
  372. document.add(Chunk.NEWLINE);
  373. document.add(Chunk.NEWLINE);
  374. }
  375. public static Font getTitleFont(){
  376. return setFont(24,Font.NORMAL);
  377. }
  378. public static Font getBigFont(){
  379. return setFont(16,Font.NORMAL);
  380. }
  381. public static Font getFont(){
  382. Font font =setFont(12,Font.NORMAL);
  383. return font;
  384. }
  385. public static Font getFont(int size){
  386. Font font =setFont(size,Font.NORMAL);
  387. return font;
  388. }
  389. /**
  390. *
  391. * @param size 大小
  392. * @return
  393. */
  394. public static Font setFont(Integer size,Integer style){
  395. BaseFont baseFont = null;
  396. Font font=null;
  397. try {
  398. baseFont=BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
  399. font=new Font(baseFont,size,style);
  400. } catch (DocumentException e) {
  401. e.printStackTrace();
  402. } catch (IOException e) {
  403. e.printStackTrace();
  404. }
  405. return font;
  406. }
  407. private static String CHECKNO="报销编号:";
  408. private static String APPLYDEP="申请部门:";
  409. private static String ANAME="报销人:";
  410. private static String CREATETIME="报销日期:";
  411. private static String REMARKS="报销事由:";
  412. private static String BANK_ACCOUNT="收款方式:";
  413. private static String BLANK=" ";
  414. public static void pushExpenseTitle(Document document, MainExpenseAccount mainExpenseAccount) throws DocumentException {
  415. StringBuilder builder = new StringBuilder();
  416. builder.append(CHECKNO).append(mainExpenseAccount.getCheckNo()).append(BLANK)
  417. .append(APPLYDEP).append(mainExpenseAccount.getApplyDepName()).append(BLANK).append(BLANK).append(BLANK)
  418. .append(ANAME).append(mainExpenseAccount.getAname());
  419. Paragraph tile1=new Paragraph(builder.toString(),getFont(8));
  420. document.add(tile1);
  421. String creactTime= DateUtils.formatDate(mainExpenseAccount.getCreateTime(), AFTConstants.YYYYMMDD);
  422. int x2 = CREATETIME.length() + creactTime.length()/2 +
  423. REMARKS.length() + mainExpenseAccount.getRemarks().length() +
  424. BANK_ACCOUNT.length() + mainExpenseAccount.getBank().length() +
  425. mainExpenseAccount.getAccounts().length()/2 + mainExpenseAccount.getName().length();
  426. builder.setLength(0);
  427. if (x2>55){
  428. builder.append(CREATETIME).append(creactTime).append(BLANK)
  429. .append(REMARKS).append(mainExpenseAccount.getRemarks()).append(BLANK)
  430. .append(BANK_ACCOUNT).append(mainExpenseAccount.getBank()).append(BLANK)
  431. .append(mainExpenseAccount.getAccounts()).append(BLANK)
  432. .append(mainExpenseAccount.getName());
  433. }else {
  434. int y =(60-x2)*2;
  435. StringBuilder blank= new StringBuilder();
  436. for (int i = 0; i < y; i++) {
  437. blank.append(" ");
  438. }
  439. builder.append(CREATETIME).append(creactTime).append(blank)
  440. .append(REMARKS).append(mainExpenseAccount.getRemarks()).append(blank)
  441. .append(BANK_ACCOUNT).append(mainExpenseAccount.getBank()).append(BLANK)
  442. .append(mainExpenseAccount.getAccounts()).append(BLANK)
  443. .append(mainExpenseAccount.getName());
  444. }
  445. Paragraph tile2=new Paragraph(builder.toString(),getFont(8));
  446. document.add(tile2);
  447. }
  448. }