BokeWordUtils.java 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. package platform.common.util;
  2. import org.apache.poi.POIXMLDocument;
  3. import org.apache.poi.xwpf.usermodel.*;
  4. import javax.servlet.ServletOutputStream;
  5. import javax.servlet.http.HttpServletResponse;
  6. import java.io.File;
  7. import java.io.FileOutputStream;
  8. import java.io.IOException;
  9. import java.io.OutputStream;
  10. import java.net.URLEncoder;
  11. import java.util.*;
  12. /**
  13. * @author kevin
  14. * @since 2019/9/3 4:10 PM
  15. */
  16. public class BokeWordUtils {
  17. private XWPFDocument document;
  18. /**
  19. * 构造函数
  20. * @param inputUrl
  21. * @param tableList
  22. */
  23. public BokeWordUtils (String inputUrl, List<String[]> tableList){
  24. this(inputUrl, new HashMap<>(), tableList);
  25. }
  26. public BokeWordUtils (String inputUrl, Map<String, String> textMap, List<String[]> tableList){
  27. try {
  28. System.out.println("===============开始读取word模版===================");
  29. System.out.println(Thread.currentThread().getName() + "\t 模版路径:" + inputUrl);
  30. document = new XWPFDocument(POIXMLDocument.openPackage(inputUrl));
  31. //解析替换文本段落对象
  32. changeText(document, textMap);
  33. //解析替换表格对象
  34. changeTable(document, textMap, tableList);
  35. System.out.println("生成完成!");
  36. } catch (IOException e) {
  37. e.printStackTrace();
  38. }
  39. }
  40. /**
  41. * 根据模板生成新word文档
  42. * 判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入
  43. * @param inputUrl 模板存放地址
  44. * @param outputUrl 新文档存放地址
  45. * @param textMap 需要替换的信息集合
  46. * @param tableList 需要插入的表格信息集合
  47. */
  48. public static boolean changWord(String inputUrl, String outputUrl,
  49. Map<String, String> textMap, List<String[]> tableList) {
  50. //模板转换默认成功
  51. boolean changeFlag = true;
  52. try {
  53. //获取docx解析对象
  54. XWPFDocument document = new XWPFDocument(POIXMLDocument.openPackage(inputUrl));
  55. //解析替换文本段落对象
  56. BokeWordUtils.changeText(document, textMap);
  57. //解析替换表格对象
  58. BokeWordUtils.changeTable(document, textMap, tableList);
  59. //生成新的word
  60. File file = new File(outputUrl);
  61. FileOutputStream stream = new FileOutputStream(file);
  62. document.write(stream);
  63. stream.close();
  64. System.out.println("成功生成!");
  65. } catch (IOException e) {
  66. e.printStackTrace();
  67. changeFlag = false;
  68. }
  69. return changeFlag;
  70. }
  71. /**
  72. * 输出到客户端
  73. * @param fileName 输出文件名
  74. */
  75. public BokeWordUtils write(HttpServletResponse response, String fileName) throws IOException{
  76. response.reset();
  77. response.setContentType("application/octet-stream; charset=utf-8");
  78. response.setHeader("Content-Disposition", "attachment; filename="+ URLEncoder.encode(fileName, "UTF-8"));
  79. write(response.getOutputStream());
  80. return this;
  81. }
  82. /**
  83. * 输出数据流
  84. * @param os 输出数据流
  85. */
  86. public BokeWordUtils write(OutputStream os) throws IOException{
  87. document.write(os);
  88. return this;
  89. }
  90. /**
  91. * 替换段落文本
  92. * @param document docx解析对象
  93. * @param textMap 需要替换的信息集合
  94. */
  95. public static void changeText(XWPFDocument document, Map<String, String> textMap){
  96. //获取段落集合
  97. List<XWPFParagraph> paragraphs = document.getParagraphs();
  98. for (XWPFParagraph paragraph : paragraphs) {
  99. //判断此段落时候需要进行替换
  100. String text = paragraph.getText();
  101. if(checkText(text)){
  102. List<XWPFRun> runs = paragraph.getRuns();
  103. for (XWPFRun run : runs) {
  104. //替换模板原来位置
  105. // run.setText(changeValue(run.toString(), textMap),0);
  106. String textValue = changeValue(run.toString(), textMap);
  107. run.setText(textValue,0);
  108. }
  109. }
  110. }
  111. }
  112. /**
  113. * 替换表格对象方法
  114. * @param document docx解析对象
  115. * @param textMap 需要替换的信息集合
  116. * @param tableList 需要插入的表格信息集合
  117. */
  118. public static void changeTable(XWPFDocument document, Map<String, String> textMap,
  119. List<String[]> tableList){
  120. //获取表格对象集合
  121. List<XWPFTable> tables = document.getTables();
  122. for (int i = 0; i < tables.size(); i++) {
  123. //只处理行数大于等于2的表格,且不循环表头
  124. XWPFTable table = tables.get(i);
  125. //判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入
  126. if(checkText(table.getText())){
  127. List<XWPFTableRow> rows = table.getRows();
  128. //遍历表格,并替换模板
  129. eachTable(rows, textMap);
  130. }else{
  131. insertTable(table, tableList);
  132. }
  133. }
  134. }
  135. /**
  136. * 遍历表格
  137. * @param rows 表格行对象
  138. * @param textMap 需要替换的信息集合
  139. */
  140. public static void eachTable(List<XWPFTableRow> rows ,Map<String, String> textMap){
  141. for (XWPFTableRow row : rows) {
  142. List<XWPFTableCell> cells = row.getTableCells();
  143. for (XWPFTableCell cell : cells) {
  144. //判断单元格是否需要替换
  145. if(checkText(cell.getText())){
  146. List<XWPFParagraph> paragraphs = cell.getParagraphs();
  147. for (XWPFParagraph paragraph : paragraphs) {
  148. List<XWPFRun> runs = paragraph.getRuns();
  149. for (XWPFRun run : runs) {
  150. run.setText(changeValue(run.toString(), textMap),0);
  151. }
  152. }
  153. }
  154. }
  155. }
  156. }
  157. /**
  158. * 为表格插入数据,行数不够添加新行
  159. * @param table 需要插入数据的表格
  160. * @param tableList 插入数据集合
  161. */
  162. public static void insertTable(XWPFTable table, List<String[]> tableList){
  163. //创建行,根据需要插入的数据添加新行,不处理表头
  164. for(int i = 0; i < tableList.size(); i++){
  165. XWPFTableRow row =table.createRow();
  166. List<XWPFTableCell> cells = row.getTableCells();
  167. for(int j = 0; j < cells.size(); j++){
  168. XWPFTableCell cell = cells.get(j);
  169. cell.setText(tableList.get(i)[j]);
  170. }
  171. }
  172. //遍历表格插入数据
  173. // List<XWPFTableRow> rows = table.getRows();
  174. // for(int i = 1; i < rows.size(); i++){
  175. // XWPFTableRow newRow = table.getRow(i);
  176. // List<XWPFTableCell> cells = newRow.getTableCells();
  177. // for(int j = 0; j < cells.size(); j++){
  178. // XWPFTableCell cell = cells.get(j);
  179. // cell.setText(tableList.get(i-1)[j]);
  180. // }
  181. // }
  182. }
  183. /**
  184. * 判断文本中时候包含$
  185. * @param text 文本
  186. * @return 包含返回true,不包含返回false
  187. */
  188. public static boolean checkText(String text){
  189. boolean check = false;
  190. if(text.indexOf("$")!= -1){
  191. check = true;
  192. }
  193. return check;
  194. }
  195. /**
  196. * 匹配传入信息集合与模板
  197. * @param value 模板需要替换的区域
  198. * @param textMap 传入信息集合
  199. * @return 模板需要替换区域信息集合对应值
  200. */
  201. public static String changeValue(String value, Map<String, String> textMap){
  202. Set<Map.Entry<String, String>> textSets = textMap.entrySet();
  203. for (Map.Entry<String, String> textSet : textSets) {
  204. //匹配模板与替换值 格式${key}
  205. String key = "${"+textSet.getKey()+"}";
  206. if(value.indexOf(key)!= -1){
  207. // value = textSet.getValue();//全部参数替换
  208. value = value.replace(key, textSet.getValue());//仅替换参数
  209. }
  210. }
  211. //模板未匹配到区域替换为空
  212. if(checkText(value)){
  213. value = "";
  214. }
  215. return value;
  216. }
  217. public static void main(String[] args) {
  218. //模板文件地址
  219. String inputUrl = "/Users/xikaiwen/Downloads/annex6.docx";
  220. //新生产的模板文件
  221. String outputUrl = "/Users/xikaiwen/Downloads/annex6_new.docx";
  222. Map<String, String> testMap = new HashMap<String, String>();
  223. testMap.put("name", "小明");
  224. testMap.put("sex", "男");
  225. testMap.put("age", "18");
  226. testMap.put("address", "北京市");
  227. testMap.put("neirong", "好的内容");
  228. testMap.put("xuehao", "88888888");
  229. testMap.put("companyName", "软通");
  230. testMap.put("bigName", "项目大类");
  231. testMap.put("smileName", "项目大类-小类");
  232. testMap.put("phone", "18051103927");
  233. testMap.put("date", DateUtil.getTimeString(new Date()));
  234. List<String[]> tableList = new ArrayList<>();
  235. tableList.add(new String[]{"1","1mm","1开开","1uu", "5", "6", "7", "8", "9"});
  236. tableList.add(new String[]{"2","1mm","1开开","1uu", "5", "6", "7", "8", "9"});
  237. tableList.add(new String[]{"3","1mm","1开开","1uu", "5", "6", "7", "8", "9"});
  238. tableList.add(new String[]{"4","1mm","1开开","1uu", "5", "6", "7", "8", "9"});
  239. tableList.add(new String[]{"5","1mm","1开开","1uu", "5", "6", "7", "8", "9"});
  240. tableList.add(new String[]{"6","1mm","1开开","1uu", "5", "6", "7", "8", "9"});
  241. tableList.add(new String[]{"7","1mm","1开开","1uu", "5", "6", "7", "8", "9"});
  242. // tableList.add(new String[]{"2","2密码","2B","基金C"});
  243. // tableList.add(new String[]{"3","3看看","3B","基看C"});
  244. // tableList.add(new String[]{"4","4累了","4B","4谁说的"});
  245. BokeWordUtils.changWord(inputUrl, outputUrl, testMap, tableList);
  246. }
  247. }