java poi实现数据的word导出(包括word模板的使用、复制表格、复制行、插入图片的使用)

1.实现的效果

实现病人基本信息、多条病历数据、多项检查项图片的动态插入(网络图片)

2.模板

把word中的占位符替换为实际的值,注意WPFRun表示有相同属性的一段文本,所以模板里变量内容需要从左到右的顺序写,${name},如果先写${},再添加内容,会拆分成几部分,不能正常使用,因此若出现替换失败的情况,可以尝试手动修改占位符,不要偷懒直接复制

3.pom.xml中相关依赖

包括poi和模板

<!-- poi -->
<dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>3.15-beta2</version>
</dependency>
<!-- 模板 -->
<dependency><groupId>org.apache.poi</groupId><artifactId>ooxml-schemas</artifactId><version>1.1</version>
</dependency>

4.导出的工具类

/*** 功能描述:word工具类** @author jynn* @created 2019年8月15日* @version 1.0.0*/
public class WordUtil {/*** 功能描述:word下载** @param response* @param patientMap* @param list* @param itemList* @param file* @see [相关类/方法](可选)* @since [产品/模块版本](可选)*/public static final void DownloadWord(HttpServletResponse
response, Map<String, Object> patientMap,List<Map<String, Object>> list, List<List<String>>
itemList, String file) {CustomXWPFDocument document = null;ServletOutputStream servletOS = null;ByteArrayOutputStream ostream = null;// 添加表格try {servletOS = response.getOutputStream();ostream = new ByteArrayOutputStream();// 生成word文档并读取模板document = new
CustomXWPFDocument(POIXMLDocument.openPackage(file));// 病人信息XWPFTable patientTable = document.getTables().get(0);eachTable(document, patientTable.getRows(), patientMap);// 病历信息// 根据病历数量复制表格for (int i = 0; i < list.size(); i++) {// 标题XWPFParagraph paragraph = document.createParagraph();XWPFRun paragraphRun = paragraph.createRun();paragraphRun.setText(list.get(i).get("${title}").toString());paragraph.setAlignment(ParagraphAlignment.CENTER);// 创建新的 CTTbl , tableCTTbl ctTbl = CTTbl.Factory.newInstance(); // 复制原来的CTTblctTbl.set(document.getTables().get(1).getCTTbl()); IBody iBody = document.getTables().get(1).getBody();BeanUtils.copyProperties(document.getTables().get(1).getBody(), iBody);XWPFTable newTable = new XWPFTable(ctTbl, iBody); // 新增一个table,使用复制好的CttblList<String> iList = itemList.get(i);Integer itemIndex = 0;// 新建西医检查信息for (String item : iList) {// 复制行,主要用于复制样式和重设图片文本// 直接新增行还需要手动改样式,比较繁琐XWPFTableRow titleRow = newTable.createRow();// 注意setText方式是在原来文本的后面添加,若不需要原先的文本在需要删除原先的run,新增一个runcopyTableRow(titleRow, newTable.getRows().get(7), null);titleRow.getTableCells().get(0).setText(item);XWPFTableRow imageRow = newTable.createRow();// 带入序号重设文本copyTableRow(imageRow, newTable.getRows().get(8), itemIndex);itemIndex++;}// 删除作为模板的检查项标题和图片行newTable.removeRow(7);newTable.removeRow(7);// 遍历表格,并替换模板eachTable(document, newTable.getRows(), list.get(i));document.createTable(); // 创建一个空的Table// 设置table值document.setTable(i + 2, newTable); // 将table设置到word中}List<XWPFTable> tables = document.getTables();// 删除作为模板的第一个表格for (int i = tables.get(1).getRows().size(); i >= 0; i--) {tables.get(1).removeRow(i);}// 输出word内容文件流,提供下载response.setContentType("application/x-msdownload");String name = java.net.URLEncoder.encode("病历.docx", "UTF8");name = new String((name).getBytes("UTF-8"), "ISO-8859-1");response.addHeader("Content-Disposition", "attachment;
filename*=utf-8'zh_cn'" + name);document.write(ostream);servletOS.write(ostream.toByteArray());} catch (Exception e) {System.out.print(e.getMessage());} finally {try {if (ostream != null) {ostream.close();}if (servletOS != null) {servletOS.close();}} catch (IOException e) {}}}/*** 功能描述:复制单元格,从source到target** @param target* @param source* @param index* @see [相关类/方法](可选)* @since [产品/模块版本](可选)*/public static void copyTableCell(XWPFTableCell target,
XWPFTableCell source, Integer index) {// 列属性if (source.getCTTc() != null) {target.getCTTc().setTcPr(source.getCTTc().getTcPr());}// 删除段落for (int pos = 0; pos < target.getParagraphs().size(); pos++) {target.removeParagraph(pos);}// 添加段落for (XWPFParagraph sp : source.getParagraphs()) {XWPFParagraph targetP = target.addParagraph();copyParagraph(targetP, sp, index);}}/*** 功能描述:复制段落,从source到target** @param target* @param source* @param index* @see [相关类/方法](可选)* @since [产品/模块版本](可选)*/public static void copyParagraph(XWPFParagraph target,
XWPFParagraph source, Integer index) {// 设置段落样式target.getCTP().setPPr(source.getCTP().getPPr());// 移除所有的runfor (int pos = target.getRuns().size() - 1; pos >= 0; pos--) {target.removeRun(pos);}// copy 新的runfor (XWPFRun s : source.getRuns()) {XWPFRun targetrun = target.createRun();copyRun(targetrun, s, index);}}/*** 功能描述:复制RUN,从source到target** @param target* @param source* @param index* @see [相关类/方法](可选)* @since [产品/模块版本](可选)*/public static void copyRun(XWPFRun target, XWPFRun source, Integer
index) {// 设置run属性target.getCTR().setRPr(source.getCTR().getRPr());// 设置文本String tail = "";if (index != null) {tail = index.toString();}target.setText(source.text().replace("}", "") + tail + "}");}/*** 功能描述:复制行,从source到target** @param target* @param source* @param index* @see [相关类/方法](可选)* @since [产品/模块版本](可选)*/public static void copyTableRow(XWPFTableRow target, XWPFTableRow
source, Integer index) {// 复制样式if (source.getCtRow() != null) {target.getCtRow().setTrPr(source.getCtRow().getTrPr());}// 复制单元格for (int i = 0; i < source.getTableCells().size(); i++) {XWPFTableCell cell1 = target.getCell(i);XWPFTableCell cell2 = source.getCell(i);if (cell1 == null) {cell1 = target.addNewTableCell();}copyTableCell(cell1, cell2, index);}}/*** 功能描述:遍历表格,替换信息** @param document* @param rows* @param textMap* @see [相关类/方法](可选)* @since [产品/模块版本](可选)*/public static void eachTable(CustomXWPFDocument document,
List<XWPFTableRow> rows, Map<String, Object> textMap) {for (XWPFTableRow row : rows) {List<XWPFTableCell> cells = row.getTableCells();for (XWPFTableCell cell : cells) {// 判断单元格是否需要替换if (checkText(cell.getText())) {List<XWPFParagraph> paragraphs = cell.getParagraphs();for (XWPFParagraph paragraph : paragraphs) {List<XWPFRun> runs = paragraph.getRuns();for (XWPFRun run : runs) {Object ob = changeValue(run.toString(), textMap);if (ob instanceof String) {run.setText((String) ob, 0);} else if (ob instanceof Map)  {run.setText("", 0);<u>Map</u> pic = (<u>Map</u>) ob;int width =
Integer.parseInt(pic.get("width").toString());int height =
Integer.parseInt(pic.get("height").toString());int picType =
getPictureType(pic.get("type").toString());String urls =
pic.get("content").toString();String[] urlList =
urls.split(";");for (String url :
urlList) {ByteArrayInputStream byteInputStream;try {//网络图片取文件数据byteInputStream = new ByteArrayInputStream(getImageData(url));document.addPictureData(byteInputStream, picType);int id2 =
document.getAllPackagePictures().size() - 1;document.createPicture(id2, width, height, paragraph);} catch (Exception
e) {e.printStackTrace();}}}break;}}}}}}/*** 功能描述:读取线上图片文件流** @param strUrl* @return* @see [相关类/方法](可选)* @since [产品/模块版本](可选)*/public static byte[] getImageData(String strUrl) {InputStream inStream = null;try {// new一个URL对象URL url = new URL(strUrl);// 打开链接HttpURLConnection conn = (HttpURLConnection)
url.openConnection();// 设置请求方式为"GET"conn.setRequestMethod("GET");// 超时响应时间为5秒conn.setConnectTimeout(10 * 1000);// 通过输入流获取图片数据inStream = conn.getInputStream();byte[] data = readInputStream(inStream);return data;} catch (Exception e) {return null;} finally {if (inStream != null) {try {inStream.close();} catch (Exception e2) {System.out.println("关闭流失败");}}}}/*** 功能描述:读取文件流** @param inStream* @return* @throws Exception* @see [相关类/方法](可选)* @since [产品/模块版本](可选)*/public static byte[] readInputStream(InputStream inStream) throws
Exception {ByteArrayOutputStream outStream = new
ByteArrayOutputStream();// 创建一个Buffer字符串byte[] buffer = new byte[1024];// 每次读取的字符串长度,如果为-1,代表全部读取完毕int len = 0;// 使用一个输入流从buffer里把数据读取出来while ((len = inStream.read(buffer)) != -1) {// 用输出流往buffer里写入数据,中间参数代表从哪个位置开始读,len代表读取的长度outStream.write(buffer, 0, len);}// 关闭输入流inStream.close();// 把outStream里的数据写入内存return outStream.toByteArray();}/*** 功能描述:为表格插入数据,行数不够添加新行** @param table* @param tableList* @param daList* @param type* @see [相关类/方法](可选)* @since [产品/模块版本](可选)*/public static void insertTable(XWPFTable table, List<String>
tableList, List<String[]> daList, Integer type) {if (2 == type) {// 创建行和创建需要的列for (int i = 1; i < daList.size(); i++) {// 添加一个新行XWPFTableRow row = table.insertNewTableRow(1);for (int k = 0; k < daList.get(0).length; k++) {// 根据String数组第一条数据的长度动态创建列row.createCell();}}// 创建行,根据需要插入的数据添加新行,不处理表头for (int i = 0; i < daList.size(); i++) {List<XWPFTableCell> cells = table.getRow(i +
1).getTableCells();for (int j = 0; j < cells.size(); j++) {XWPFTableCell cell02 = cells.get(j);cell02.setText(daList.get(i)[j]);}}} else if (4 == type) {// 插入表头下面第一行的数据for (int i = 0; i < tableList.size(); i++) {XWPFTableRow row = table.createRow();List<XWPFTableCell> cells = row.getTableCells();cells.get(0).setText(tableList.get(i));}}}/*** 功能描述:判断文本中时候包含$** @param text* @return* @see [相关类/方法](可选)* @since [产品/模块版本](可选)*/public static boolean checkText(String text) {boolean check = false;if (text.indexOf("$") != -1) {check = true;}return check;}/*** 功能描述:匹配传入信息集合与模板** @param value* @param textMap* @return* @see [相关类/方法](可选)* @since [产品/模块版本](可选)*/public static Object changeValue(String value, Map<String, Object>
textMap) {Set<Map.Entry<String, Object>> textSets =
textMap.entrySet();Object valu = "";for (Map.Entry<String, Object> textSet : textSets) {// 匹配模板与替换值 格式${key}String key = textSet.getKey();if (value.indexOf(key) != -1) {valu = textSet.getValue();}}return valu;}/*** 功能描述:根据图片类型,取得对应的图片类型代码** @param picType* @return* @see [相关类/方法](可选)* @since [产品/模块版本](可选)*/private static int getPictureType(String picType) {int res = CustomXWPFDocument.PICTURE_TYPE_PICT;if (picType != null) {if (picType.equalsIgnoreCase("png")) {res = CustomXWPFDocument.PICTURE_TYPE_PNG;} else if (picType.equalsIgnoreCase("dib")) {res = CustomXWPFDocument.PICTURE_TYPE_DIB;} else if (picType.equalsIgnoreCase("emf")) {res = CustomXWPFDocument.PICTURE_TYPE_EMF;} else if (picType.equalsIgnoreCase("jpg") ||
picType.equalsIgnoreCase("jpeg")) {res = CustomXWPFDocument.PICTURE_TYPE_JPEG;} else if (picType.equalsIgnoreCase("wmf")) {res = CustomXWPFDocument.PICTURE_TYPE_WMF;}}return res;}
}

5.自定义的ducument

主要需要重写document的创建图片方法

/*** 功能描述:自定义XWPFDocument,并重写 createPicture()方法** @author jynn* @created 2019年8月18日* @version 1.0.0*/
public class CustomXWPFDocument extends XWPFDocument {public CustomXWPFDocument() {super();}public CustomXWPFDocument(OPCPackage opcPackage) throws
IOException {super(opcPackage);}public CustomXWPFDocument(InputStream in) throws IOException {super(in);}/*** 功能描述:创建图片** @param id* @param width* @param height* @param paragraph* @return* @see [相关类/方法](可选)* @since [产品/模块版本](可选)*/public void createPicture(int id, int width, int height,
XWPFParagraph paragraph) {final int EMU = 9525;width *= EMU;height *= EMU;String blipId =
getAllPictures().get(id).<u>getPackageRelationship</u><u>()</u>.getId();CTInline inline =
paragraph.createRun().getCTR().addNewDrawing().addNewInline();System.out.println(blipId + ":" + inline);String picXml = "" + "<a:graphic
xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">"+ "   <a:graphicData
uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"+ "      <pic:pic
xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"+ "         <pic:nvPicPr>" + "            <pic:cNvPr
id=\"" + id + "\" name=\"Generated\"/>"+ "            <pic:cNvPicPr/>" + "
</pic:nvPicPr>" + "         <pic:blipFill>"+ "            <a:blip r:embed=\"" + blipId+ "\"
xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"/>"+ "            <a:stretch>" + "
<a:fillRect/>" + "            </a:stretch>"+ "         </pic:blipFill>" + "         <pic:spPr>"
+ "            <a:xfrm>"+ "               <a:off x=\"0\" y=\"0\"/>" + "
<a:ext cx=\"" + width + "\" cy=\""+ height + "\"/>" + "            </a:xfrm>" + "
<a:prstGeom prst=\"rect\">"+ "               <a:avLst/>" + "
</a:prstGeom>" + "         </pic:spPr>"+ "      </pic:pic>" + "   </a:graphicData>" +
"</a:graphic>";inline.addNewGraphic().addNewGraphicData();XmlToken xmlToken = null;try {xmlToken = XmlToken.Factory.parse(picXml);} catch (XmlException xe) {xe.printStackTrace();}inline.set(xmlToken);inline.setDistT(0);inline.setDistB(0);inline.setDistL(0);inline.setDistR(0);CTPositiveSize2D extent = inline.addNewExtent();extent.setCx(width);extent.setCy(height);CTNonVisualDrawingProps docPr = inline.addNewDocPr();docPr.setId(id);docPr.setName("图片" + id);docPr.setDescr("测试");}
}

6.源代码

运行接口:http://localhost:9400/word/export
https://github.com/JynnFun/word

java poi实现word导出(包括word模板的使用、复制表格、复制行、插入图片的使用)相关推荐

  1. Java POI Excel导入导出

    Java POI Excel导入导出 1.maven引入依赖 2.导入Excel 3.导出Excel 1.maven引入依赖 <!-- POI Excel 操作 --> <depen ...

  2. 【在工程Word文档的大量表格中自动插入图片的python程序】

    在工程Word文档的大量表格中自动插入图片的python程序 一.问题描述 在word的表格中插入图片代码 图形界面GUI设计 程序打包 一.问题描述 我的姐姐是一个工程技术公司的资料员,经常需要在w ...

  3. Java使用POI生成柱状图导出到word文档(柱状图)

    本篇文章主要介绍,如何使用Apache POI组件生成柱状图导出到word文档中,具体步骤看下文. 一.实现效果 Java使用POI技术生成柱状图导出到word文档中,最终生成的柱状图如下所示: 二. ...

  4. 最新实用版——JAVA使用POI替换Word模板中指定字符,并可插入图片。

    JAVA替换Word模板指定字符,并可插入图片. 在一年之前还之前有写过一篇使用jacob对word插入图片的博客.点击率蛮高8800多次,当然多亏了百度搜索引擎的帮忙

  5. java实现将数据导出为word功能(文字,表格,图片的循环导出)

    1.配置文件的准备 1.导出功能实现所需要的pom文件 <!-- 导出到word(循环图片) --><!-- word导出 方式:easypoi--><dependenc ...

  6. java使用freemarker模版导出分页word

    1.模版的制作 (1).先用word制作好模版的样式,我的模版样式如下图 (2).将制作好的word模版另存为word 2003 XML文件,具体内容如下 <?xml version=" ...

  7. 一、后端:针对用JAVA POI解决已知路径WORD文件增加自定义页眉,灵活设置页眉字体部分样式@2019

    一.获取添加页眉doc文件 我的项目文件路径: String reportSavePath= "****************"; DOCX文件一: changer.setAcc ...

  8. 用python 修改word中表格数据,插入图片 +实例分析

    今天学习了关于word表格修改数据,插入图片的知识.Word表格跟对普通的文章段落处理不太一样,下面我就用我学校的请假条表格来带大家一一分析. 1.导入python-docx库 在cmd中导入该库 p ...

  9. JAVA实现word导出,word转PDF,预览汇总

    #使用POI实现word模板导出 笔者的word模板没有存在的OSS中,因为模板不多,故我是在Spring boot项目中的resources中创建了一个专门用于存放word模板的文件夹 首先创建一个 ...

  10. java poi 上传与下载word文件

    java编程要实现对word的操作没有vb那种编程语言来得容易,得借助一些开源组件,其中就包括jacob.poi等, 而poi应用得最为广泛,对word2003和2007的读和写word操作都十分方便 ...

最新文章

  1. 浅谈千万级PV/IP规模高性能高并发网站架构
  2. Exchange2010配置-设置OWA身份验证及重定向
  3. java 反射模式_java 设计模式——反射机制的应用
  4. boost::callable_traits添加可变参数的测试程序
  5. mysql拦截器实现crud_Mybatis自定义SQL拦截器
  6. 网站获取ip代码怎么写_大学生写论文必备技能:怎么免费获取外文文献并下载...
  7. 后台执行命令的工具screen
  8. Compile qt-2.3.10
  9. MSN Messenger的用户管理
  10. java jdom 类_JDOM 介绍及使用指南
  11. C语言编程入门——综合练习(一)
  12. 14款开源或免费的GIS软件
  13. 互联网公司常用架构模式梳理
  14. 理财十问:1.你知道自己的风险偏好吗?
  15. C++之getch(),getche(),getchar()的区别
  16. SQL2022-8-10
  17. 【大学生数学竞赛】公式大全(补充中)
  18. 【知乎问题】如何让不懂编程的人感受到编程的魅力
  19. 如何在2周内交付85%以上需求?阿里工程师这么做
  20. 将数据库中的页面渲染到网页上

热门文章

  1. Tern – 字幕组机翻小助手:自动翻译英文字幕为中英双语字幕[Win/macOS]
  2. JAVA数组实现商品的进销存
  3. 2016学习进度记录
  4. elasticsearch聚合--桶(Buckets)和指标(Metrics)的概念
  5. 洛谷P2375 [NOI2014] 动物园 题解
  6. OpenCV 入门教程:中值滤波和双边滤波
  7. windows10安装jupyter notebook
  8. 平台解析|计讯水电站下泄生态流量监控云平台
  9. 6. 用*输出字母C的图案
  10. 几个知名英文搜索引擎的优劣比较