这周工作中,遇到一个需求是需要将数据库中富文本内容导出到word文档里面,于是就采用POI技术实现了一下导出word文档的功能。(word文档是识别html内容的,所以富文本内容也自然能够识别。

一、准备工作

采用技术介绍:

  • Java + POI
  • Jsoup(主要是解析图片标签,然后缩放图片大小,下文有介绍
<!-- jsoup依赖-->
<dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.12.1</version>
</dependency>
<!-- poi依赖-->
<dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>4.1.0</version>
</dependency>
<dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>4.1.0</version>
</dependency>

二、具体步骤

(1)Word工具类

采用POI组件编写一个导出word的工具类。

package com.gitee.zhuyb.richtext.word;import org.apache.poi.poifs.filesystem.DirectoryEntry;
import org.apache.poi.poifs.filesystem.DocumentEntry;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;/*** @author: ZhuYouBin* @date: 2022/1/13 10:21* @description: poi操作word工具类*/
public class WordUtil {/*** 导出富文本内容到word* @param request* @param response* @param content 输出内容* @param fileName 导出文件名称* @throws Exception*/public static void exportHtmlToWord(HttpServletRequest request, HttpServletResponse response, String content, String fileName) throws Exception {// 拼接html格式内容StringBuffer sbf = new StringBuffer();// 这里拼接一下html标签,便于word文档能够识别sbf.append("<html " +"xmlns:v=\"urn:schemas-microsoft-com:vml\" xmlns:o=\"urn:schemas-microsoft-com:office:office\" xmlns:w=\"urn:schemas-microsoft-com:office:word\" xmlns:m=\"http://schemas.microsoft.com/office/2004/12/omml\" xmlns=\"http://www.w3.org/TR/REC-html40\"" + //将版式从web版式改成页面试图">");sbf.append("<head>" +"<!--[if gte mso 9]><xml><w:WordDocument><w:View>Print</w:View><w:TrackMoves>false</w:TrackMoves><w:TrackFormatting/><w:ValidateAgainstSchemas/><w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid><w:IgnoreMixedContent>false</w:IgnoreMixedContent><w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText><w:DoNotPromoteQF/><w:LidThemeOther>EN-US</w:LidThemeOther><w:LidThemeAsian>ZH-CN</w:LidThemeAsian><w:LidThemeComplexScript>X-NONE</w:LidThemeComplexScript><w:Compatibility><w:BreakWrappedTables/><w:SnapToGridInCell/><w:WrapTextWithPunct/><w:UseAsianBreakRules/><w:DontGrowAutofit/><w:SplitPgBreakAndParaMark/><w:DontVertAlignCellWithSp/><w:DontBreakConstrainedForcedTables/><w:DontVertAlignInTxbx/><w:Word11KerningPairs/><w:CachedColBalance/><w:UseFELayout/></w:Compatibility><w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel><m:mathPr><m:mathFont m:val=\"Cambria Math\"/><m:brkBin m:val=\"before\"/><m:brkBinSub m:val=\"--\"/><m:smallFrac m:val=\"off\"/><m:dispDef/><m:lMargin m:val=\"0\"/> <m:rMargin m:val=\"0\"/><m:defJc m:val=\"centerGroup\"/><m:wrapIndent m:val=\"1440\"/><m:intLim m:val=\"subSup\"/><m:naryLim m:val=\"undOvr\"/></m:mathPr></w:WordDocument></xml><![endif]-->" +"</head>");sbf.append("<body>");// 富文本内容sbf.append(content);sbf.append("</body></html>");// 必须要设置编码,避免中文就会乱码byte[] b = sbf.toString().getBytes("GBK");// 将字节数组包装到流中ByteArrayInputStream bais = new ByteArrayInputStream(b);POIFSFileSystem poifs = new POIFSFileSystem();DirectoryEntry directory = poifs.getRoot();// 这代码不能省略,否则导出乱码。DocumentEntry documentEntry = directory.createDocument("WordDocument", bais);//输出文件request.setCharacterEncoding("utf-8");// 导出word格式response.setContentType("application/msword");response.addHeader("Content-Disposition", "attachment;filename=" +new String(fileName.getBytes("GB2312"),"iso8859-1") + ".doc");ServletOutputStream ostream = response.getOutputStream();poifs.writeFilesystem(ostream);bais.close();ostream.close();}}

(2)图片工具类

图片工具类,主要是用于缩放图片大小,这里缩放图片采用的是java中awt包下提供的图像处理类。

假设富文本中又包含base64编码的图片,这时候要导出到word文档中,图片如果太大,导出word时候图片会超出word范围,就像下面所示:

ImageUtils工具类代码如下:

package com.gitee.zhuyb.richtext.word;import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;/*** @author: ZhuYouBin* @date: 2022/1/13 15:01* @description: 图片处理工具类*/
public class ImageUtils {/*** 通过BufferedImage图片流调整图片大小*/public static BufferedImage resizeImage(BufferedImage originalImage, int targetWidth, int targetHeight) throws IOException {Image resultingImage = originalImage.getScaledInstance(targetWidth, targetHeight, Image.SCALE_AREA_AVERAGING);BufferedImage outputImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_RGB);outputImage.getGraphics().drawImage(resultingImage, 0, 0, null);return outputImage;}/*** 返回base64图片* @param data* @return*/public static String imageToBase64(byte[] data) {BASE64Encoder encoder = new BASE64Encoder();// 返回Base64编码过的字节数组字符串return encoder.encode(data);}/*** base64转换成byte数组* @param base64* @return* @throws IOException*/public static byte[] base64ToByte(String base64) throws IOException {BASE64Decoder decoder = new BASE64Decoder();// 返回Base64编码过的字节数组字符串return decoder.decodeBuffer(base64);}/*** BufferedImage图片流转byte[]数组*/public static byte[] imageToBytes(BufferedImage bImage) {ByteArrayOutputStream out = new ByteArrayOutputStream();try {ImageIO.write(bImage, "png", out);} catch (IOException e) {e.printStackTrace();}return out.toByteArray();}/*** byte[]数组转BufferedImage图片流*/public static BufferedImage bytesToBufferedImage(byte[] ImageByte) {ByteArrayInputStream in = new ByteArrayInputStream(ImageByte);BufferedImage image = null;try {image = ImageIO.read(in);} catch (IOException e) {e.printStackTrace();}return image;}
}

(3)导出word

这里采用web下载的方式导出word文档。

这里先给出用于测试的富文本内容数据:

<h1>如何将富文本内容导出到word文档</h1><p style="color:red;font-size:20px;">采用poi将富文本内容导出到word文档</p><div style="background-color:green;">这是有背景颜色的div内容</div>
<img src="这里写base64后的图片编码">这是base64编码后的图片

首先将图片转换成base64编码,然后把编码赋值到上面的【img】标签中的【src】属性里面即可测试。

因为直接将这些测试数据赋值给静态字符串,无法编译,所以下面为了测试,首先通过文件读取富文本内容。(实际开发中,富文本内容都是直接从数据库中获取,所以无需操作文件

package com.gitee.zhuyb.richtext.word;import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;/*** @version 1.0.0* @Description: #类描述* @Date: 2022/1/16 13:57* @Copyright (C) ZhuYouBin*/
@RestController
@RequestMapping("/export")
public class ExportController {@RequestMapping(value = "/exportWord")public void export(HttpServletRequest request, HttpServletResponse response)throws Exception {try {String tmpContent = "";// 获取img图片标签// 1.Jsoup解析htmlDocument document = Jsoup.parse(tmpContent);// 获取所有img图片标签Elements img = document.getElementsByTag("img");int index = 0;List<String> imgBase64List = new ArrayList<>();for (Element element : img) {imgBase64List.add(element.attr("src"));// 处理特殊符号String attrData = element.attr("src");// base64编码后可能包含 + 特殊字符,所以需要转义attrData = attrData.replaceAll("\\+", "\\\\+");tmpContent = tmpContent.replaceAll(attrData, "{{image_src" + index + "}}");index++;}// 缩放图片大小,然后重新base64编码后替换到富文本内容里面导出wordindex = 0;String prefix = "data:image/png;base64,"; // base64编码前缀for (String base64 : imgBase64List) {if (StringUtils.isNotBlank(base64)) {// 缩小图片base64 = base64.replaceAll(prefix, "");BufferedImage bufferedImage = ImageUtils.bytesToBufferedImage(ImageUtils.base64ToByte(base64));if (bufferedImage == null) {tmpContent = tmpContent.replaceAll("\\{\\{image_src" + index + "}}", "");} else {int height = bufferedImage.getHeight();int width = bufferedImage.getWidth();// 如果图片宽度小于700,则图片不缩放,还是使用原图片if (width > 700) {BufferedImage imgZoom = ImageUtils.resizeImage(bufferedImage, 700, height);String imageToBase64 = ImageUtils.imageToBase64(ImageUtils.imageToBytes(imgZoom));tmpContent = tmpContent.replaceAll("\\{\\{image_src" + index + "}}", prefix + imageToBase64);} else {tmpContent = tmpContent.replaceAll("\\{\\{image_src" + index + "}}", prefix + base64);}}} else {tmpContent = tmpContent.replaceAll("\\{\\{image_src" + index + "}}", "");}index++;}// 执行导出操作WordUtil.exportHtmlToWord(request, response, tmpContent, "富文本内容导出word");} catch (Exception e) {e.printStackTrace();}}}

(4)如何解决图片太大的问题

前面说了,导出富文本中的base64图片时候,如果图片太大,导出到word中就会很大,导致word很难看,那有什么解决办法呢?

解决方案:

  • 将图片缩放后,在将新的base64编码导出到word中
  • 采用jsoup提取富文本中的所有【img】标签,然后获取【src】属性内容,将base64转换成image对象,缩放图片,之后再将缩放的图片进行base64编码,重新替换【src】属性。

具体上面的代码已经实现了,可以仔细看下。

注意:这种图片导出有一个缺点,就是导出的图片可能会变形,无法控制宽高比。

以上,就是使用Java + POI + Jsoup实现富文本内容导出到word文档的操作步骤。

【操作word】Java + POI导出富文本的内容到word文档相关推荐

  1. Java poi导出带html标签内容的word文档

    public static void exportWord(HttpServletResponse response, String content, String fileName) throws ...

  2. java freemarker 导出富文本到Word文档

    最近一直在加班 导致看到代码就想吐 今天抽出时间来记录一下 用freemaker导出富文本信息 之前使用freemaker导出图片等信息时 使用的是xml方式,不明白的 可以看 freemaker生成 ...

  3. springboot导出富文本框数据到word

    这里需要注意的是:依赖的版本号都是一一对应的,如果使用不兼容的版本号,可能会报编译异常和缺少类的错误,这里已提供对应的所需依赖和版本号,大家可以参考一下. 具体的api文档可以参考官网api,很好理解 ...

  4. Java POI导出(图片,文字,表格)word文档

    先给出官网链接,方便各位博友深入了解 http://deepoove.com/poi-tl/ 这里的教程,针对导出带有图片.文字.表格的Word文档 1.话不多说 先添加依赖 <dependen ...

  5. java导出富文本到word_富文本编辑器内容实现word导出下载,请各位大神们指点,感激不尽...

    展开全部 给个我之前的写的例子给你action 层public ActionForward dataExport(ActionMapping mapping, ActionForm form, Htt ...

  6. java 富文本 word_Java导出富文本到word

    源码地址: 背景 最近用java开发一个中车项目管理系统,里面有一个维修单word导出功能. 可用方案 在网上查找资料,总结出两种比较可行的方案. (1) 制作word模板,导出成mht文件(单页面网 ...

  7. Java 实现HTML富文本导出至word完美解决方案

    Java 实现HTML富文本导出至word完美解决方案 **需求: 最近用java开发一个申报管理系统,里面有一个根据申请书的模板填写项目申报信息的功能,并将项目申请书word导出功能.** 1: 动 ...

  8. java根据html生成word文档,Java之HTML富文本导出WORD(不含图片)

    一.需求: 我们在使用富文本编辑器来编辑文本的时候,文本会自带HTML的标签比如 等来修饰字体样式. 比如ueditor.kindeditor等富文本编辑器. 那么,我们如何将富文本编辑器里的内容导出 ...

  9. Java POI导出word文件及生成表格

    HWPF是处理 Microsoft Word 97(-2007) .doc文件格式,它还为较旧的Word 6和Word 95文件格式提供了有限的只读支持.包含在poi-scratchpad-XXX.j ...

最新文章

  1. win10 安装字体且不占用系统盘资源
  2. easyui 传递参数报错(错误:uncaught SyntaxError: Unexpected identifier)
  3. Flex Builder 2 注册码
  4. 阿里云峰会 | 统一召回引擎在搜索场景的应用实践
  5. 我通过“种树”,拿下鹅厂实习offer
  6. 引脚悬空是什么电平_STM32单片机必须掌握的八种IO口模式和引脚配置方式
  7. 如何用DOM4J编程使用xml schema
  8. Java 学习笔记(官方不推荐写法篇)
  9. 中国高铁走向全球,一个行业标准帮了大忙
  10. 多频电磁感应仪GEM-2介绍
  11. Sql Prompt使用技巧
  12. idea 关闭检查更新_intellij idea怎么关闭自动更新
  13. shopex mysql索引_shopex数据库表结构说明文档.doc
  14. 中标麒麟Linux64平台上QT5.6.3源码编译安装
  15. 计算机图形学迷宫论文,三维迷宫的设计与制造
  16. 三维激光扫描系统基本原理及分类
  17. EPICS stream模块使用示例 -- 基于字符串协议的通信
  18. IB学生喜欢申请哪些英国院校?
  19. 拿两千块钱的薪水要有一万块钱的范儿--蜗居编剧
  20. 【小知识】有趣代码注释图案【持续收集更新...】

热门文章

  1. 几个手机兼职做任务发布悬赏的app对比
  2. 科大讯飞的2022:夯实“根据地”业务,以技术创新点燃大模型产业落地的“星星之火”...
  3. 两个狮子和老鼠的小故事
  4. win10设置各种闪退解决办法
  5. 不是所有人都适合职场
  6. 同源时钟、同相位时钟、同时钟域时钟
  7. 九号机器人田奇峰_九号机器人三款新品亮相 以全新视角解读服务机器人产业...
  8. 数据库系统原理与应用教程(052)—— MySQL 的数据完整性(十四):交叉表查询(行列转换)
  9. macOS无法退出登录,显示关闭所有icloud服务再试一次
  10. 百度地图、高德地图都用POI吸引你,不过它到底是什么?