这里主要提到是需要注意的几个地方,适合已经研究过使用过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="data: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 "";}}

导出包含富文本内容和图片的word和pdf相关推荐

  1. vuejs项目纯js导出word、在线下载富文本内容或者网页另存为word文件

    所有前端导入导出方法集合: 前端必备技能知识:JS导出Blob流文件为Excel表格.Vue.js使用Blob的方式实现excel表格的下载(流文件下载)_勤动手多动脑少说多做厚积薄发-CSDN博客_ ...

  2. java freemarker 图片_java通过freemarker导出包含富文本图片的word文档

    废话不多说,进入正题! 本文重点在于:对富文本图片的导出(基础的freemarker+word模板导出这里不做详细解说哈) (ps:大神的东西太深奥~~懵逼了 一周才搞定,为了方便后来在更加简单,清晰 ...

  3. PHP 富文本内容中图片路径追加域名

    public function mergeImageUrl($content){$suffix = 'http://wwww.baidu.com/';$pregRule = "/<[i ...

  4. Java 富文本内容转化word导出

    一.需求: 当创建使用富文本编辑器,操作完的数据,传输到后台都是带有html标签的. 如:<h1>标题头</h1><h2>第二个标题</h2><a ...

  5. 提取富文本内容(包括去除图片)

    //截取富文本内容 function getSimpleText(html){ var re1 = new RegExp("<.+?>","g"); ...

  6. 跨平台应用开发进阶(五十一):HTML5(富文本内容)连续数字、字母不自动换行问题分析及解决

    文章目录 一.前言 二.问题分析 三.解决方法 3.1 对 input 标签设置 3.2 对 input 标签内的 p 标签设置 四.延伸阅读 顶部状态栏穿透问题 五.拓展阅读 一.前言 项目开发过程 ...

  7. uni怎么使用原生html标签,uni-app如何完美解析富文本内容

    在uni-app中有 rich-text 标签是自带解析富文本内容的,但是不是很完美,怎么说呢?比如富文本的代码块.图片宽度等都是无法控制的,那么现在就利用插件来解析,这个解析插件小编是利用图片.ht ...

  8. php 给富文本里的图片增加ALT、TITLE属性

    php 给富文本里的图片增加ALT.TITLE属性 $text = '内容<img src="http://www.test.com/test1.jpg">内容'; $ ...

  9. Android中TextView文本或富文本内容自行换行的问题

    Android中TextView设置文本或富文本的时候出现没有到头就换行的问题. 网上有很多相关内容. 但大多都是关于文本换行的情况, 对于有富文本内容的情况, 如设置Spanned对象的内容, 会出 ...

  10. 最全的java对接微信小程序客服功能实现(包含自动回复文本消息、图片消息,进入人工客服)

    java对接微信小程序客服功能实现(包含自动回复文本消息.图片消息,进入人工客服) 第一步:请求校验(确认请求来自微信服务器) 代码如下: @ApiOperation(value = " 微 ...

最新文章

  1. MyBatis延迟加载及在spring中集成配置
  2. django-重写登录认证(可以使用用户名或手机号登录)
  3. ADO学习(三)Command 对象
  4. cas4.2.7实现单点登录
  5. JavaScript之BOM基础
  6. 阿里云虚拟机被尝试登陆多次,还好哥的密码不是一般般的
  7. apache-commons pool使用
  8. Hibernate-面试题
  9. SQL Server : 使用SQL Express的User Instance(用户实例)特性
  10. 重走JAVA之路(四):ThreadLocal源码解析
  11. 如何更改 think-cell 图表的默认颜色?
  12. Chrome浏览器保存整个网页为图片
  13. PPC2003SE开发日记-资源之工具安装(JONSON原创)
  14. 领跑衫获奖感言 课程总结
  15. LeetCode - 720 - 词典里最长的单词(longest-word-in-dictionary)
  16. 零基础学习Java会不会很吃力?
  17. PTA 7-10 字符转换 (15分)
  18. CH3NH3PbI2Cl (MAPbI2Cl) 甲胺氯基钙钛矿 1446121-07-8
  19. SSRF(Server-side Request Forgery)
  20. 树莓派魔镜MagicMirror —— 6 清理并更新系统

热门文章

  1. [渝粤教育] 西南科技大学 财务会计 在线考试复习资料(1)
  2. window10 Embedded 各分支
  3. 特朗普启动美国AI国家计划,人工智能角逐再添新变化!
  4. java迷宫算法_迷宫求解算法(java版)
  5. PLC有几种编程语言以及它们的特点是什么
  6. plc和计算机语言,PLC的编程语言具体有哪些
  7. javascript实现常用的设计模式
  8. 软件测试可用性常用指标
  9. B站视频下载助手使用教程
  10. 谷歌闹别扭期间女生创办“谷姐”网(cnblogs)