| doc/print.md | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/product/print/config/CmnCode.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/product/print/service/PrintRealizeService.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/product/print/service/ide/IPrintRealizeService.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/product/print/util/CustomPictureRenderPolicy.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/product/print/util/DynamicTableRenderPolicy.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
doc/print.md
@@ -26,7 +26,7 @@ ### 子表标签 {{$~index~}}: 固定写法,输出子表行号 {{$~i~}}: 固定写法,输出子表行号 {{$字段名}}:输出子表中指定字段的值 ###  src/main/java/com/product/print/config/CmnCode.java
@@ -32,6 +32,9 @@ NOT_FIND_START_FLAG("表格中没有找到起始下标", 15), //子表格中没有找到对应的字段 NOT_FIND_CHILD_TABLE_FIELD("子表格中没有找到对应的字段", 16), GET_BEAN_FAIL("获取bean失败", 17), DEALT_FILE_PATH_IS_EMPTY("处理后的文件路径为空", 18), EXISTS_FILE_RECORD_BUT_NO_FILE("存在文件记录,但是未找到对应文件", 19), ; private String text; src/main/java/com/product/print/service/PrintRealizeService.java
@@ -10,10 +10,11 @@ import com.deepoove.poi.config.ConfigureBuilder; import com.deepoove.poi.data.TextRenderData; import com.deepoove.poi.data.style.Style; import com.deepoove.poi.render.RenderContext; import com.google.common.collect.Lists; import com.product.common.lang.StringUtils; import com.product.core.cache.DataPoolCacheImpl; import com.product.core.config.Global; import com.product.core.entity.DataEntity; import com.product.core.entity.DataTableEntity; import com.product.core.entity.FieldSetEntity; import com.product.core.exception.BaseException; @@ -30,17 +31,15 @@ import com.product.tool.flow.service.FlowDetailService; import com.product.util.BaseUtil; import com.product.util.SystemParamReplace; import org.apache.poi.xwpf.usermodel.XWPFTable; import org.apache.pdfbox.io.MemoryUsageSetting; import org.apache.pdfbox.multipdf.PDFMergerUtility; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.OutputStream; import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.UUID; import java.util.*; import java.util.stream.Collectors; @@ -121,17 +120,32 @@ /** * 打印传输pdf流到前端 * * @param fse 打印数据 * @param fseOrDte 打印数据 * @param response 响应 * @param isConvertPdf 是否转换为pdf * @throws BaseException */ @Override public void print(FieldSetEntity fse, HttpServletResponse response, boolean isConvertPdf) throws BaseException { //打印配置 FieldSetEntity printConfig = getPrintConfig(fse.getString("~" + CmnConst.PRINT_TEMP + "~")); public void print(DataEntity fseOrDte, HttpServletResponse response, boolean isConvertPdf) throws BaseException { FieldSetEntity fse; DataTableEntity dte; //打印配置 FieldSetEntity printConfig; if (fseOrDte.isFieldsetEntity()) { fse = (FieldSetEntity) fseOrDte; printConfig = getPrintConfig(getPrintTemplateField(fse)); } else if (fseOrDte.isDataTableEntity()) { dte = (DataTableEntity) fseOrDte; fse = dte.getFieldSetEntity(0); printConfig = getPrintConfig(getPrintTemplateField(fse)); } else { throw new BaseException(CmnCode.GET_BEAN_FAIL); } //获取到替换后的文件路径 (pdf文件或者word文件) String tempPdfFilePath = replaceTemplateFileOut(printConfig, fse, isConvertPdf); String tempPdfFilePath = replaceTemplateFileOut(printConfig, fseOrDte, isConvertPdf); if (StringUtils.isEmpty(tempPdfFilePath)) { throw new BaseException(CmnCode.DEALT_FILE_PATH_IS_EMPTY); } //获取文件名 String fileName = BaseUtil.ifNull(printConfig.getString(CmnConst.PRINT_FILE_NAME), printConfig.getString(CmnConst.PRINT_NAME)); if (isConvertPdf) { @@ -146,11 +160,27 @@ // 设置自定义头Content-Disposition response.setHeader("Content-Disposition", "attachment;filename=" + URLEncodeUtil.encode(fileName)); try ( OutputStream out = response.getOutputStream(); ) { FileUtil.writeToStream(new File(tempPdfFilePath), out); } catch (Exception e) { try (OutputStream out = response.getOutputStream();) { if (tempPdfFilePath.contains(",")) { // 更高效的方式:直接从文件合并到输出流 PDFMergerUtility merger = new PDFMergerUtility(); merger.setDestinationStream(response.getOutputStream()); String[] tempPdfFilePathArr = tempPdfFilePath.split(","); for (int i = 0; i < tempPdfFilePathArr.length; i++) { String singleTempPdfFilePath = tempPdfFilePathArr[i]; File file = new File(singleTempPdfFilePath); if (file.exists()) { merger.addSource(file); // 直接添加文件源 } } // 执行合并 merger.mergeDocuments(MemoryUsageSetting.setupMainMemoryOnly()); } else { FileUtil.writeToStream(new File(tempPdfFilePath), out); } } catch (Exception e) { e.printStackTrace(); throw new BaseException(CmnCode.PRINT_CONTENT_FAIL, e); } finally { @@ -159,8 +189,23 @@ System.out.println(absolutePath); file.delete(); } } /** * 获取打印模板字段 * @param fse * @return */ private String getPrintTemplateField(FieldSetEntity fse) { if (FieldSetEntity.isEmpty(fse)) { return null; } String printTemplateField = fse.getString("~" + CmnConst.PRINT_TEMP + "~"); if (StringUtils.isEmpty(printTemplateField)) { printTemplateField = fse.getString("~print_template~"); } return printTemplateField; } /** * 获取打印配置 @@ -183,75 +228,97 @@ * 替换模板文件并输出 * * @param printConf 打印配置 * @param fse 替换数据 * @param fseOrDte 替换数据 * @param isConvertPdf 是否转换为pdf * @return 替换后的文件路径 * @throws BaseException 异常 */ private String replaceTemplateFileOut(FieldSetEntity printConf, FieldSetEntity fse, boolean isConvertPdf) throws BaseException { private String replaceTemplateFileOut(FieldSetEntity printConf, DataEntity fseOrDte, boolean isConvertPdf) throws BaseException { FieldSetEntity fse = null; DataTableEntity dte = null; if (fseOrDte.isFieldsetEntity()) { fse = (FieldSetEntity) fseOrDte; } else if (fseOrDte.isDataTableEntity()) { dte = (DataTableEntity) fseOrDte; } else { throw new BaseException(CmnCode.GET_BEAN_FAIL); } if (fse != null) { dte = new DataTableEntity(); dte.addFieldSetEntity(fse); } Object[] fields = fse.getFields(); for (int i = 0; i < fields.length; i++) { String field = fields[i].toString(); FieldSetEntity metaEntity = fse.getMeta().getFieldMeta(field); if (metaEntity == null) { continue; } String fieldType = metaEntity.getString("field_type"); //判断是否拥有流程标识 if ("flowsign".equals(fieldType)) { if (StringUtils.equalsAny(fse.getString(field), "1", "2")) { //流程办理中或办结 获取流程意见 FieldSetEntity flowTask = getBaseDao().getFieldSetByFilter("product_sys_flow_task", "table_name=? and record_uuid=?", new Object[]{fse.getTableName(), fse.getUUID()}, false); if (flowTask != null) { String taskUuid = flowTask.getString(CmnConst.UUID); //获取流程意见 FlowDetailService flowDetailService = SpringUtil.getBean(FlowDetailService.class); JSONArray opinion = flowDetailService.getHistoryInfo(taskUuid); fse.setValue("~flow_opinion~", opinion); } } break; } } List<String> localTempPathList = Lists.newArrayList(); if (!DataTableEntity.isEmpty(dte)) { for (int m = 0; m < dte.getRows(); m++) { fse = dte.getFieldSetEntity(m); // 打印模板附件uuid String template_uuid = printConf.getString(CmnConst.PRINT_TEMPLATE); // 获取打印模板 File file = getTemplateFile(template_uuid); // 加载参照 打印时使用显示值 而不是实际值 getBaseDao().loadPromptData(fse); // 文件名前缀部分 Object tempKey = UUID.randomUUID(); // 替换后的word临时路径 String localTempPathWord = Global.getSystemConfig("temp.dir", "") + File.separator + "temp_print_" + tempKey + ".docx"; Object[] fields = fse.getFields(); for (int i = 0; i < fields.length; i++) { String field = fields[i].toString(); FieldSetEntity metaEntity = fse.getMeta().getFieldMeta(field); if (metaEntity == null) { continue; } String fieldType = metaEntity.getString("field_type"); //判断是否拥有流程标识 if ("flowsign".equals(fieldType)) { if (StringUtils.equalsAny(fse.getString(field), "1", "2")) { //流程办理中或办结 获取流程意见 FieldSetEntity flowTask = getBaseDao().getFieldSetByFilter("product_sys_flow_task", "table_name=? and record_uuid=?", new Object[]{fse.getTableName(), fse.getUUID()}, false); if (flowTask != null) { String taskUuid = flowTask.getString(CmnConst.UUID); //获取流程意见 FlowDetailService flowDetailService = SpringUtil.getBean(FlowDetailService.class); JSONArray opinion = flowDetailService.getHistoryInfo(taskUuid); fse.setValue("~flow_opinion~", opinion); } } break; } } replaceWord(localTempPathWord, file.getPath(), fse); file.delete(); // 打印模板附件uuid String template_uuid = printConf.getString(CmnConst.PRINT_TEMPLATE); // 获取打印模板 File file = getTemplateFile(template_uuid); // 加载参照 打印时使用显示值 而不是实际值 getBaseDao().loadPromptData(fse); // 文件名前缀部分 Object tempKey = UUID.randomUUID(); // 替换后的word临时路径 String localTempPathWord = Global.getSystemConfig("temp.dir", "") + File.separator + "temp_print_" + tempKey + ".docx"; String replaceParams = SystemParamReplace.replaceParams(Optional.ofNullable(printConf.getString(CmnConst.PRINT_FILE_NAME)).orElse(printConf.getString(CmnConst.PRINT_NAME)), fse); printConf.setValue(CmnConst.PRINT_FILE_NAME, replaceParams); if (isConvertPdf) { try { // 替换后的pdf临时路径 String localTempPathPdf = Global.getSystemConfig("temp.dir", "") + File.separator + "temp_print_" + tempKey + ".pdf"; //检查文件是否存在不存则创建 FileUtil.touch(localTempPathPdf); // 转换pdf PdfConcurrenceUtil.convertToPdf(localTempPathWord, localTempPathPdf, "docx"); // 删除word临时文件 File wordTemp = new File(localTempPathWord); if (wordTemp.exists()) { wordTemp.delete(); } return localTempPathPdf; } catch (Exception e) { throw new BaseException(CmnCode.CONVERT_PDF_ERROR, e); } finally { FileUtil.del(localTempPathWord); } } return localTempPathWord; replaceWord(localTempPathWord, file.getPath(), fse); file.delete(); String replaceParams = SystemParamReplace.replaceParams(Optional.ofNullable(printConf.getString(CmnConst.PRINT_FILE_NAME)).orElse(printConf.getString(CmnConst.PRINT_NAME)), fse); printConf.setValue(CmnConst.PRINT_FILE_NAME, replaceParams); if (isConvertPdf) { try { // 替换后的pdf临时路径 String localTempPathPdf = Global.getSystemConfig("temp.dir", "") + File.separator + "temp_print_" + tempKey + ".pdf"; //检查文件是否存在不存则创建 FileUtil.touch(localTempPathPdf); // 转换pdf PdfConcurrenceUtil.convertToPdf(localTempPathWord, localTempPathPdf, "docx"); // 删除word临时文件 File wordTemp = new File(localTempPathWord); if (wordTemp.exists()) { wordTemp.delete(); } localTempPathList.add(localTempPathPdf); } catch (Exception e) { throw new BaseException(CmnCode.CONVERT_PDF_ERROR, e); } finally { FileUtil.del(localTempPathWord); } } else { localTempPathList.add(localTempPathWord); } } } return BaseUtil.collection2String(localTempPathList); } /** @@ -274,18 +341,6 @@ Map<String, DataTableEntity> subDataMap = dataFse.getSubData(); ConfigureBuilder config = Configure.builder(); config.addPlugin('@', new FlowOpinionRenderPolicy(flowOpinion)); config.addPlugin('$', new com.deepoove.poi.policy.DynamicTableRenderPolicy() { @Override public void doRender(RenderContext<Object> context) throws Exception { return; } @Override public void render(XWPFTable table, Object data) throws Exception { return; } }); config.addPlugin('&', new CustomPictureRenderPolicy()); config.buildGrammerRegex("(#)?([\\w\\u4e00-\\u9fa5]+)(\\.?[\\w\\u4e00-\\u9fa5\\|]*)*(#)?"); TableEmptyHandler tableEmptyHandler = new TableEmptyHandler(); src/main/java/com/product/print/service/ide/IPrintRealizeService.java
@@ -1,6 +1,6 @@ package com.product.print.service.ide; import com.product.core.entity.FieldSetEntity; import com.product.core.entity.DataEntity; import com.product.core.exception.BaseException; import javax.servlet.http.HttpServletResponse; @@ -16,11 +16,10 @@ /** * 打印 * @param fse 打印数据 * @param fseOrDte 打印数据 * @param response 响应 * @param isConvertPdf 是否转换为pdf * @throws BaseException */ void print(FieldSetEntity fse, HttpServletResponse response,boolean isConvertPdf) throws BaseException; void print(DataEntity fseOrDte, HttpServletResponse response, boolean isConvertPdf) throws BaseException; } src/main/java/com/product/print/util/CustomPictureRenderPolicy.java
@@ -8,9 +8,12 @@ import com.deepoove.poi.data.Pictures; import com.deepoove.poi.policy.PictureRenderPolicy; import com.deepoove.poi.render.RenderContext; import com.product.common.lang.StringUtils; import com.product.core.dao.BaseDao; import com.product.core.entity.FieldSetEntity; import com.product.core.spring.context.SpringMVCContextHolder; import com.product.file.service.FileManagerService; import com.product.print.config.CmnCode; import java.io.File; import java.io.FileInputStream; @@ -31,9 +34,29 @@ public PictureRenderData cast(Object source) throws Exception { FileManagerService fileManagerService = SpringUtil.getBean(FileManagerService.class); String templateUid = source.toString(); if (StringUtils.isEmpty(templateUid)) { return null; } int width = 0; int height = 0; if (templateUid.contains(" ")) { String[] infoArr = templateUid.split(" "); templateUid = infoArr[0]; width = Integer.parseInt(infoArr[1]); height = Integer.parseInt(infoArr[2]); } BaseDao baseDao = SpringUtil.getBean(BaseDao.class); FieldSetEntity attachmentFse = baseDao.getFieldSetEntity("product_sys_attachments", templateUid, false); fileManagerService.getFile(templateUid); // 遇错跳过,默认使用透明背景不拦截,记录日志到文件 try { fileManagerService.getFile(templateUid); } catch (Exception e) { attachmentFse = baseDao.getFieldSetEntityByFilter("product_sys_attachments", "attachment_title=?", new Object[]{"sys_sp_deal_透明背景"}, false); fileManagerService.getFile(attachmentFse.getUUID()); SpringMVCContextHolder.getSystemLogger().error(String.format("%s-附件uuid:%s", CmnCode.EXISTS_FILE_RECORD_BUT_NO_FILE.getText(), templateUid)); } String fileName = attachmentFse.getString("file_name"); String type = fileName.substring(fileName.lastIndexOf(".") + 1); File file = fileManagerService.getFile(attachmentFse); @@ -47,7 +70,11 @@ } else if ("svg".equals(type)) { imgType = PictureType.SVG; } return converter.convert(Pictures.ofStream(new FileInputStream(file), imgType).create()); if (width > 0 && height > 0) { return converter.convert(Pictures.ofStream(new FileInputStream(file), imgType).size(width, height).create()); } else { return converter.convert(Pictures.ofStream(new FileInputStream(file), imgType).create()); } } @Override src/main/java/com/product/print/util/DynamicTableRenderPolicy.java
@@ -1,12 +1,12 @@ package com.product.print.util; import cn.hutool.core.collection.CollectionUtil; import com.deepoove.poi.exception.RenderException; import com.deepoove.poi.render.RenderContext; import com.deepoove.poi.template.ElementTemplate; import com.deepoove.poi.template.MetaTemplate; import com.deepoove.poi.template.run.RunTemplate; import com.deepoove.poi.util.TableTools; import com.google.common.collect.Maps; import com.product.common.lang.StringUtils; import com.product.core.exception.BaseException; import com.product.print.config.CmnCode; @@ -17,7 +17,9 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.util.*; import java.util.Base64; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -30,11 +32,10 @@ private String replaceKey; private final String indexKey = "~index~"; private final String indexKey = "~i~"; public DynamicTableRenderPolicy(String replaceKey) { this.replaceKey = replaceKey; } private List<MetaTemplate> metaTemplateList; @@ -64,159 +65,173 @@ @Override public void render(XWPFTable xwpfTable, Object data) throws Exception { if (xwpfTable == null) { return; } List<Map<String, Object>> subTableData = (List<Map<String, Object>>) data; List<XWPFTableRow> rows = xwpfTable.getRows(); //读取rows中的内容 String tableExpression = "{{" + this.replaceKey + "}}"; //获取表格起始行和结束行 int startRowIndex = -1; rows: for (int i = 0; i < rows.size(); i++) { XWPFTableRow row = rows.get(i); for (int j = 0; j < row.getTableCells().size(); j++) { XWPFTableCell cell = row.getTableCells().get(j); String text = cell.getText(); if (tableExpression.equals(text)) { startRowIndex = i; break rows; } try { if (xwpfTable == null) { return; } List<Map<String, Object>> subTableData = (List<Map<String, Object>>) data; List<XWPFTableRow> rows = xwpfTable.getRows(); //读取rows中的内容 String tableExpression = "{{" + this.replaceKey + "}}"; //获取表格起始行和结束行 int startRowIndex = -1; outer: for (int i = 0; i < rows.size(); i++) { XWPFTableRow row = rows.get(i); for (int j = 0; j < row.getTableCells().size(); j++) { XWPFTableCell cell = row.getTableCells().get(j); String text = cell.getText(); if (tableExpression.equals(text)) { startRowIndex = i; break outer; } } } if (startRowIndex == -1) { throw new BaseException(CmnCode.NOT_FIND_START_FLAG); } } } if (startRowIndex == -1) { throw new BaseException(CmnCode.NOT_FIND_START_FLAG); } //在表格中查找子表字段以{{$开头}}以}}结尾的内容 String regex = "\\{\\{\\$[a-zA-Z0-9_]+\\}\\}"; Pattern pattern = Pattern.compile(regex); //字段所在行 XWPFTableRow fieldRow = null; for (int i = startRowIndex; i < rows.size(); i++) { XWPFTableRow row = rows.get(i); for (int j = 0; j < row.getTableCells().size(); j++) { XWPFTableCell cell = row.getTableCells().get(j); String text = cell.getText(); Matcher matcher = pattern.matcher(text); if (matcher.find()) { fieldRow = row; i = rows.size(); break; } } } if (fieldRow == null) { throw new BaseException(CmnCode.NOT_FIND_CHILD_TABLE_FIELD); } //在表格中查找子表字段以{{$开头}}以}}结尾的内容 String regex = "\\{\\{\\$[a-zA-Z0-9_]+\\}\\}"; Pattern pattern = Pattern.compile(regex); //字段所在行 XWPFTableRow fieldRow = null; for (int i = startRowIndex; i < rows.size(); i++) { XWPFTableRow row = rows.get(i); for (int j = 0; j < row.getTableCells().size(); j++) { XWPFTableCell cell = row.getTableCells().get(j); String text = cell.getText(); Matcher matcher = pattern.matcher(text); if (matcher.find()) { fieldRow = row; i = rows.size(); break; } } } if (fieldRow == null) { throw new BaseException(CmnCode.NOT_FIND_CHILD_TABLE_FIELD); } //读取最后行每个单元格的值,调用getReplaceKey方法获取表达式中的值 String[] fieldNames = new String[fieldRow.getTableCells().size()]; for (int i = 0; i < fieldRow.getTableCells().size(); i++) { XWPFTableCell cell = fieldRow.getTableCells().get(i); String text = cell.getText(); String replaceKey = getReplaceKey(text); //获取表达式中的值 if (StringUtils.isEmpty(replaceKey)) { //设置单元格为空值 replaceKey = ""; } fieldNames[i] = replaceKey; } //读取最后行每个单元格的值,调用getReplaceKey方法获取表达式中的值 String[] fieldNames = new String[fieldRow.getTableCells().size()]; for (int i = 0; i < fieldRow.getTableCells().size(); i++) { XWPFTableCell cell = fieldRow.getTableCells().get(i); String text = cell.getText(); String replaceKey = getReplaceKey(text); //获取表达式中的值 if (StringUtils.isEmpty(replaceKey)) { //设置单元格为空值 replaceKey = ""; } fieldNames[i] = replaceKey; } if (subTableData != null && subTableData.size() > 0) { for (int i = 0; i < subTableData.size(); i++) { Map<String, Object> map = subTableData.get(i); XWPFTableRow row; if (i == 0) { row = fieldRow; } else { int fieldRowIndex = xwpfTable.getRows().indexOf(fieldRow); //创建一行在fieldRowIndex下面 row = xwpfTable.insertNewTableRow(fieldRowIndex + i); PrintPoiUtil.copyTableRow(row, fieldRow); } //遍历字段每个字段创建一个单元格 for (int j = 0; j < fieldNames.length; j++) { //当前单元格 XWPFTableCell cell = row.getCell(j); //清空单元格内容 XWPFParagraph xwpfParagraph = cell.addParagraph(); int index = cell.getParagraphs().indexOf(xwpfParagraph); PrintPoiUtil.copyParagraph(xwpfParagraph, cell.getParagraphs().get(0)); //设置段落文字对齐方式 xwpfParagraph.setAlignment(cell.getParagraphs().get(0).getAlignment()); //删除所有的run for (int k = xwpfParagraph.getRuns().size() - 1; k >= 0; k--) { xwpfParagraph.removeRun(k); } XWPFRun xwpfRun = xwpfParagraph.createRun(); PrintPoiUtil.copyRun(xwpfRun, cell.getParagraphs().get(0).getRuns().get(0)); //删除cell中的段落但排除新增的段落 for (int k = cell.getParagraphs().size() - 1; k >= 0; k--) { if (k < index) { cell.removeParagraph(k); } } //判断是否是序号列 if (indexKey.equals(fieldNames[j])) { cell.setText(String.valueOf(i + 1)); continue; } Object value = map.get(fieldNames[j]); if (value == null) { value = ""; } // if ("lx_flow_opinion".equals(this.replaceKey) && "opinion".equals(fieldNames[j])) { // //将流程节点处理人加到意见栏中 // value = "[" + map.get("actual_person") + "] " + value; // } xwpfRun.setText(value.toString(), 0); if ("lx_flow_opinion".equals(this.replaceKey) && "opinion".equals(fieldNames[j])) { if (!StringUtils.isEmpty(map.get("sign_attachment_uuid"))) { //意见框 插入签名图片到单元格右下角位置 xwpfParagraph = cell.addParagraph(); xwpfParagraph.setAlignment(ParagraphAlignment.RIGHT); XWPFRun run = xwpfParagraph.createRun(); String signAttachmentBase64 = map.get("sign_attachment_uuid").toString(); //将base64转换字节流 byte[] bytes = Base64.getDecoder().decode(signAttachmentBase64.split(",")[1]); //将字节流转换为输入流 InputStream inputStream = new ByteArrayInputStream(bytes); try { //换行插入图片 run.addPicture(inputStream, XWPFDocument.PICTURE_TYPE_PNG, "sign.png", Units.toEMU(50), Units.toEMU(20)); run.addBreak(); run.setText("" + map.get("deal_time").toString().substring(0, 16)); inputStream.close(); } catch (InvalidFormatException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } else { xwpfParagraph = cell.addParagraph(); xwpfParagraph.setAlignment(ParagraphAlignment.RIGHT); XWPFRun run = xwpfParagraph.createRun(); run.setText((String) map.get("actual_person")); run.addBreak(); run.setText(map.get("deal_time").toString().substring(0, 16)); } if (subTableData != null && subTableData.size() > 0) { int rowCount; for (int i = 0, count = 0; i < subTableData.size(); i += rowCount, count++) { rowCount = 1; Map<String, Object> map = subTableData.get(i); XWPFTableRow row; if (i == 0) { row = fieldRow; } else { int fieldRowIndex = xwpfTable.getRows().indexOf(fieldRow); //创建一行在fieldRowIndex下面 row = xwpfTable.insertNewTableRow(fieldRowIndex + count); PrintPoiUtil.copyTableRow(row, fieldRow); } //遍历字段每个字段创建一个单元格 for (int j = 0; j < fieldNames.length; j++) { String fieldName = fieldNames[j]; if (fieldName.contains(" ")) { int curIndex = Integer.parseInt(fieldName.substring(fieldName.indexOf(" ") + 1)); if (curIndex > 1 && curIndex > rowCount) { map = i + 1 == subTableData.size() ? Maps.newHashMap() : subTableData.get(i + 1); rowCount = curIndex; } fieldName = fieldName.substring(0, fieldName.indexOf(" ")); } //当前单元格 XWPFTableCell cell = row.getCell(j); //清空单元格内容 XWPFParagraph xwpfParagraph = cell.addParagraph(); int index = cell.getParagraphs().indexOf(xwpfParagraph); PrintPoiUtil.copyParagraph(xwpfParagraph, cell.getParagraphs().get(0)); //设置段落文字对齐方式 xwpfParagraph.setAlignment(cell.getParagraphs().get(0).getAlignment()); //删除所有的run for (int k = xwpfParagraph.getRuns().size() - 1; k >= 0; k--) { xwpfParagraph.removeRun(k); } XWPFRun xwpfRun = xwpfParagraph.createRun(); PrintPoiUtil.copyRun(xwpfRun, cell.getParagraphs().get(0).getRuns().get(0)); //删除cell中的段落但排除新增的段落 for (int k = cell.getParagraphs().size() - 1; k >= 0; k--) { if (k < index) { cell.removeParagraph(k); } } //判断是否是序号列 if (indexKey.equals(fieldName)) { if (map.isEmpty()) { xwpfRun.setText("", 0); } else { xwpfRun.setText(String.valueOf(i + rowCount), 0); } continue; } Object value = map.get(fieldName); if (value == null) { value = ""; } xwpfRun.setText(value.toString(), 0); if ("lx_flow_opinion".equals(this.replaceKey) && "opinion".equals(fieldName)) { if (!StringUtils.isEmpty(map.get("sign_attachment_uuid"))) { //意见框 插入签名图片到单元格右下角位置 xwpfParagraph = cell.addParagraph(); xwpfParagraph.setAlignment(ParagraphAlignment.RIGHT); XWPFRun run = xwpfParagraph.createRun(); String signAttachmentBase64 = map.get("sign_attachment_uuid").toString(); //将base64转换字节流 byte[] bytes = Base64.getDecoder().decode(signAttachmentBase64.split(",")[1]); //将字节流转换为输入流 InputStream inputStream = new ByteArrayInputStream(bytes); try { //换行插入图片 run.addPicture(inputStream, XWPFDocument.PICTURE_TYPE_PNG, "sign.png", Units.toEMU(50), Units.toEMU(20)); run.addBreak(); run.setText("" + map.get("deal_time").toString().substring(0, 16)); inputStream.close(); } catch (InvalidFormatException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } else { xwpfParagraph = cell.addParagraph(); xwpfParagraph.setAlignment(ParagraphAlignment.RIGHT); XWPFRun run = xwpfParagraph.createRun(); run.setText((String) map.get("actual_person")); run.addBreak(); run.setText(map.get("deal_time").toString().substring(0, 16)); } } } } } } else { } } } else { // 删除fieldRow int index = xwpfTable.getRows().indexOf(fieldRow); xwpfTable.removeRow(index); } //删除起始行 xwpfTable.removeRow(startRowIndex); int index = xwpfTable.getRows().indexOf(fieldRow); xwpfTable.removeRow(index); } //删除起始行 xwpfTable.removeRow(startRowIndex); } catch (Exception e) { e.printStackTrace(); } } /**