springboot word转pdf,springboot word

  springboot word转pdf,springboot word

  

目录

一。背景二。方案选择1.Spire.Doc for Java方案2.docx4j方案jodconverter图书馆办公室方案4.其他三。实操1 .docx4j 2。poi-TL jod转换器自由办公室方案四。结论1.docx4j方案jodconverter图书馆办公室方案

 

  

一.背景

项目中有个需求大体意思是,上传一个单词模板,根据单词模板合成单词文件,再将单词文件转为可移植文档格式文件的扩展名(portable document format的缩写)格式.

 

  

二.方案选择

 

  

1.Spire.Doc for Java方案

塔尖Java。文档这个是商用收费的,不过应用程序接口文档丰富且集成简单,免费版仅支持3页转换。类似的还有ITEXT,这个商用也是受限制的。

 

  

2.docx4j方案

开源可商用,仅支持文档格式的单词.

 

  

3.jodconverter+LibreOffice 方案

开源可商用,调用本地办公室服务,进行可移植文档格式文件的扩展名(可移植文档格式的缩写)转换,类似的还有jodconverter openOffice。

 

  

4.其他

至于其他的由于不支持跨平台不做考虑。

 

  

三.实操

 

  

1.docx4j

首先尝试了docx4j,因为docx4j本身支持模板替换的操作,可一次性做替换及文档类型转换,而且仅支持文档类型,对于本次需求问题不大。

 

  1.依赖仅需要一个即可

  相关性groupId组织。docx4j/groupId artifactIddocx4j-export-fo/artifactId版本6 .1 .0/版本/相关性2.主要代码

  @ SLF 4j公共类PdfUtil { public static T void exportByLocalPath(http servlet response response,String fileName,String path,MapString,String params){ try(InputStream in=PdfUtil。班级。getclass loader().getResourceAsStream(path)){ convertDocxToPdf(in,response,fileName,params);} catch(异常e) { log.error(docx文档转换为便携文档格式失败,e . getmessage());} } /** * docx文档转换为* @ param response * @ return */public static void convertDocxToPdf(InputStream in,HttpServletResponse响应,字符串文件名,映射字符串,字符串参数)抛出异常{回应。设置内容类型(“应用程序/PDF”);字符串完整文件名=新字符串(文件名。getbytes(),标准字符集.ISO _ 8859 _ 1);回应。设置标题(内容-处置,附件;文件名=完整文件名。pdf’);WordprocessingMLPackage wml package=WordprocessingMLPackage。负载(英寸);if (params!=null!参数。isempty()){ MainDocumentPart文档部分=

   wmlPackage.getMainDocumentPart(); cleanDocumentPart(documentPart); documentPart.variableReplace(params); } setFontMapper(wmlPackage); Docx4J.toPDF(wmlPackage,response.getOutputStream()); } /** * 清除文档空白占位符 * @param documentPart * @return {@link boolean} */ public static boolean cleanDocumentPart(MainDocumentPart documentPart) throws Exception { if (documentPart == null) { return false; } Document document = documentPart.getContents(); String wmlTemplate = XmlUtils.marshaltoString(document, true, false, Context.jc); document = (Document) XmlUtils.unwrap(DocxVariableClearUtil.doCleanDocumentPart(wmlTemplate, Context.jc)); documentPart.setContents(document); return true; } /** * 设置字体样式 * @param mlPackage */ private static void setFontMapper(WordprocessingMLPackage mlPackage) throws Exception { Mapper fontMapper = new IdentityPlusMapper(); fontMapper.put("隶书", PhysicalFonts.get("LiSu")); fontMapper.put("宋体", PhysicalFonts.get("SimSun")); fontMapper.put("微软雅黑", PhysicalFonts.get("Microsoft Yahei")); fontMapper.put("黑体", PhysicalFonts.get("SimHei")); fontMapper.put("楷体", PhysicalFonts.get("KaiTi")); fontMapper.put("新宋体", PhysicalFonts.get("NSimSun")); fontMapper.put("华文行楷", PhysicalFonts.get("STXingkai")); fontMapper.put("华文仿宋", PhysicalFonts.get("STFangsong")); fontMapper.put("宋体扩展", PhysicalFonts.get("simsun-extB")); fontMapper.put("仿宋", PhysicalFonts.get("FangSong")); fontMapper.put("仿宋_GB2312", PhysicalFonts.get("FangSong_GB2312")); fontMapper.put("幼圆", PhysicalFonts.get("YouYuan")); fontMapper.put("华文宋体", PhysicalFonts.get("STSong")); fontMapper.put("华文中宋", PhysicalFonts.get("STZhongsong")); mlPackage.setFontMapper(fontMapper); }}清除工具类,用于处理占位符替换不生效的问题,这里参考文章

  

public class DocxVariableClearUtil { /** * 去任意XML标签 */ private static final Pattern XML_PATTERN = Pattern.compile("<[^>]*>"); private DocxVariableClearUtil() { } /** * start符号 */ private static final char PREFIX = $; /** * 中包含 */ private static final char LEFT_BRACE = {; /** * 结尾 */ private static final char RIGHT_BRACE = }; /** * 未开始 */ private static final int NONE_START = -1; /** * 未开始 */ private static final int NONE_START_INDEX = -1; /** * 开始 */ private static final int PREFIX_STATUS = 1; /** * 左括号 */ private static final int LEFT_BRACE_STATUS = 2; /** * 右括号 */ private static final int RIGHT_BRACE_STATUS = 3; /** * doCleanDocumentPart * * @param wmlTemplate * @param jc * @return * @throws JAXBException */ public static Object doCleanDocumentPart(String wmlTemplate, JAXBContext jc) throws JAXBException { // 进入变量块位置 int curStatus = NONE_START; // 开始位置 int keyStartIndex = NONE_START_INDEX; // 当前位置 int curIndex = 0; char[] textCharacters = wmlTemplate.toCharArray(); StringBuilder documentBuilder = new StringBuilder(textCharacters.length); documentBuilder.append(textCharacters); // 新文档 StringBuilder newDocumentBuilder = new StringBuilder(textCharacters.length); // 最后一次写位置 int lastWriteIndex = 0; for (char c : textCharacters) { switch (c) { case PREFIX: // 不管其何状态直接修改指针,这也意味着变量名称里面不能有PREFIX keyStartIndex = curIndex; curStatus = PREFIX_STATUS; break; case LEFT_BRACE: if (curStatus == PREFIX_STATUS) { curStatus = LEFT_BRACE_STATUS; } break; case RIGHT_BRACE: if (curStatus == LEFT_BRACE_STATUS) { // 接上之前的字符 newDocumentBuilder.append(documentBuilder.substring(lastWriteIndex, keyStartIndex)); // 结束位置 int keyEndIndex = curIndex + 1; // 替换 String rawKey = documentBuilder.substring(keyStartIndex, keyEndIndex); // 干掉多余标签 String mappingKey = XML_PATTERN.matcher(rawKey).replaceAll(""); if (!mappingKey.equals(rawKey)) { char[] rawKeyChars = rawKey.toCharArray(); // 保留原格式 StringBuilder rawStringBuilder = new StringBuilder(rawKey.length()); // 去掉变量引用字符 for (char rawChar : rawKeyChars) { if (rawChar == PREFIX rawChar == LEFT_BRACE rawChar == RIGHT_BRACE) { continue; } rawStringBuilder.append(rawChar); } // 要求变量连在一起 String variable = mappingKey.substring(2, mappingKey.length() - 1); int variableStart = rawStringBuilder.indexOf(variable); if (variableStart > 0) { rawStringBuilder = rawStringBuilder.replace(variableStart, variableStart + variable.length(), mappingKey); } newDocumentBuilder.append(rawStringBuilder.toString()); } else { newDocumentBuilder.append(mappingKey); } lastWriteIndex = keyEndIndex; curStatus = NONE_START; keyStartIndex = NONE_START_INDEX; } default: break; } curIndex++; } // 余部 if (lastWriteIndex < documentBuilder.length()) { newDocumentBuilder.append(documentBuilder.substring(lastWriteIndex)); } return XmlUtils.unmarshalString(newDocumentBuilder.toString(), jc); }}

 

  

2.poi-tl+jodconverter+LibreOffice 方案

poi-tl这个是专门用来进行word模板合成的开源库,文档很详细。

 

  LibreOffice 下载最新的稳定版本即可。

  1.maven依赖

  

<!-- word合成 --><!-- 这里注意版本,1.5版本依赖的poi 3.x的版本 --><dependency><groupId>com.deepoove</groupId><artifactId>poi-tl</artifactId><version>1.5.1</version></dependency><!-- jodconverter word转pdf --><!-- jodconverter-core这个依赖,理论上不用加的,jodconverter-local已经依赖了,但测试的时候不添加依赖找不到 --><dependency><groupId>org.jodconverter</groupId><artifactId>jodconverter-core</artifactId><version>4.2.0</version></dependency><dependency><groupId>org.jodconverter</groupId><artifactId>jodconverter-local</artifactId><version>4.2.0</version></dependency><dependency><groupId>org.jodconverter</groupId><artifactId>jodconverter-spring-boot-starter</artifactId><version>4.2.0</version></dependency><!-- 工具类,非必须 --><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.4.3</version></dependency>

2.主要代码

 

  JodConverterConfig配置类

  

@Configurationpublic class JodConverterConfig { @Autowired private OfficeManager officeManager; @Bean public DocumentConverter documentConverter() { return LocalConverter.builder() .officeManager(officeManager) .build(); }}

yml配置文件

 

  

jodconverter: local: enabled: true office-home: "C:\Program Files\LibreOffice"

PdfService合成导出代码

 

  

@Slf4j@Componentpublic class PdfService { @Autowired private DocumentConverter documentConverter; public void docxToPDF(InputStream inputStream,HttpServletResponse response,String fileName) { response.setContentType("application/pdf"); try { String fullFileName = new String(fileName.getBytes(), StandardCharsets.ISO_8859_1); response.setHeader("Content-disposition","attachment;filename=\"+fullFileName+".pdf\"); documentConverter .convert(inputStream) .as(DefaultDocumentFormatRegistry.DOCX) .to(response.getOutputStream()) .as(DefaultDocumentFormatRegistry.PDF) .execute(); } catch (OfficeException IOException e) { log.error("word转pdf失败:{}",e.getMessage()); } } public void exportByLocalPath(HttpServletResponse response, String fileName, String path, Object params) throws Exception { BufferedOutputStream outputStream = null; BufferedInputStream wordInputStream = null; try (InputStream in = PdfService.class.getClassLoader().getResourceAsStream(path)) { // 生成临时文件 String outPutWordPath = System.getProperty("java.io.tmpdir").replaceAll(File.separator + "$", "") + fileName+".docx"; File tempFile = FileUtil.touch(outPutWordPath); outputStream = FileUtil.getOutputStream(tempFile); // word模板合成写到临时文件 WordUtil.replaceWord(outputStream, in, params); // word 转pdf wordInputStream = FileUtil.getInputStream(tempFile); docxToPDF(wordInputStream, response,fileName); // 移除临时文件 FileUtil.del(tempFile); } catch (Exception e) { log.error("docx文档转换为PDF失败", e.getMessage()); } finally { IoUtil.close(outputStream); IoUtil.close(wordInputStream); } }

 

  

四.结论

 

  

1.docx4j方案

依赖少同时支持word合成及格式转换转化效率较差对于含样式及图片转换不友好,容易排版混乱

 

  

2.jodconverter+LibreOffice 方案

操作稳定转换效率快集成依赖设置较多依赖本地服务LibreOffice打开word可能排版样式错乱最后考虑项目需求,最终选择了jodconverter+LibreOffice方案。以上为个人经验,希望能给大家一个参考,也希望大家多多支持盛行IT。

 

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: