导出包含富文本内容和图片的word和pdf

news/2025/2/21 1:42:25/

这里主要提到是需要注意的几个地方,适合已经研究过使用过freemarker+xml方式导出word的伙伴们,在此基础上应该一看就明白。若看不懂请自行查找导出word的资料,资料很多,这里主要是记录下导出包含富文本内容和图片的方式,以便后续自查。

需求是需要按照特定模板导出word,其中有些功能模块的内容是使用ckeditor编辑器填写的,这就涉及到了导出时要兼容富文本所包含的html标签,
这里多说两句:有两种情况
一、导出内容不包含富文本内容和富文本中增加的图片的情况,大体使用freemarker+xml方式,制作模板步骤:用office的word(据说WPS做得模板不可用,未亲测)做导出模板–>另存为xml格式文件—>再直接改后缀名为ftl放入项目中。我是先用的freemarker+xml方式导出word,发现解析不了html,又改用的freemarker+mht方式。因为他解析不了html代码,所以导出富文本内容没有合格结构是乱的,图片也无法显示
在这里插入图片描述
二、导出内容包含富文本和图片,大体使用freemarker+mht方式,制作模板步骤:用office的word(据说WPS做得模板不可用,未亲测)做导出模板–>另存为mht格式文件—>再直接改后缀名为ftl放入项目中
下面我们着重介绍下第二中情况:

本人做的时候也是网上各种查资料,特此感谢两篇文章大家也可以看下 文章一 文章二
特别感谢其中一位博主,还提供了源码包,放入项目中只需要根据项目实际情况调整下图片路径和导出word方式即可。

  • 1、做模板

首先第一步是制作模板,模板步骤见上面,制作模板时也可以不用占位符使用常量占位,到程序中知道显示位置再改成${} 占位符也是一样的。使用1111或者aaa的常量,个人感觉模板排查起来要方便些
在这里插入图片描述

  • 2.处理mht文件

打开我们的mht文件并处理,我使用EditPlus查看编码,很多编辑器都可以打开看代码,需要注意的是,模板生成时有时占位符${content!’’}有可能会被word自身的标签截断,因为mht文件有时候会自动换行,会在单词中间加上= 号 或者在{ 等符号与单词之间加上一些mht文件的样式,我们都要删掉,不删掉可能会造成模板异常,

  • 2.1在模板中找到下面截图中的代码

在这里插入图片描述
${imagesBase64String} 和 ${imagesXmlHrefString}这两个占位符是我们手动加进去的,简析富文本图片的核心就在这里,按照这个位置加进去即可

  • 2.2全文检索gb2312把他改成utf-8,看到前面加上3D前缀的要保留mht文件很多地方都是以3D为标识的

在这里插入图片描述

  • 2.3 在模板文件中找到Content-Location: file:///C:/B2260B68/file7736.files,并记录下来,后面代码中要用到

在这里插入图片描述
到这里模板文件就做完了,后缀名改为ftl放入项目中,如何取值或者list循环取值,判断等等都是freemarker规则,跟ftl一样使用

  • 3、下面主要介绍代码中主要的几部分,详细的请下载源码包查看
  • 代码中有下图中的代码块,设置的值就是上面在模板文件中找到的,相匹配上就可以了,后三项具体为什么设这个值我也没搞明白,就这么用也没问题,因为到后面具体用到这三个值的时候是加上32位随机码组合而成的唯一标识再使用的。
  • 在这里插入图片描述
    下面是生成word的方法:
// 配置信息,代码本身写的还是很可读的,就不过多注解了private static Configuration configuration = null;// 这里注意的是利用WordUtils的类加载器动态获得模板文件的位置// private static final String templateFolder =// WordUtils.class.getClassLoader().getResource("../../").getPath() +// "WEB-INF/templetes/";//获取系统模板所在路径private static final String templateFolder = getTempletePath("");static {configuration = new Configuration();configuration.setDefaultEncoding("utf-8");try {configuration.setDirectoryForTemplateLoading(new File(templateFolder));} catch (IOException e) {e.printStackTrace();}}//exportWord是项目中放ftl文件模板的文件夹,得到的是存放模板的路径
private static String getTempletePath(String fileName) {try {File temFile = new File(Thread.currentThread().getContextClassLoader().getResource("/").toURI().getPath());String templatePath = (new StringBuilder(String.valueOf(temFile.getParentFile().getParentFile().getPath()))).append(File.separator).append("exportWord").append(File.separator).append(fileName).toString();return templatePath;} catch (URISyntaxException e) {e.printStackTrace();}return "";}//controller调用此方法
public static void exportRichWord(HttpServletRequest request, HttpServletResponse response, Map<String, Object> map,String title, String ftlFile) throws IOException {Template freemarkerTemplate = configuration.getTemplate(ftlFile);File file = null;InputStream fin = null;ServletOutputStream out = null;try {WordHtmlGeneratorHelper.handleAllObject(map);// 调用工具类的createDoc方法生成Word文档file = createDoc(map, freemarkerTemplate);fin = new FileInputStream(file);response.setCharacterEncoding("utf-8");response.setContentType("application/msword");SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");String formatDate = sdf.format(new Date());// 设置浏览器以下载的方式处理该文件名String fileName = title + formatDate + ".doc";response.setHeader("Content-Disposition","attachment;filename=".concat(String.valueOf(URLEncoder.encode(fileName, "UTF-8"))));out = response.getOutputStream();byte[] buffer = new byte[512]; // 缓冲区int bytesToRead = -1;// 通过循环将读入的Word文件的内容输出到浏览器中while ((bytesToRead = fin.read(buffer)) != -1) {out.write(buffer, 0, bytesToRead);}} finally {if (fin != null)fin.close();if (out != null)out.close();if (file != null)file.delete(); // 删除临时文件}}private static File createDoc(Map<?, ?> dataMap, Template template) {String name = "sellPlan.doc";File f = new File(name);Template t = template;try {// 这个地方不能使用FileWriter因为需要指定编码类型否则生成的Word文档会因为有无法识别的编码而无法打开Writer w = new OutputStreamWriter(new FileOutputStream(f), "utf-8");t.process(dataMap, w);w.close();} catch (Exception ex) {ex.printStackTrace();throw new RuntimeException(ex);}return f;}

下面是controller中调用导出方法,并往map中放值,里面的imagesBase64String就是对应的模板中的占位符,下面这段代码是模板中,富文本添加的内容要经过特殊处理,如果模板中只有一个富文本,如下图
在这里插入图片描述

if (handler1.getDocBase64BlockResults() != null&& handler1.getDocBase64BlockResults().size() > 0) {for (String item : handler1.getDocBase64BlockResults()) {handledBase64Block += item + "\n";}}dataMap.put("imagesBase64String", handledBase64Block);if (handler1.getXmlImgRefs() != null&& handler1.getXmlImgRefs().size() > 0) {for (String item : handler1.getXmlImgRefs()) {xmlimaHref += item + "\n";}}dataMap.put("imagesXmlHrefString", xmlimaHref);

如果导出的模板中有多个富文本,多张图片,则需要在处理最后把dataMap中的富文本中的图片累加起来即可正常显示,实际是叠加后再放入占位符,避免后面的把前面的冲掉:
在这里插入图片描述

//模板中包含多个富文本时String old_handledBase64Block = "";if(dataMap.containsKey("imagesBase64String")){old_handledBase64Block = (String) dataMap.get("imagesBase64String");handledBase64Block = old_handledBase64Block + handledBase64Block;}dataMap.put("imagesBase64String", handledBase64Block);String old_xmlimaHref = "";if(dataMap.containsKey("imagesXmlHrefString")){old_xmlimaHref = (String) dataMap.get("imagesXmlHrefString");xmlimaHref = old_xmlimaHref + xmlimaHref;}dataMap.put("imagesXmlHrefString", xmlimaHref);

最后再说下图片路径的问题,demo中的路径是博主自己写的demo适用路径,大神们后续放到自己项目中,改成自己相对应的路径即可显示。我直接跑demo中的示例图片显示不正常,我直接拿到我自己项目中改成我自己的就可以正常显示了。
在这里插入图片描述
以上内容仅供参考,也感谢之前大神的分享资料,帮助良多~~~

源码:源码我就不再自己上传一遍了,转大神的demo源码:https://pan.baidu.com/s/1bpj2mCn
来源于博文

**

导出包含富文本内容和图片的pdf文件

**比较简单,直接用ftl页面即可,但是重要的一点就是ftl模板的头部必须要加入,必须要加,否则富文本内容和图片不能政策显示。
在这里插入图片描述
页面取值的时候如图即可,gzjh和gzzj就是富文本内容
在这里插入图片描述
导出相关代码也贴出来一些仅供参考:
1、Controller中为map设置值
在这里插入图片描述
2、exportPdf实现

	
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringWriter;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.xhtmlrenderer.pdf.ITextRenderer;import com.lowagie.text.pdf.BaseFont;import freemarker.template.Configuration;
import freemarker.template.Template;
public class PDFTemplateUtil {private static Configuration configuration = null;//获取系统模板所在路径private static final String templateFolder = getTempletePath("");static {configuration = new Configuration();configuration.setDefaultEncoding("utf-8");try {configuration.setDirectoryForTemplateLoading(new File(templateFolder));} catch (IOException e) {e.printStackTrace();}}/*** 通过模板导出pdf文件* @param data 数据* @param templateFileName 模板文件名* @throws Exception*/public static ByteArrayOutputStream createPDF(Map<String,Object> data, Template template) throws Exception {ITextRenderer renderer = new ITextRenderer();OutputStream out = new ByteArrayOutputStream();try {// 设置 css中 的字体样式(暂时仅支持宋体和黑体) 必须,不然中文不显示renderer.getFontResolver().addFont(templateFolder+"fonts/simsun.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);Template t = template;StringWriter writer = new StringWriter();// 将数据输出到html中t.process(data, writer);writer.flush();String html = writer.toString();// 把html代码传入渲染器中renderer.setDocumentFromString(html);// 设置模板中的图片路径 (这里的images在resources目录下) 模板中img标签src路径需要相对路径加图片名 如<img src="images/xh.jpg"/>// String url = PDFTemplateUtil.class.getClassLoader().getResource("images").toURI().toString();// renderer.getSharedContext().setBaseURL(url);renderer.layout();renderer.createPDF(out, false);renderer.finishPDF();out.flush();return (ByteArrayOutputStream)out;} finally {if(out != null){out.close();}}}public static void exportPdf(HttpServletRequest request, HttpServletResponse response,Map<String,Object> mapData,String title, String ftlFile) throws Exception{Template freemarkerTemplate = configuration.getTemplate(ftlFile);ByteArrayOutputStream baos = null;OutputStream out = null;try {baos = createPDF(mapData, freemarkerTemplate);;// 设置响应消息头,告诉浏览器当前响应是一个下载文件response.setContentType( "application/x-msdownload");// 告诉浏览器,当前响应数据要求用户干预保存到文件中,以及文件名是什么 如果文件名有中文,必须URL编码 SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");String formatDate = sdf.format(new Date());// 设置浏览器以下载的方式处理该文件名String fileName = title + formatDate + ".pdf";response.setHeader("Content-Disposition","attachment;filename=".concat(String.valueOf(URLEncoder.encode(fileName, "UTF-8"))));out = response.getOutputStream();baos.writeTo(out);baos.close();} catch (Exception e) {e.printStackTrace();throw new Exception("导出失败:" + e.getMessage());} finally{if(baos != null){baos.close();}if(out != null){out.close();}}}private static String getTempletePath(String fileName) {try {File temFile = new File(Thread.currentThread().getContextClassLoader().getResource("/").toURI().getPath());String templatePath = (new StringBuilder(String.valueOf(temFile.getParentFile().getParentFile().getPath()))).append(File.separator).append("exword").append(File.separator).append(fileName).toString();return templatePath;} catch (URISyntaxException e) {e.printStackTrace();}return "";}}

http://www.ppmy.cn/news/144971.html

相关文章

轻松实现Word在线编辑

本文转载自&#xff1a; https://www.cnblogs.com/xgw2004058/archive/2009/07/28/1532993.html 作者&#xff1a;xgw2004058 转载请注明该声明。 原地址&#xff1a;http://blog.joycode.com/kaneboy/archive/2004/11/03/37889.aspx有朋友询问如何在Web页面上做到像SharePoi…

Java开发中Word转PDF文件5种方案横向评测

Java开发中Word转PDF文件5种方案横向评测 前段时间接了个项目&#xff0c;需要各种处理Word模板、转PDF、签章等等&#xff0c;非常头疼&#xff0c;其中光是一个word转PDF就折磨我好久&#xff0c;实现转换很简单&#xff0c;但是效果总是达不到满意&#xff0c;于是我把市面…

解析word文件的简单实现

一、了解word结构 文章&#xff1a;《Office文件格式基础知识》、《Anatomy of a WordProcessingML File》 office 97-03 office 97-03的存储规范为OLE。它是COM对象的子集&#xff0c;是一种对象链接和嵌入的技术&#xff0c;该技术可以包含文本&#xff0c;图形&#xff0c;…

word技巧

word 高效经典教程&#xff08;整理版&#xff09; 目录 一分钟驾驭word 高效经典教程&#xff08;整理版&#xff09;... 6 A、基础知识... 6 1、度量单位... 6 2、WORD中文字字号与磅的对应关系... 6 3、字体文件格式... 7 B、文本编辑... 7 1、快速移动文档... 7 2…

java读取word文档中的文字和图片,doc和docx兼容版

也是我东抄抄&#xff0c;西抄抄拿来测试改装的&#xff0c;话不多说&#xff0c;直接上代码 <dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.4</version></dependency><depen…

EndNote20 for Mac 与搭载Apple M1芯片Mac版Word不兼容的解决方案(新发布的EndNote 20.1更新版可适配Apple M1)

2021年6月&#xff0c;EndNote20发布了EndNote 20.1更新版。该版本解决了与搭载Apple M1芯片的Mac版Word不兼容的问题。要升级EndNote 20.1&#xff0c;理论上&#xff0c;在启动EndNote20后会弹出升级界面&#xff0c;选择升级即可。或者&#xff0c;参考以下官网升级操作说明…

电脑计算机配置应用程序兼容性,电脑怎么打开兼容模式怎么办

1. windows7怎么开兼容模式 启用兼容模式就可以了,具体步骤如下: 1. 点击右下角“开始”菜单,单击“运行”,在弹出的对话框里键入“gpedit.msc”,单击“确定”。 2. 此时进入组策略编辑器界面,双击“计算机配置”,进入下一步骤。 3.找到“管理模板”选项,双击,进入下一…

32 位和 64 位版本的 Office 2010 之间的兼容性

32 位和 64 位版本的 Office 2010 之间的兼容性 Office 2010 摘要&#xff1a;针对处理 2GB 或更多数据的客户&#xff0c;Microsoft Office 2010 现在作为 64 位版本提供。本文讨论有关 32 位版本与新的 64 位版本和旧的 32 位 Office 应用程序之间兼容性的问题&#xff0c;并…