package com.ruoyi.manage.util; import com.aspose.words.Document; import com.aspose.words.DocumentBuilder; import com.aspose.words.License; import com.aspose.words.SaveFormat; import com.ruoyi.framework.exception.ErrorException; import jakarta.servlet.http.HttpServletResponse; import org.springframework.core.io.ClassPathResource; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.OutputStream; /** * 体系文件附件预览工具:把附件统一以 PDF 流输出给前端预览/盖章。 * PDF 原样输出;Word、图片用 Aspose.Words 在线转 PDF;Excel/PPT 等无法转 PDF 的格式给出明确提示。 */ public final class DocumentPreviewUtils { private static final String[] WORD_EXT = {".doc", ".docx", ".rtf", ".txt", ".wps"}; private static final String[] IMAGE_EXT = {".png", ".jpg", ".jpeg", ".bmp", ".gif"}; private DocumentPreviewUtils() { } public static void writeAsPdf(File file, HttpServletResponse response) throws Exception { if (file == null || !file.exists()) { throw new ErrorException("附件不存在或已被删除"); } String name = file.getName().toLowerCase(); if (name.endsWith(".pdf")) { prepare(response, file.getName(), file.length()); try (InputStream in = new FileInputStream(file); OutputStream os = response.getOutputStream()) { in.transferTo(os); os.flush(); } return; } Document doc; if (endsWithAny(name, WORD_EXT)) { applyLicense(); doc = new Document(file.getPath()); } else if (endsWithAny(name, IMAGE_EXT)) { applyLicense(); doc = new Document(); new DocumentBuilder(doc).insertImage(file.getPath()); } else { throw new ErrorException("该文件格式不支持在线盖章预览,请上传 PDF 或 Word 文件"); } // 先转换到内存,转换失败时响应头还没提交,前端才能收到错误信息 ByteArrayOutputStream buffer = new ByteArrayOutputStream(); doc.save(buffer, SaveFormat.PDF); byte[] bytes = buffer.toByteArray(); prepare(response, file.getName() + ".pdf", bytes.length); try (OutputStream os = response.getOutputStream()) { os.write(bytes); os.flush(); } } private static void prepare(HttpServletResponse response, String fileName, long length) { response.setContentType("application/pdf"); response.setCharacterEncoding("UTF-8"); response.setHeader("Content-disposition", "inline;filename=" + fileName); response.setContentLength((int) length); } private static boolean endsWithAny(String name, String[] suffixes) { for (String suffix : suffixes) { if (name.endsWith(suffix)) { return true; } } return false; } private static void applyLicense() throws Exception { // 凭证,否则转换后带水印 try (InputStream is = new ClassPathResource("lib/license.xml").getInputStream()) { License license = new License(); license.setLicense(is); } } }