java导出word格式的文件

  1. 使用POI技术生成word格式的月报,实现功能根据日期进行预览,导出。
  2. 使用template.docx作为word模板,参数使用特殊符号标识,封装数据(Map<String,String>); 通过IO读取模板替换参数,从而动态获取数据。
  3. 预览的实现,由于web页面展示通过html或pdf来进行。将word转为pdf后基本都会出现样式的不兼容问题,所以放弃。 最终我根据word的模板又手写了一个html对应的模板,参数使用的jsp的el表达式动态替换参数,从而动态获取数据。暂时没有考虑word模板过多的情况。
  4. 由于我做的系统的前端是easyui的框架,预览时的翻页使用了panel插件功能,批量导出使用的ZipEntry。

相关代码

  

  1 package com.bocsh.base.util;
  2 
  3 import java.io.ByteArrayOutputStream;
  4 import java.io.FileInputStream;
  5 import java.io.IOException;
  6 import java.util.List;
  7 import java.util.Map;
  8 import java.util.Map.Entry;
  9 import java.util.Set;
 10 
 11 
 12 //import org.apache.poi.POIXMLDocument;
 13 import org.apache.poi.xwpf.usermodel.*;
 14 
 15 /**
 16  * 通过word模板生成新的word工具类
 17  *
 18  * @author zhiheng
 19  *
 20  *
 21  * XWPFDocument代表一个docx文档,其可以用来读docx文档,也可以用来写docx文档
 22  * XWPFParagraph代表文档、表格、标题等种的段落,由多个XWPFRun组成
 23  * XWPFRun代表具有同样风格的一段文本
 24  * XWPFTable代表一个表格
 25  * XWPFTableRow代表表格的一行
 26  * XWPFTableCell代表表格的一个单元格
 27  * XWPFChar 表示.docx文件中的图表
 28  * XWPFHyperlink 表示超链接
 29  * XWPFPicture 代表图片
 30  *
 31  *
 32  *
 33  */
 34 public class WorderToNewWordUtils {
 35 
 36     /**
 37      * 判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入
 38      * @param inputUrl 模板存放地址
 39      * @param textMap 需要替换的信息集合
 40      * @param excelDataBytes 生成了新的数据流  word格式, 存放容器
 41      * @return 成功返回true,失败返回false
 42      */
 43     public static boolean changWord(String inputUrl,
 44                                     Map<String, String> textMap, Map<String,byte[]> excelDataBytes) {
 45 
 46         //模板转换默认成功
 47         boolean changeFlag = true;
 48         ByteArrayOutputStream writeToBytes = null;
 49         try {
 50             //获取docx解析对象
 51             XWPFDocument document = new XWPFDocument(new FileInputStream(inputUrl));
 52             //解析替换文本段落对象
 53             WorderToNewWordUtils.changeText(document, textMap);
 54             //解析替换表格对象
 55             WorderToNewWordUtils.changeTable(document, textMap);
 56 
 57             //生成了新的数据流  word 格式
 58             writeToBytes = new ByteArrayOutputStream();
 59             document.write(writeToBytes);
 60             excelDataBytes.put(textMap.get("year") + textMap.get("month"), writeToBytes.toByteArray());
 61 
 62         } catch (IOException e) {
 63             e.printStackTrace();
 64             changeFlag = false;
 65         }finally{
 66             try {
 67                 if(writeToBytes!=null)
 68                 writeToBytes.close();
 69             } catch (IOException e) {
 70                 e.printStackTrace();
 71             }
 72         }
 73 
 74         return changeFlag;
 75 
 76     }
 77 
 78 
 79     /**
 80      * 替换段落文本
 81      * @param document docx解析对象
 82      * @param textMap 需要替换的信息集合
 83      */
 84     public static void changeText(XWPFDocument document, Map<String, String> textMap){
 85         //获取段落集合
 86         List<XWPFParagraph> paragraphs = document.getParagraphs();
 87 
 88         for (XWPFParagraph paragraph : paragraphs) {
 89             //判断此段落时候需要进行替换
 90             String text = paragraph.getText();
 91             if(checkText(text)){
 92                 List<XWPFRun> runs = paragraph.getRuns();
 93                 for (XWPFRun run : runs) {
 94                     //替换模板原来位置
 95                     run.setText(changeValue(run.toString(), textMap),0);
 96                 }
 97             }
 98         }
 99 
100     }
101 
102     /**
103      * 替换表格对象方法
104      * @param document docx解析对象
105      * @param textMap 需要替换的信息集合
106      */
107     private static void changeTable(XWPFDocument document, Map<String, String> textMap){
108         //获取表格对象集合
109         List<XWPFTable> tables = document.getTables();
110         for (int i = 0; i < tables.size(); i++) {
111             //只处理行数大于等于2的表格,且不循环表头
112             XWPFTable table = tables.get(i);
113             if(table.getRows().size()>1){
114                 //判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入
115                 if(checkText(table.getText())){
116                     List<XWPFTableRow> rows = table.getRows();
117                     //遍历表格,并替换模板
118                     eachTable(rows, textMap);
119                 }
120             }
121         }
122 
123 
124     }
125 
126 
127     /**
128      * 遍历表格
129      * @param rows 表格行对象
130      * @param textMap 需要替换的信息集合
131      */
132     private static void eachTable(List<XWPFTableRow> rows ,Map<String, String> textMap){
133         for (XWPFTableRow row : rows) {
134             List<XWPFTableCell> cells = row.getTableCells();
135             for (XWPFTableCell cell : cells) {
136                 //判断单元格是否需要替换
137                 if(checkText(cell.getText())){
138                     List<XWPFParagraph> paragraphs = cell.getParagraphs();
139                     for (XWPFParagraph paragraph : paragraphs) {
140                         List<XWPFRun> runs = paragraph.getRuns();
141                         for (XWPFRun run : runs) {
142                             run.setText(changeValue(run.toString(), textMap),0);
143                         }
144                     }
145                 }
146             }
147         }
148     }
149 
150 
151     /**
152      * 判断文本中时候包含$
153      * @param text 文本
154      * @return 包含返回true,不包含返回false
155      */
156     private static boolean checkText(String text){
157         boolean check  =  false;
158         if(text.indexOf("$")!= -1){
159             check = true;
160         }
161         return check;
162 
163     }
164 
165     /**
166      * 匹配传入信息集合与模板
167      * @param value 模板需要替换的区域
168      * @param textMap 传入信息集合
169      * @return 模板需要替换区域信息集合对应值
170      */
171     private static String changeValue(String value, Map<String, String> textMap){
172         Set<Entry<String, String>> textSets = textMap.entrySet();
173         for (Entry<String, String> textSet : textSets) {
174             //匹配模板与替换值 格式${key}
175             String key = "${"+textSet.getKey()+"}";
176             if(value.indexOf(key)!= -1){
177                 value = textSet.getValue();
178             }
179         }
180         //模板未匹配到区域替换为空
181         if(checkText(value)){
182             value = "0";
183         }
184         return value;
185     }
186 
187 
188 }

注意:

  1. html模板和word模板共用的数据模型
  2. 写这个功能前翻阅了大量的关于java导出word的博客,有大量的将word转为ftl格式再去操作,感觉不是很方便和直观。
  3. 上面的代码参考了 https://www.cnblogs.com/sun-flower1314/p/10128796.html,这里有使用POI对word大量的操作。
原文地址:https://www.cnblogs.com/xuebuhui/p/12036185.html