6c
10 天以前 cfd0903dc0cfc7ffd39c2caa101f31a50441d39c
已送审保养打印;
列表批量打印
已修改6个文件
201 ■■■■ 文件已修改
doc/print.md 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/product/print/config/CmnCode.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/product/print/service/PrintRealizeService.java 113 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/product/print/service/ide/IPrintRealizeService.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/product/print/util/CustomPictureRenderPolicy.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/product/print/util/DynamicTableRenderPolicy.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/print.md
@@ -26,7 +26,7 @@
### 子表标签
        {{$~index~}}: 固定写法,输出子表行号
        {{$~i~}}: 固定写法,输出子表行号
        {{$字段名}}:输出子表中指定字段的值
### ![img.png](img.png)
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 {
    public void print(DataEntity fseOrDte, HttpServletResponse response, boolean isConvertPdf) throws BaseException {
        FieldSetEntity fse;
        DataTableEntity dte;
        //打印配置
        FieldSetEntity printConfig = getPrintConfig(fse.getString("~" + CmnConst.PRINT_TEMP + "~"));
        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,10 +160,26 @@
        // 设置自定义头Content-Disposition
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncodeUtil.encode(fileName));
        try (
                OutputStream out = response.getOutputStream();
        ) {
        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);
@@ -159,7 +189,22 @@
            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,12 +228,30 @@
     * 替换模板文件并输出
     *
     * @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);
        }
        List<String> localTempPathList = Lists.newArrayList();
        if (!DataTableEntity.isEmpty(dte)) {
            for (int m = 0; m < dte.getRows(); m++) {
                fse = dte.getFieldSetEntity(m);
        Object[] fields = fse.getFields();
        for (int i = 0; i < fields.length; i++) {
@@ -244,14 +307,18 @@
                if (wordTemp.exists()) {
                    wordTemp.delete();
                }
                return localTempPathPdf;
                        localTempPathList.add(localTempPathPdf);
            } catch (Exception e) {
                throw new BaseException(CmnCode.CONVERT_PDF_ERROR, e);
            } finally {
                FileUtil.del(localTempPathWord);
            }
                } else {
                    localTempPathList.add(localTempPathWord);
        }
        return 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);
        // 遇错跳过,默认使用透明背景不拦截,记录日志到文件
        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,8 +70,12 @@
        } else if ("svg".equals(type)) {
            imgType = PictureType.SVG;
        }
        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
    public void doRender(RenderContext<PictureRenderData> context) throws Exception {
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,6 +65,7 @@
    @Override
    public void render(XWPFTable xwpfTable, Object data) throws Exception {
        try {
        if (xwpfTable == null) {
            return;
        }
@@ -73,15 +75,14 @@
        String tableExpression = "{{" + this.replaceKey + "}}";
        //获取表格起始行和结束行
        int startRowIndex = -1;
        rows:
        for (int i = 0; i < rows.size(); i++) {
            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 rows;
                        break outer;
                }
            }
@@ -127,7 +128,9 @@
        }
        if (subTableData != null && subTableData.size() > 0) {
            for (int i = 0; i < subTableData.size(); i++) {
                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) {
@@ -135,11 +138,20 @@
                } else {
                    int fieldRowIndex = xwpfTable.getRows().indexOf(fieldRow);
                    //创建一行在fieldRowIndex下面
                    row = xwpfTable.insertNewTableRow(fieldRowIndex + i);
                        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);
                    //清空单元格内容
@@ -161,20 +173,20 @@
                        }
                    }
                    //判断是否是序号列
                    if (indexKey.equals(fieldNames[j])) {
                        cell.setText(String.valueOf(i + 1));
                        if (indexKey.equals(fieldName)) {
                            if (map.isEmpty()) {
                                xwpfRun.setText("", 0);
                            } else {
                                xwpfRun.setText(String.valueOf(i + rowCount), 0);
                            }
                        continue;
                    }
                    Object value = map.get(fieldNames[j]);
                        Object value = map.get(fieldName);
                    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 ("lx_flow_opinion".equals(this.replaceKey) && "opinion".equals(fieldName)) {
                        if (!StringUtils.isEmpty(map.get("sign_attachment_uuid"))) {
                            //意见框 插入签名图片到单元格右下角位置
                            xwpfParagraph = cell.addParagraph();
@@ -217,6 +229,9 @@
        }
        //删除起始行
        xwpfTable.removeRow(startRowIndex);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**