公司HDFS网盘下载word模板,实现对模板的数据填充和创建临时文件上传
1 /** 2 * 获取通报单模板,填充模板,并上传网盘返回fileId 3 */ 4 private JSONObject getReport(String reportNo, String projectName, String notificationObject, String notificationReason, HttpServletRequest request) { 5 JSONObject returnJson = new JSONObject(); 6 7 RestTemplate restTemplate = new RestTemplate(); 8 HttpHeaders httpHeaders = new HttpHeaders(); 9 HttpEntity httpEntity = new HttpEntity(httpHeaders); 10 InputStream in = null; 11 ByteArrayOutputStream out = new ByteArrayOutputStream(); 12 //填充模板的数据 13 JSONObject params = new JSONObject(); 14 JSONObject tableData = new JSONObject(); 15 tableData.put("number", reportNo); 16 tableData.put("date", DateUtil.format(new Date(), "yyyy-MM-dd").toString()); 17 tableData.put("title", projectName); 18 tableData.put("target", notificationObject); 19 tableData.put("reason", notificationReason); 20 params.put("tableData", tableData); 21 22 String fileId = null; 23 FileOutputStream fos = null; 24 BufferedOutputStream bos = null; 25 File fi = null; 26 try { 27 ResponseEntity<byte[]> getTempResponse = restTemplate.exchange(netdiscIP + netdiscDownload + reportTempFileId, HttpMethod.GET, httpEntity, byte[].class); 28 ByteArrayInputStream inputStream = new ByteArrayInputStream(getTempResponse.getBody()); 29 PoiWordUtils.execute(inputStream, out, params); 30 byte[] bytes = out.toByteArray(); 31 HttpHeaders headers = new HttpHeaders(); 32 //设置名字 33 String downloadName = "督查通报建议单.docx"; 34 //解决chrome/firefox/ie浏览器压缩包名字含有中文时乱码的问题 35 String agent = request.getHeader("USER-AGENT"); 36 if (agent.contains("MSIE") || agent.contains("Trident")) { 37 downloadName = java.net.URLEncoder.encode(downloadName, StandardCharsets.UTF_8.toString()); 38 } else { 39 downloadName = new String(downloadName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1); 40 } 41 headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment;fileName=\"" + downloadName + "\""); 42 headers.add(HttpHeaders.CONNECTION, "close"); 43 44 //创建临时文件上传 45 String tempFileName = "督查通报建议单_" + System.currentTimeMillis(); 46 fi = File.createTempFile(tempFileName, ".docx"); 47 fos = new FileOutputStream(fi); 48 bos = new BufferedOutputStream(fos); 49 bos.write(bytes); 50 51 //设置请求头 52 HttpHeaders requestHeaders = new HttpHeaders(); 53 MediaType type = MediaType.parseMediaType("multipart/form-data"); 54 requestHeaders.setContentType(type); 55 System.out.println(fi); 56 System.out.println(fi.getName()); 57 58 //设置请求体,注意是LinkedMultiValueMap 59 FileInputStream input = new FileInputStream(fi); 60 MultipartFile multipartFile = new MockMultipartFile("file", fi.getName(), "text/plain", IOUtils.toByteArray(input)); 61 HttpClientResult result = HttpClientUtils.doPostFile(netdiscIP + netdiscUpload, multipartFile); 62 JSONObject object = JSONObject.parseObject(result.getContent()); 63 if (object != null && object.getInteger("code") == 200) { 64 fileId = object.getString("data"); 65 } 66 returnJson.put("fileName",tempFileName + ".docx"); 67 returnJson.put("fileId",fileId ); 68 } catch (Exception e) { 69 throw new RuntimeException(e.getMessage()); 70 } finally { 71 try { 72 if (bos != null) { 73 try { 74 bos.close(); 75 } catch (IOException e1) { 76 e1.printStackTrace(); 77 } 78 } 79 if (fos != null) { 80 try { 81 fos.close(); 82 } catch (IOException e1) { 83 e1.printStackTrace(); 84 } 85 } 86 if (in != null) { 87 in.close(); 88 } 89 fi.delete(); 90 out.close(); 91 } catch (IOException e) { 92 throw new RuntimeException(e.getMessage()); 93 } 94 } 95 return returnJson; 96 }
PoiWordUtils:
1 @Slf4j 2 public class PoiWordUtils { 3 4 /** 5 * 顿号 6 */ 7 private static final String DUNHAO = "、"; 8 9 /** 10 * 执行 11 * 12 * @param in 模板输入流 13 * @param out 文件输出流 14 * @param params params 15 * @Author LIZHIQIANG 16 * @Date Create in 2020/1/14 9:58 17 */ 18 public static void execute(InputStream in, OutputStream out, JSONObject params) { 19 try { 20 XWPFDocument document = new XWPFDocument(in); 21 //需要循环的段落${listRow}开头,暂定最多三个 22 List<XWPFParagraph> targetParagraphs1 = new ArrayList<>(); 23 List<XWPFParagraph> targetParagraphs2 = new ArrayList<>(); 24 List<XWPFParagraph> targetParagraphs3 = new ArrayList<>(); 25 List<IBodyElement> bodyElements = document.getBodyElements(); 26 for (IBodyElement element : bodyElements) { 27 //文本段落对象 28 if (element instanceof XWPFParagraph) { 29 XWPFParagraph paragraph = (XWPFParagraph) element; 30 //段落内容 31 String paragraphText = paragraph.getParagraphText(); 32 33 //空段落跳过 34 if (paragraphText.isEmpty()) { 35 continue; 36 } 37 //需要循环的段落 38 if (paragraphText.startsWith("${listRow1}")) { 39 targetParagraphs1.add(paragraph); 40 continue; 41 } 42 if (paragraphText.startsWith("${listRow2}")) { 43 targetParagraphs2.add(paragraph); 44 continue; 45 } 46 if (paragraphText.startsWith("${listRow3}")) { 47 targetParagraphs3.add(paragraph); 48 continue; 49 } 50 //处理普通段落 51 processParagraph(paragraph, params); 52 } else if (element instanceof XWPFTable) { 53 XWPFTable table = (XWPFTable) element; 54 List<XWPFTableRow> rows = table.getRows(); 55 String tableDataString = params.getString("tableData"); 56 JSONObject tableData = JSON.parseObject(tableDataString); 57 System.out.println(JSON.toJSONString(tableData,true)); 58 if (tableData == null) { 59 continue; 60 } 61 //需要循环的tableRows 62 List<XWPFTableRow> targetTableRows = new ArrayList<>(); 63 List<Integer> targetTableRowsPos = new ArrayList<>(); 64 for (int i = 0; i < rows.size(); i++) { 65 XWPFTableRow row = rows.get(i); 66 List<XWPFTableCell> cells = row.getTableCells(); 67 String firstParagraphText2 = cells.get(0).getParagraphs().get(0).getParagraphText(); 68 String firstParagraphText = cells.get(0).getParagraphs().get(0).getText(); 69 if (firstParagraphText.startsWith("${listTables")) { 70 targetTableRows.add(row); 71 targetTableRowsPos.add(i); 72 continue; 73 } 74 for (XWPFTableCell cell : cells) { 75 List<XWPFParagraph> paragraphs = cell.getParagraphs(); 76 for (XWPFParagraph paragraph : paragraphs) { 77 processParagraph(paragraph, tableData); 78 } 79 } 80 } 81 processTableRows(table, targetTableRows, targetTableRowsPos, tableData); 82 } 83 84 } 85 //处理循环段落 86 processParagraphs(document, targetParagraphs1, params, "1"); 87 processParagraphs(document, targetParagraphs2, params, "2"); 88 processParagraphs(document, targetParagraphs3, params, "3"); 89 document.write(out); 90 91 } catch (IOException e) { 92 e.printStackTrace(); 93 } 94 } 95 96 /** 97 * 处理普通段落 98 * 99 * @param paragraph paragraph 100 * @param params params 101 * @Author LIZHIQIANG 102 * @Date Create in 2020/1/14 9:38 103 */ 104 private static void processParagraph(XWPFParagraph paragraph, JSONObject params) { 105 106 List<XWPFRun> runs = paragraph.getRuns(); 107 //需要循环替换的单元 108 List<XWPFRun> targetRuns1 = new ArrayList<>(); 109 List<XWPFRun> targetRuns2 = new ArrayList<>(); 110 List<XWPFRun> targetRuns3 = new ArrayList<>(); 111 for (XWPFRun run : runs) { 112 String runKey = run.text(); 113 System.out.println(runKey); 114 if (!runKey.startsWith("${") || !runKey.endsWith("}")) { 115 continue; 116 } 117 if ("${#}".equals(runKey)) { 118 run.setText("", 0); 119 continue; 120 } 121 if ("${listTables1}".equals(runKey)) { 122 run.setText("", 0); 123 continue; 124 } 125 if (runKey.startsWith("${listRow")) { 126 run.setText("", 0); 127 continue; 128 } 129 //添加需要循环的单元 130 if (runKey.startsWith("${listRuns1")) { 131 targetRuns1.add(run); 132 continue; 133 } 134 if (runKey.startsWith("${listRuns2")) { 135 targetRuns2.add(run); 136 continue; 137 } 138 if (runKey.startsWith("${listRuns3")) { 139 targetRuns3.add(run); 140 continue; 141 } 142 String key = runKey.replace("${", "").replace("}", ""); 143 String value = params.getString(key); 144 if (!StringUtils.isEmpty(value)) { 145 run.setText(value, 0); 146 } else { 147 run.setText("", 0); 148 log.warn("处理普通段落单元失败:{},找不到替换数据", runKey); 149 } 150 } 151 //处理需要循环的单元 152 processRuns(paragraph, targetRuns1, params, "1"); 153 processRuns(paragraph, targetRuns2, params, "2"); 154 processRuns(paragraph, targetRuns3, params, "3"); 155 } 156 157 /** 158 * 处理需要循环的单元 159 * 160 * @param paragraph paragraph 161 * @param targetRuns targetRuns 162 * @param params params 163 * @return void 164 * @Author LIZHIQIANG 165 * @Date Create in 2020/3/1 18:06 166 */ 167 private static void processRuns(XWPFParagraph paragraph, List<XWPFRun> targetRuns, JSONObject params, String sorting) { 168 169 if (targetRuns.isEmpty() || params.isEmpty()) { 170 return; 171 } 172 //默认key 173 String defaultKey = "listRuns" + sorting; 174 JSONArray jsonArray = params.getJSONArray(defaultKey); 175 //循环需要替换的数据 176 for (int i = 0; i < jsonArray.size(); i++) { 177 Object data = jsonArray.get(i); 178 //参数 一次循环的参数 179 JSONObject param = JSON.parseObject(data.toString()); 180 //循环需要替换的单元 181 for (XWPFRun run : targetRuns) { 182 183 String runKey = run.text(); 184 XWPFRun newRun = paragraph.createRun(); 185 CTRPr rPr = run.getCTR().getRPr(); 186 newRun.getCTR().setRPr(rPr); 187 //处理顿号 188 if (runKey.equals("${" + defaultKey + "DUNHAO}")) { 189 if (i == jsonArray.size() - 1) { 190 newRun.setText("", 0); 191 continue; 192 } 193 newRun.setText(DUNHAO); 194 continue; 195 } 196 String key = runKey.replace("${", "").replace("}", ""); 197 String value = param.getString(key); 198 if (!StringUtils.isEmpty(value)) { 199 newRun.setText(value); 200 } else { 201 log.warn("处理循环单元失败:{},找不到对应值", runKey); 202 newRun.setText("", 0); 203 } 204 205 } 206 } 207 for (XWPFRun run : targetRuns) { 208 run.setText("", 0); 209 } 210 211 } 212 213 /** 214 * 处理循环段落(新增段落后删模板段落) 215 * 216 * @param document document 217 * @param targetParagraphs targetParagraphs 218 * @param params params 219 * @Author LIZHIQIANG 220 * @Date Create in 2020/1/14 9:38 221 */ 222 private static void processParagraphs(XWPFDocument document, List<XWPFParagraph> targetParagraphs, JSONObject params, String sorting) { 223 224 if (targetParagraphs.isEmpty() || params.isEmpty()) { 225 return; 226 } 227 String listKey = "listRow" + sorting; 228 JSONArray jsonArray = params.getJSONArray(listKey); 229 if (jsonArray == null) { 230 return; 231 } 232 233 //document.insertNewParagraph(cursor) 插到这个光标前面 所以反转 234 Collections.reverse(targetParagraphs); 235 Collections.reverse(jsonArray); 236 //需要追加的此段落后 最后一个 237 XWPFParagraph lastParagraph = document.getParagraphArray(document.getPosOfParagraph(targetParagraphs.get(0))); 238 //循环需要替换的数据 239 // for (int i = 0; i < jsonArray.size(); i++) { 240 // Object data = jsonArray.get(i); 241 // //参数 一次循环的参数 242 // JSONObject param = JSON.parseObject(data.toString()); 243 // System.out.println(JSON.toJSONString(param,true)); 244 // for (XWPFParagraph paragraph : targetParagraphs) { 245 // System.out.println("处理段落:"+paragraph.getText()); 246 // //根据光标插入段落 247 // //需要追加的此段落光标后 最后一个 248 // XmlCursor cursor = lastParagraph.getCTP().newCursor(); 249 // XWPFParagraph newPar = document.insertNewParagraph(cursor); 250 // 251 // lastParagraph = newPar; 252 // //重置光标 最后插入的光标是这个 253 // //获取段落对象的样式的ppr标签 254 // CTPPr pPr = paragraph.getCTP().getPPr(); 255 // newPar.getCTP().setPPr(pPr); 256 // List<XWPFRun> runs = paragraph.getRuns(); 257 // 258 // //需要循环替换的单元 259 // List<XWPFRun> targetRuns1 = new ArrayList<>(); 260 // List<XWPFRun> targetRuns2 = new ArrayList<>(); 261 // List<XWPFRun> targetRuns3 = new ArrayList<>(); 262 // for (XWPFRun run : runs) { 263 // String runKey = run.text(); 264 // CTRPr rPr = run.getCTR().getRPr(); 265 // XWPFRun newRun = newPar.createRun(); 266 // newRun.getCTR().setRPr(rPr); 267 // if (!runKey.startsWith("${") || !runKey.endsWith("}")) { 268 // newRun.setText(runKey); 269 // continue; 270 // } 271 // //添加需要循环的单元 272 // if (runKey.startsWith("${listRuns1")) { 273 // targetRuns1.add(run); 274 // continue; 275 // } 276 // if (runKey.startsWith("${listRuns2")) { 277 // targetRuns2.add(run); 278 // continue; 279 // } 280 // if (runKey.startsWith("${listRuns3")) { 281 // targetRuns3.add(run); 282 // continue; 283 // } 284 // if (("${" + listKey + "}").equals(runKey)) { 285 // newRun.setText(""); 286 // continue; 287 // } 288 // if ("${#}".equals(runKey)) { 289 // run.setText("", 0); 290 // continue; 291 // } 292 // String key = runKey.replace("${", "").replace("}", ""); 293 // String value = param.getString(key); 294 // if (!StringUtils.isEmpty(value)) { 295 // newRun.setText(value); 296 //// System.out.println("处理单元:"+runKey+" > "+value); 297 // continue; 298 // } else { 299 // log.warn("处理循环模板段落单元失败:{},找不到对应值", runKey); 300 // } 301 // newRun.setText(runKey); 302 // } 303 // //===处理需要循环的单元 304 // processRuns(newPar, targetRuns1, param, "1"); 305 // processRuns(newPar, targetRuns2, param, "2"); 306 // processRuns(newPar, targetRuns3, param, "3"); 307 // 308 // } 309 // } 310 //删除模板集合段落 311 XmlCursor lastCursor = lastParagraph.getCTP().newCursor(); 312 for (Object data : jsonArray) { 313 JSONObject param = JSON.parseObject(data.toString()); 314 for (XWPFParagraph paragraph : targetParagraphs) { 315 //根据光标插入段落 316 XWPFParagraph newPar = document.insertNewParagraph(lastCursor); 317 //重置光标 最后插入的光标是这个 318 lastCursor = newPar.getCTP().newCursor(); 319 //复制段落 320 copyParagraph(paragraph, newPar); 321 //处理普通段落 322 processParagraph(newPar, param); 323 } 324 } 325 for (XWPFParagraph paragraph : targetParagraphs) { 326 document.removeBodyElement(document.getPosOfParagraph(paragraph)); 327 } 328 } 329 330 /** 331 * 处理循环的表格行 332 * 333 * @param table table 334 * @param targetTableRows targetTableRows 335 * @param targetTableRowsPos targetTableRowsPos 336 * @param params params 337 * @return void 338 * @Author LIZHIQIANG 339 * @Date Create in 2020/3/5 20:56 340 */ 341 private static void processTableRows(XWPFTable table, List<XWPFTableRow> targetTableRows, List<Integer> targetTableRowsPos, JSONObject params) { 342 if (targetTableRows.isEmpty() || params.isEmpty()) { 343 return; 344 } 345 //默认key 346 String defaultKey = "listTables1"; 347 JSONArray jsonArray = params.getJSONArray(defaultKey); 348 if (jsonArray == null) { 349 return; 350 } 351 352 for (int i = 0; i < targetTableRows.size(); i++) { 353 XWPFTableRow row = targetTableRows.get(i); 354 //循环需要替换的数据 355 for (Object data : jsonArray) { 356 //参数 一次循环的参数 357 JSONObject param = JSON.parseObject(data.toString()); 358 XWPFTableRow newRow = table.createRow(); 359 copyTableRow(row, newRow); 360 List<XWPFTableCell> newRowCells = newRow.getTableCells(); 361 for (XWPFTableCell newRowCell : newRowCells) { 362 List<XWPFParagraph> paragraphs = newRowCell.getParagraphs(); 363 for (XWPFParagraph paragraph : paragraphs) { 364 processParagraph(paragraph, param); 365 } 366 } 367 } 368 table.removeRow(targetTableRowsPos.get(i)); 369 } 370 } 371 372 373 /** 374 * 复制单元 375 * 376 * @param target target 377 * @param source source 378 */ 379 private static void copyRun(XWPFRun source, XWPFRun target) { 380 // 设置run属性 381 target.getCTR().setRPr(source.getCTR().getRPr()); 382 // 设置文本 383 target.setText(source.text()); 384 } 385 386 /** 387 * 复制段落 388 * 389 * @param source 源段落 390 * @param target 目标段落 391 */ 392 private static void copyParagraph(XWPFParagraph source, XWPFParagraph target) { 393 // 设置run属性 394 target.getCTP().setPPr(source.getCTP().getPPr()); 395 //清除新段落的单元 396 List<XWPFRun> targetRuns = target.getRuns(); 397 if (targetRuns != null && targetRuns.size() > 0) { 398 for (int pos = 0; pos < targetRuns.size(); pos++) { 399 target.removeRun(pos); 400 } 401 } 402 //复制源段落的单元到目标段落 403 for (XWPFRun sourceRun : source.getRuns()) { 404 XWPFRun targetRun = target.createRun(); 405 copyRun(sourceRun, targetRun); 406 } 407 } 408 409 /** 410 * 复制表格列 411 * 412 * @param source 源 413 * @param target 目标 414 */ 415 private static void copyTableCell(XWPFTableCell source, XWPFTableCell target) { 416 // 设置TableCell属性 417 target.getCTTc().setTcPr(source.getCTTc().getTcPr()); 418 419 List<XWPFParagraph> targetParagraphs = target.getParagraphs(); 420 if (targetParagraphs != null && targetParagraphs.size() > 0) { 421 for (int pos = 0; pos < targetParagraphs.size(); pos++) { 422 target.removeParagraph(pos); 423 } 424 } 425 List<XWPFParagraph> sourceParagraphs = source.getParagraphs(); 426 for (XWPFParagraph sourceParagraph : sourceParagraphs) { 427 XWPFParagraph targetParagraph = target.addParagraph(); 428 copyParagraph(sourceParagraph, targetParagraph); 429 } 430 } 431 432 /** 433 * 复制表格行 434 * 435 * @param source 源 436 * @param target 目标 437 */ 438 private static void copyTableRow(XWPFTableRow source, XWPFTableRow target) { 439 // 设置TableRow属性 440 target.getCtRow().setTrPr(source.getCtRow().getTrPr()); 441 442 List<XWPFTableCell> sourceCells = source.getTableCells(); 443 List<XWPFTableCell> targetCells = target.getTableCells(); 444 //复制列及其属性和内容 445 for (int pos = 0; pos < sourceCells.size(); pos++) { 446 XWPFTableCell sourceCell = sourceCells.get(pos); 447 XWPFTableCell targetCell = targetCells.get(pos); 448 copyTableCell(sourceCell, targetCell); 449 } 450 } 451 452 }