SpringBoot项目里,用户上传Word/PPT/PDF文件后,如何用Apache POI和iText准确获取总页数?(附完整工具类)

张开发
2026/4/11 3:07:21 15 分钟阅读

分享文章

SpringBoot项目里,用户上传Word/PPT/PDF文件后,如何用Apache POI和iText准确获取总页数?(附完整工具类)
SpringBoot实战用Apache POI和iText精准获取Word/PPT/PDF页数的完整方案在文档管理系统、在线打印服务等企业级应用中准确获取用户上传文档的总页数是一个高频需求。无论是按页计费、内容预览分页还是打印任务分配都需要后端快速解析不同格式的文档。本文将深入探讨如何在SpringBoot项目中通过Apache POI和iText库实现这一功能并提供一个经过生产验证的完整工具类。1. 环境准备与基础配置在开始编码前我们需要配置好SpringBoot项目的基础环境。首先在pom.xml中添加必要的依赖dependencies !-- iText for PDF processing -- dependency groupIdcom.itextpdf/groupId artifactIditextpdf/artifactId version5.5.13.3/version /dependency !-- Apache POI for Office documents -- dependency groupIdorg.apache.poi/groupId artifactIdpoi/artifactId version5.2.3/version /dependency dependency groupIdorg.apache.poi/groupId artifactIdpoi-ooxml/artifactId version5.2.3/version /dependency dependency groupIdorg.apache.poi/groupId artifactIdpoi-scratchpad/artifactId version5.2.3/version /dependency /dependenciesSpringBoot默认的文件上传大小限制为1MB对于文档处理来说通常不够。我们需要在application.yml中调整配置spring: servlet: multipart: max-file-size: 50MB max-request-size: 50MB enabled: true提示实际项目中应根据业务需求合理设置大小限制过大的限制可能导致内存问题。2. 文件上传与类型识别SpringBoot通过MultipartFile接收上传文件我们需要先正确处理文件上传并识别文件类型PostMapping(/upload) public ResponseEntity? handleFileUpload(RequestParam(file) MultipartFile file) { try { // 获取原始文件名和后缀 String originalFilename file.getOriginalFilename(); String fileExtension originalFilename.substring(originalFilename.lastIndexOf(.)); // 验证文件类型 if (!isSupportedFileType(fileExtension)) { return ResponseEntity.badRequest().body(不支持的文件类型); } // 获取页数 int pageCount FilePageCounter.getPageCount(file.getInputStream(), fileExtension); return ResponseEntity.ok(Map.of( filename, originalFilename, pageCount, pageCount )); } catch (Exception e) { return ResponseEntity.internalServerError().body(文件处理失败: e.getMessage()); } } private boolean isSupportedFileType(String extension) { return extension.equalsIgnoreCase(.doc) || extension.equalsIgnoreCase(.docx) || extension.equalsIgnoreCase(.ppt) || extension.equalsIgnoreCase(.pptx) || extension.equalsIgnoreCase(.pdf); }3. 核心工具类实现下面是我们精心设计的FilePageCounter工具类它封装了各种文档格式的页数获取逻辑import org.apache.poi.hslf.usermodel.HSLFSlideShow; import org.apache.poi.hwpf.extractor.WordExtractor; import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.xslf.usermodel.XMLSlideShow; import org.apache.poi.xwpf.usermodel.XWPFDocument; import com.itextpdf.text.pdf.PdfReader; import org.apache.poi.util.ZipSecureFile; import java.io.InputStream; public class FilePageCounter { static { // 防止POI处理压缩文件时的安全限制 ZipSecureFile.setMinInflateRatio(0); } public static int getPageCount(InputStream inputStream, String fileExtension) throws Exception { switch (fileExtension.toLowerCase()) { case .pdf: return getPdfPageCount(inputStream); case .doc: return getDocPageCount(inputStream); case .docx: return getDocxPageCount(inputStream); case .ppt: return getPptPageCount(inputStream); case .pptx: return getPptxPageCount(inputStream); default: throw new IllegalArgumentException(不支持的文件类型: fileExtension); } } private static int getPdfPageCount(InputStream inputStream) throws Exception { PdfReader reader null; try { reader new PdfReader(inputStream); return reader.getNumberOfPages(); } finally { if (reader ! null) { reader.close(); } } } private static int getDocPageCount(InputStream inputStream) throws Exception { WordExtractor extractor null; try { extractor new WordExtractor(inputStream); return extractor.getSummaryInformation().getPageCount(); } finally { if (extractor ! null) { extractor.close(); } } } private static int getDocxPageCount(InputStream inputStream) throws Exception { XWPFDocument document null; try { document new XWPFDocument(inputStream); return document.getProperties().getExtendedProperties() .getUnderlyingProperties().getPages(); } finally { if (document ! null) { document.close(); } } } private static int getPptPageCount(InputStream inputStream) throws Exception { HSLFSlideShow slideShow null; try { slideShow new HSLFSlideShow(inputStream); return slideShow.getSlides().size(); } finally { if (slideShow ! null) { slideShow.close(); } } } private static int getPptxPageCount(InputStream inputStream) throws Exception { XMLSlideShow slideShow null; try { slideShow new XMLSlideShow(inputStream); return slideShow.getSlides().size(); } finally { if (slideShow ! null) { slideShow.close(); } } } }4. 性能优化与异常处理在实际生产环境中我们需要考虑以下几个关键点来提升稳定性和性能资源释放确保所有打开的流和文档对象都被正确关闭内存管理处理大文件时避免内存溢出异常处理提供有意义的错误信息4.1 大文件处理策略对于大文件我们可以采用更高效的处理方式// 对于PDF文件使用部分读取模式 private static int getLargePdfPageCount(InputStream inputStream) throws Exception { PdfReader reader null; try { reader new PdfReader(inputStream); reader.setPartialReadMode(true); // 启用部分读取 return reader.getNumberOfPages(); } finally { if (reader ! null) { reader.close(); } } }4.2 常见问题与解决方案问题现象可能原因解决方案POI报错Zip bomb detected文件压缩率过高触发安全限制设置ZipSecureFile.setMinInflateRatio(0)获取的页数为0文档未正确设置页数属性对于Word文档尝试解析内容估算页数内存溢出文件过大使用部分读取模式或增加JVM内存文件损坏上传的文件不完整添加文件头验证逻辑5. 高级应用场景5.1 批量处理与异步任务对于需要处理大量文档的系统我们可以结合Spring的异步功能Service public class DocumentProcessingService { Async public CompletableFutureInteger processDocumentAsync(MultipartFile file) { try { String filename file.getOriginalFilename(); String extension filename.substring(filename.lastIndexOf(.)); int pageCount FilePageCounter.getPageCount(file.getInputStream(), extension); return CompletableFuture.completedFuture(pageCount); } catch (Exception e) { throw new RuntimeException(文档处理失败, e); } } }5.2 与云存储集成当文档存储在云服务(如AWS S3)时我们可以直接从云存储获取流进行处理public int getPageCountFromS3(String bucketName, String objectKey) throws Exception { S3Object s3Object s3Client.getObject(bucketName, objectKey); try (InputStream inputStream s3Object.getObjectContent()) { String extension objectKey.substring(objectKey.lastIndexOf(.)); return FilePageCounter.getPageCount(inputStream, extension); } }在实际项目中我们还需要考虑文档安全性验证、病毒扫描等额外需求。这个工具类已经过多个生产项目验证能够稳定处理各种常见文档格式。根据具体业务需求你可以进一步扩展其功能比如添加对Excel文件的支持或集成更高级的文档分析功能。

更多文章