Java 填充模板

最近接了个任务,需要对模板进行填充,使用word模板进行填充,尝试后,使用.docx的文档。
以下是dome:

 /**
     * 模板附件上传
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void legalConUploadTemplate(ConBase conBase) {
        /**
         *1.先根据模板参数去法务获取副本的流,获取到后进行填充,然后保存到本地,然后再从本地获取这附件,上传到法务
         */
        String legalId = baseSysVarClient.getValueByCode("conTemplateLegalId");
        //判断是否已生成模板附件
        List<ConLegalFile> conLegalFileList = conLegalFileService.selectByConBaseIdAndName(conBase.getConBaseId(), "conBase");
        for (ConLegalFile file : conLegalFileList){
            this.deletelegalFile(file, conBase.getUpdateUserCode());
        }
        //获取模板信息
        ConTemplateAttach attach = conTemplateAttachService.selectByLegalId(legalId);

        JSONObject js = new JSONObject();
        js.put("attachmentId",attach.getAttachmentId());
        js.put("mipAccount",conBase.getCreateUserCode());
        js.put("fileId",attach.getLegalId());
        byte[] legalDownLoad = this.legalDownLoad(js);
        List<ConItemCenter> info = conItemCenterService.getInfo(conBase.getConBaseId());
        InputStream inputStream = ConTemplateCtr.getInstance().print(new ByteArrayInputStream(legalDownLoad), conBase, info);
        //转换成MultipartFile
        MultipartFile multipartFile = null;
        String name = conBase.getConName() + ".docx";
        try {
            multipartFile = new MockMultipartFile(name, name,
                    ContentType.APPLICATION_OCTET_STREAM.toString(), inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        this.legalConUpload(multipartFile,"ContractNeedStamp",
                "conBase",conBase.getConBaseId().toString(), conBase.getCreateUserCode());
    }

方法入口
InputStream inputStream = ConTemplateCtr.getInstance().print(new ByteArrayInputStream(legalDownLoad), conBase, info);
注意这行代码,在这里面进行填充

import com.midea.dmr.common.utils.DateUtils;
import com.midea.dmr.cont.domain.bean.ConBase;
import com.midea.dmr.cont.domain.bean.ConItemCenter;

import java.io.InputStream;
import java.util.*;

public class ConTemplateCtr {

    private ConTemplateCtr() {
    }

    private static class ConTemplateCtrInstance {
        private static final ConTemplateCtr INSTANCE = new ConTemplateCtr();
    }

    public static ConTemplateCtr getInstance() {
        return ConTemplateCtrInstance.INSTANCE;
    }

    /**
     * 模板替换
     */
    public InputStream print(InputStream in, ConBase conBase, List<ConItemCenter> info) {
        // 模板全的路径
        //String templatePaht = "D:\\物料制作年度框架协议.docx";
        // 输出位置
        String outPath = "D:\\物料制作年度框架协议3.docx";
        Map<String, Object> paramMap = new HashMap(16);
        // 普通的占位符示例 参数数据结构 {str,str}
        paramMap.put("vendorName", conBase.getVendorName());
        Date effectiveTime = conBase.getEffectiveTime();
        paramMap.put("effectiveYear", DateUtils.getYear(effectiveTime));
        paramMap.put("effectiveMonth", DateUtils.getMonth(effectiveTime));
        paramMap.put("effectiveDay", DateUtils.getDay(effectiveTime));
        Date expirationTime = conBase.getExpirationTime();
        paramMap.put("expirationYear", DateUtils.getYear(expirationTime));
        paramMap.put("expirationMonth", DateUtils.getMonth(expirationTime));
        paramMap.put("expirationDay", DateUtils.getDay(expirationTime));
        paramMap.put("detailedAddress1", conBase.getDetailedAddress1());
        paramMap.put("vendorUserName", conBase.getVendorUserName());
        paramMap.put("vendorMobile", conBase.getVendorMobile());
        paramMap.put("vendorMail", conBase.getVendorMail());
        paramMap.put("operationCenterName", conBase.getOperationCenterName());
        List<List<String>> tbRow = new ArrayList();
        for (int i = 0; i < info.size(); i++) {
            List<String> tbRow1 = new ArrayList();
            ConItemCenter conItemCenter = info.get(i);
            tbRow1.add(conItemCenter.getCostemCode());
            tbRow1.add(conItemCenter.getProductName());
            tbRow1.add(conItemCenter.getMaterialProcessDesc());
            tbRow1.add(conItemCenter.getMaterialSpec());
            tbRow1.add(conItemCenter.getMaterialBulkSize());
            tbRow1.add(conItemCenter.getUomName());
            if (null != conItemCenter.getRealPrice()) {
                tbRow1.add(String.valueOf(conItemCenter.getRealPrice().setScale(2)));
            }
            tbRow.add(tbRow1);
        }
        //获取参数
        paramMap.put(PoiWordUtils.addRowText + "tb1", tbRow);
        //模板渲染
        return DynWordUtils.process(paramMap, in, outPath);
    }


}

这里主要是参数配置
//模板渲染
return DynWordUtils.process(paramMap, in, outPath);
后面的就是方式类
ConTemplateCtr类

package com.midea.dmr.cont.ctr;

import com.midea.dmr.common.utils.DateUtils;
import com.midea.dmr.cont.domain.bean.ConBase;
import com.midea.dmr.cont.domain.bean.ConItemCenter;

import java.io.InputStream;
import java.util.*;

public class ConTemplateCtr {

    private ConTemplateCtr() {
    }

    private static class ConTemplateCtrInstance {
        private static final ConTemplateCtr INSTANCE = new ConTemplateCtr();
    }

    public static ConTemplateCtr getInstance() {
        return ConTemplateCtrInstance.INSTANCE;
    }

    /**
     * 模板替换
     */
    public InputStream print(InputStream in, ConBase conBase, List<ConItemCenter> info) {
        // 模板全的路径
        //String templatePaht = "D:\\物料制作年度框架协议.docx";
        // 输出位置
        String outPath = "D:\\物料制作年度框架协议3.docx";
        Map<String, Object> paramMap = new HashMap(16);
        // 普通的占位符示例 参数数据结构 {str,str}
        paramMap.put("vendorName", conBase.getVendorName());
        Date effectiveTime = conBase.getEffectiveTime();
        paramMap.put("effectiveYear", DateUtils.getYear(effectiveTime));
        paramMap.put("effectiveMonth", DateUtils.getMonth(effectiveTime));
        paramMap.put("effectiveDay", DateUtils.getDay(effectiveTime));
        Date expirationTime = conBase.getExpirationTime();
        paramMap.put("expirationYear", DateUtils.getYear(expirationTime));
        paramMap.put("expirationMonth", DateUtils.getMonth(expirationTime));
        paramMap.put("expirationDay", DateUtils.getDay(expirationTime));
        paramMap.put("detailedAddress1", conBase.getDetailedAddress1());
        paramMap.put("vendorUserName", conBase.getVendorUserName());
        paramMap.put("vendorMobile", conBase.getVendorMobile());
        paramMap.put("vendorMail", conBase.getVendorMail());
        paramMap.put("operationCenterName", conBase.getOperationCenterName());
        List<List<String>> tbRow = new ArrayList();
        for (int i = 0; i < info.size(); i++) {
            List<String> tbRow1 = new ArrayList();
            ConItemCenter conItemCenter = info.get(i);
            tbRow1.add(conItemCenter.getCostemCode());
            tbRow1.add(conItemCenter.getProductName());
            tbRow1.add(conItemCenter.getMaterialProcessDesc());
            tbRow1.add(conItemCenter.getMaterialSpec());
            tbRow1.add(conItemCenter.getMaterialBulkSize());
            tbRow1.add(conItemCenter.getUomName());
            if (null != conItemCenter.getRealPrice()) {
                tbRow1.add(String.valueOf(conItemCenter.getRealPrice().setScale(2)));
            }
            tbRow.add(tbRow1);
        }
        //获取参数
        paramMap.put(PoiWordUtils.addRowText + "tb1", tbRow);
        //模板渲染
        return DynWordUtils.process(paramMap, in, outPath);
    }


}

DynWordUtils类

package com.midea.dmr.cont.ctr;

import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlCursor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.*;

/**
 * Create by IntelliJ Idea 2018.2
 *
 * @author: qyp
 * Date: 2019-10-25 14:48
 */
public class DynWordUtils {

    private static final Logger logger = LoggerFactory.getLogger(DynWordUtils.class);

    /**
     * 被list替换的段落 被替换的都是oldParagraph
     */
    private XWPFParagraph oldParagraph;

    /**
     * 参数
     */
    private Map<String, Object> paramMap;

    /**
     * 当前元素的位置
     */
    int n = 0;

    /**
     * 判断当前是否是遍历的表格
     */
    boolean isTable = false;

    /**
     * 模板对象
     */
    XWPFDocument templateDoc;

    /**
     * 默认字体的大小
     */
    public static final int DEFAULT_FONT_SIZE = 10;

    /**
     * 重复模式的占位符所在的行索引
     */
    private int currentRowIndex;

    /**
     * 入口
     *
     * @param paramMap     模板中使用的参数
     * @param templatePaht 模板全路径
     * @param outPath      生成的文件存放的本地全路径
     */
    public static void process(Map<String, Object> paramMap, String templatePaht, String outPath) {
        DynWordUtils dynWordUtils = new DynWordUtils();
        dynWordUtils.setParamMap(paramMap);
        dynWordUtils.createWord(templatePaht, outPath);
    }

    /**
     * 入口
     *
     * @param paramMap 模板中使用的参数
     * @param outPath  生成的文件存放的本地全路径
     */
    public static InputStream process(Map<String, Object> paramMap, InputStream in, String outPath) {
        DynWordUtils dynWordUtils = new DynWordUtils();
        dynWordUtils.setParamMap(paramMap);
        return dynWordUtils.createWord(in, outPath);
    }

    /**
     * 生成动态的word
     *
     * @param outPath
     */
    public InputStream createWord(InputStream in, String outPath) {
        ByteArrayOutputStream outStream = null;
        InputStream inputStream = null;
        try {
            Date date = new Date();
            logger.info("生成动态的createWord_outPath:" + outPath);
            outStream = new ByteArrayOutputStream();
            templateDoc = new XWPFDocument(in);
            parseTemplateWord();
            logger.info("生成动态的createWord成功。" + date.getTime());
            templateDoc.write(outStream);
            inputStream = new ByteArrayInputStream(outStream.toByteArray());
        } catch (Exception e) {
            StackTraceElement[] stackTrace = e.getStackTrace();

            String className = stackTrace[0].getClassName();
            String methodName = stackTrace[0].getMethodName();
            int lineNumber = stackTrace[0].getLineNumber();

            logger.info("错误:第:" + lineNumber + "行, 类名:" + className + ", 方法名:" + methodName);
            logger.info("生成动态的word失败_" + e.getMessage());
        } finally {
            if (outStream != null) {
                try {
                    outStream.close();
                } catch (IOException e) {
                    logger.info("关闭流失败:" + e.getMessage());
                }
            }
        }
        return inputStream;
    }

    /**
     * 生成动态的word
     *
     * @param templatePath
     * @param outPath
     */
    public void createWord(String templatePath, String outPath) {
        FileOutputStream outStream = null;
        try {
            logger.info("生成动态的createWord_templatePath:" + templatePath + "_outPath:" + outPath);
            outStream = new FileOutputStream(outPath);
            templateDoc = new XWPFDocument(OPCPackage.open(templatePath));
            parseTemplateWord();
            templateDoc.write(outStream);
        } catch (Exception e) {
            StackTraceElement[] stackTrace = e.getStackTrace();

            String className = stackTrace[0].getClassName();
            String methodName = stackTrace[0].getMethodName();
            int lineNumber = stackTrace[0].getLineNumber();

            logger.info("错误:第:" + lineNumber + "行, 类名:" + className + ", 方法名:" + methodName);
            logger.info("createWord_生成动态的word失败:{}", e.getMessage());
        } finally {
            if (outStream != null) {
                try {
                    outStream.close();
                } catch (IOException e) {
                    logger.info("createWord_关闭流失败:" + e.getMessage());
                }
            }
        }
    }


    /**
     * 解析word模板
     */
    public void parseTemplateWord() throws Exception {

        List<IBodyElement> elements = templateDoc.getBodyElements();

        for (; n < elements.size(); n++) {
            IBodyElement element = elements.get(n);
            // 普通段落
            if (element instanceof XWPFParagraph) {

                XWPFParagraph paragraph = (XWPFParagraph) element;
                oldParagraph = paragraph;
                if (paragraph.getParagraphText().isEmpty()) {
                    continue;
                }

                delParagraph(paragraph);

            } else if (element instanceof XWPFTable) {
                // 表格
                isTable = true;
                XWPFTable table = (XWPFTable) element;

                delTable(table, paramMap);
                isTable = false;
            }
        }

    }

    /**
     * 处理段落
     */
    private void delParagraph(XWPFParagraph paragraph) throws Exception {
        List<XWPFRun> runs = oldParagraph.getRuns();
        StringBuilder sb = new StringBuilder();
        for (XWPFRun run : runs) {
            String text = run.getText(0);
            if (text == null) {
                continue;
            }
            sb.append(text);
            run.setText("", 0);
        }
        placeholder(paragraph, runs, sb);
    }


    /**
     * 匹配传入信息集合与模板
     *
     * @param placeholder 模板需要替换的区域()
     * @param paramMap    传入信息集合
     * @return 模板需要替换区域信息集合对应值
     */
    public void changeValue(XWPFRun currRun, String placeholder, Map<String, Object> paramMap) throws Exception {

        String placeholderValue = placeholder;
        if (paramMap == null || paramMap.isEmpty()) {
            return;
        }

        Set<Map.Entry<String, Object>> textSets = paramMap.entrySet();
        for (Map.Entry<String, Object> textSet : textSets) {
            //匹配模板与替换值 格式${key}
            String mapKey = textSet.getKey();
            String docKey = PoiWordUtils.getDocKey(mapKey);

            if (placeholderValue.indexOf(docKey) != -1) {
                Object obj = textSet.getValue();
                // 需要添加一个list
                if (obj instanceof List) {
                    placeholderValue = delDynList(placeholder, (List) obj);
                } else {
                    placeholderValue = placeholderValue.replaceAll(
                            PoiWordUtils.getPlaceholderReg(mapKey)
                            , String.valueOf(obj));
                }
            }
        }

        currRun.setText(placeholderValue, 0);
    }

    /**
     * 处理的动态的段落(参数为list)
     *
     * @param placeholder 段落占位符
     * @param obj
     * @return
     */
    private String delDynList(String placeholder, List obj) {
        String placeholderValue = placeholder;
        List dataList = obj;
        Collections.reverse(dataList);
        for (int i = 0, size = dataList.size(); i < size; i++) {
            Object text = dataList.get(i);
            // 占位符的那行, 不用重新创建新的行
            if (i == 0) {
                placeholderValue = String.valueOf(text);
            } else {
                XWPFParagraph paragraph = createParagraph(String.valueOf(text));
                if (paragraph != null) {
                    oldParagraph = paragraph;
                }
                // 增加段落后doc文档的element的size会随着增加(在当前行的上面添加
                // 这里减操作是回退并解析新增的行(因为可能新增的带有占位符,这里为了支持图片和表格)
                if (!isTable) {
                    n--;
                }
            }
        }
        return placeholderValue;
    }

    /**
     * 创建段落 <p></p>
     *
     * @param texts
     */
    public XWPFParagraph createParagraph(String... texts) {

        // 使用游标创建一个新行
        XmlCursor cursor = oldParagraph.getCTP().newCursor();
        XWPFParagraph newPar = templateDoc.insertNewParagraph(cursor);
        // 设置段落样式
        newPar.getCTP().setPPr(oldParagraph.getCTP().getPPr());

        copyParagraph(oldParagraph, newPar, texts);

        return newPar;
    }

    /**
     * 处理表格(遍历)
     *
     * @param table    表格
     * @param paramMap 需要替换的信息集合
     */
    public void delTable(XWPFTable table, Map<String, Object> paramMap) throws Exception {
        List<XWPFTableRow> rows = table.getRows();
        for (int i = 0, size = rows.size(); i < size; i++) {
            XWPFTableRow row = rows.get(i);
            currentRowIndex = i;
            // 如果是动态添加行 直接处理后返回
            if (delAndJudgeRow(table, paramMap, row)) {
                return;
            }
        }
    }

    /**
     * 判断并且是否是动态行,并且处理表格占位符
     *
     * @param table    表格对象
     * @param paramMap 参数map
     * @param row      当前行
     * @return
     * @throws Exception
     */
    private boolean delAndJudgeRow(XWPFTable table, Map<String, Object> paramMap, XWPFTableRow row) throws Exception {
        // 当前行是动态行标志
        if (PoiWordUtils.isAddRow(row)) {
            List<XWPFTableRow> xwpfTableRows = addAndGetRows(table, row, paramMap);
            // 回溯添加的行,这里是试图处理动态添加的图片
            for (XWPFTableRow tbRow : xwpfTableRows) {
                delAndJudgeRow(table, paramMap, tbRow);
            }
            return true;
        }

        // 如果是重复添加的行
        if (PoiWordUtils.isAddRowRepeat(row)) {
            List<XWPFTableRow> xwpfTableRows = addAndGetRepeatRows(table, row, paramMap);
            // 回溯添加的行,这里是试图处理动态添加的图片
            for (XWPFTableRow tbRow : xwpfTableRows) {
                delAndJudgeRow(table, paramMap, tbRow);
            }
            return true;
        }
        // 当前行非动态行标签
        List<XWPFTableCell> cells = row.getTableCells();
        for (XWPFTableCell cell : cells) {
            //判断单元格是否需要替换
            if (PoiWordUtils.checkText(cell.getText())) {
                List<XWPFParagraph> paragraphs = cell.getParagraphs();
                for (XWPFParagraph paragraph : paragraphs) {
                    List<XWPFRun> runs = paragraph.getRuns();
                    StringBuilder sb = new StringBuilder();
                    for (XWPFRun run : runs) {
                        sb.append(run.toString());
                        run.setText("", 0);
                    }
                    placeholder(paragraph, runs, sb);
                }
            }
        }
        return false;
    }

    /**
     * 处理占位符
     *
     * @param runs 当前段的runs
     * @param sb   当前段的内容
     * @throws Exception
     */
    private void placeholder(XWPFParagraph currentPar, List<XWPFRun> runs, StringBuilder sb) throws Exception {
        if (runs.size() > 0) {
            String text = sb.toString();
            XWPFRun currRun = runs.get(0);
            if (PoiWordUtils.isPicture(text)) {
                // 该段落是图片占位符
                ImageEntity imageEntity = (ImageEntity) PoiWordUtils.getValueByPlaceholder(paramMap, text);
                int indentationFirstLine = currentPar.getIndentationFirstLine();
                // 清除段落的格式,否则图片的缩进有问题
                currentPar.getCTP().setPPr(null);
                //设置缩进
                currentPar.setIndentationFirstLine(indentationFirstLine);
//                addPicture(currRun, imageEntity);
            } else {
                changeValue(currRun, text, paramMap);
            }
        }
    }

    /**
     * 添加图片
     * @param currRun 当前run
     * @param imageEntity 图片对象
     * @throws InvalidFormatException
     * @throws FileNotFoundException
     */
    /*private void addPicture(XWPFRun currRun, ImageEntity imageEntity) throws InvalidFormatException, FileNotFoundException {
        Integer typeId = imageEntity.getTypeId().getTypeId();
        String picId = currRun.getDocument().addPictureData(new FileInputStream(imageEntity.getUrl()), typeId);
        ImageUtils.createPicture(currRun, picId, templateDoc.getNextPicNameNumber(typeId),
                imageEntity.getWidth(), imageEntity.getHeight());
    }*/

    /**
     * 添加行  标签行不是新创建的
     *
     * @param table
     * @param flagRow  flagRow 表有标签的行
     * @param paramMap 参数
     */
    private List<XWPFTableRow> addAndGetRows(XWPFTable table, XWPFTableRow flagRow, Map<String, Object> paramMap) throws Exception {
        List<XWPFTableCell> flagRowCells = flagRow.getTableCells();
        XWPFTableCell flagCell = flagRowCells.get(0);

        String text = flagCell.getText();
        List<List<String>> dataList = (List<List<String>>) PoiWordUtils.getValueByPlaceholder(paramMap, text);

        if (dataList == null || dataList.size() <= 0) {
            return new ArrayList();
        }
        // 新添加的行
        List<XWPFTableRow> newRows = new ArrayList(dataList.size());

        XWPFTableRow currentRow = flagRow;
        int cellSize = flagRow.getTableCells().size();
        for (int i = 0, size = dataList.size(); i < size; i++) {
            if (i != 0) {
                currentRow = table.createRow();
                // 复制样式
                if (flagRow.getCtRow() != null) {
                    currentRow.getCtRow().setTrPr(flagRow.getCtRow().getTrPr());
                }
            }
            addRow(flagCell, currentRow, cellSize, dataList.get(i));
            newRows.add(currentRow);
        }
        return newRows;
    }

    /**
     * 添加重复多行 动态行  每一行都是新创建的
     *
     * @param table
     * @param flagRow
     * @param paramMap
     * @return
     * @throws Exception
     */
    private List<XWPFTableRow> addAndGetRepeatRows(XWPFTable table, XWPFTableRow flagRow, Map<String, Object> paramMap) throws Exception {
        List<XWPFTableCell> flagRowCells = flagRow.getTableCells();
        XWPFTableCell flagCell = flagRowCells.get(0);
        String text = flagCell.getText();
        List<List<String>> dataList = (List<List<String>>) PoiWordUtils.getValueByPlaceholder(paramMap, text);
        String tbRepeatMatrix = PoiWordUtils.getTbRepeatMatrix(text);
        //Assert.assertNotNull("模板矩阵不能为空", tbRepeatMatrix);

        // 新添加的行
        if (dataList == null || dataList.size() <= 0) {
            return new ArrayList();
        }
        List<XWPFTableRow> newRows = new ArrayList(dataList.size());

        String[] split = tbRepeatMatrix.split(PoiWordUtils.tbRepeatMatrixSeparator);
        int startRow = Integer.parseInt(split[0]);
        int endRow = Integer.parseInt(split[1]);
        int startCell = Integer.parseInt(split[2]);
        int endCell = Integer.parseInt(split[3]);

        XWPFTableRow currentRow;
        for (int i = 0, size = dataList.size(); i < size; i++) {
            int flagRowIndex = i % (endRow - startRow + 1);
            XWPFTableRow repeatFlagRow = table.getRow(flagRowIndex);
            // 清除占位符那行
            if (i == 0) {
                table.removeRow(currentRowIndex);
            }
            currentRow = table.createRow();
            // 复制样式
            if (repeatFlagRow.getCtRow() != null) {
                currentRow.getCtRow().setTrPr(repeatFlagRow.getCtRow().getTrPr());
            }
            addRowRepeat(startCell, endCell, currentRow, repeatFlagRow, dataList.get(i));
            newRows.add(currentRow);
        }
        return newRows;
    }

    /**
     * 根据模板cell添加新行
     *
     * @param flagCell    模板列(标记占位符的那个cell)
     * @param row         新增的行
     * @param cellSize    每行的列数量(用来补列补足的情况)
     * @param rowDataList 每行的数据
     */
    private void addRow(XWPFTableCell flagCell, XWPFTableRow row, int cellSize, List<String> rowDataList) {
        for (int i = 0; i < cellSize; i++) {
            XWPFTableCell cell = row.getCell(i);
            cell = cell == null ? row.createCell() : row.getCell(i);
            if (i < rowDataList.size()) {
                PoiWordUtils.copyCellAndSetValue(flagCell, cell, rowDataList.get(i));
            } else {
                // 数据不满整行时,添加空列
                PoiWordUtils.copyCellAndSetValue(flagCell, cell, "");
            }
        }
    }

    /**
     * 根据模板cell  添加重复行
     *
     * @param startCell     模板列的开始位置
     * @param endCell       模板列的结束位置
     * @param currentRow    创建的新行
     * @param repeatFlagRow 模板列所在的行
     * @param rowDataList   每行的数据
     */
    private void addRowRepeat(int startCell, int endCell, XWPFTableRow currentRow, XWPFTableRow repeatFlagRow, List<String> rowDataList) {
        int cellSize = repeatFlagRow.getTableCells().size();
        for (int i = 0; i < cellSize; i++) {
            XWPFTableCell cell = currentRow.getCell(i);
            cell = cell == null ? currentRow.createCell() : currentRow.getCell(i);
            int flagCellIndex = i % (endCell - startCell + 1);
            XWPFTableCell repeatFlagCell = repeatFlagRow.getCell(flagCellIndex);
            if (i < rowDataList.size()) {
                PoiWordUtils.copyCellAndSetValue(repeatFlagCell, cell, rowDataList.get(i));
            } else {
                // 数据不满整行时,添加空列
                PoiWordUtils.copyCellAndSetValue(repeatFlagCell, cell, "");
            }
        }
    }

    /**
     * 复制段落
     *
     * @param sourcePar 原段落
     * @param targetPar
     * @param texts
     */
    private void copyParagraph(XWPFParagraph sourcePar, XWPFParagraph targetPar, String... texts) {

        targetPar.setAlignment(sourcePar.getAlignment());
        targetPar.setVerticalAlignment(sourcePar.getVerticalAlignment());

        // 设置布局
        targetPar.setAlignment(sourcePar.getAlignment());
        targetPar.setVerticalAlignment(sourcePar.getVerticalAlignment());

        if (texts != null && texts.length > 0) {
            String[] arr = texts;
            XWPFRun xwpfRun = sourcePar.getRuns().isEmpty() ? sourcePar.getRuns().get(0) : null;

            for (int i = 0, len = texts.length; i < len; i++) {
                String text = arr[i];
                XWPFRun run = targetPar.createRun();
                if (xwpfRun != null) {

                    String fontFamily = xwpfRun.getFontFamily();
                    run.setText(text);
                    run.setFontFamily(fontFamily);
                    int fontSize = xwpfRun.getFontSize();
                    run.setFontSize((fontSize == -1) ? DEFAULT_FONT_SIZE : fontSize);
                    run.setBold(xwpfRun.isBold());
                    run.setItalic(xwpfRun.isItalic());
                } else {
                    run.setFontFamily("仿宋_GB2312");
                    int fontSize = -1;
                    run.setFontSize((fontSize == -1) ? DEFAULT_FONT_SIZE : fontSize);
                    run.setBold(false);
                    run.setItalic(false);
                }
            }
        }
    }

    public void setParamMap(Map<String, Object> paramMap) {
        this.paramMap = paramMap;
    }
}

FreeMarkerUtil类

package com.midea.dmr.cont.ctr;

import com.itextpdf.text.Document;
import com.itextpdf.text.Font;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
import com.midea.dmr.common.exception.ParamValidationException;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;

import java.io.*;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.logging.Logger;

/**
 * freemarker工具类
 */
public class FreeMarkerUtil {
    private static final Logger LOG = Logger.getLogger(FreeMarkerUtil.class.getName());
    private static final String ENCODE = "UTF-8";

    /**
     * freeMarker渲染
     *
     * @param data
     * @param templateFile
     * @return
     * @throws
     */
    public static String freeMarkerRender(Map<String, Object> data, byte[] templateFile) throws ParamValidationException {
        Writer writer = new StringWriter();
        try {
            Configuration configuration = initConfig();

            Template template = getTemplate(configuration, templateFile);
            template.process(data, writer);
            writer.flush();
            return writer.toString();
        } catch (Exception e) {
            LOG.info("freeMarker渲染异常:" + e.getMessage());
            throw new ParamValidationException("freeMarker渲染异常");
        } finally {
            try {
                writer.close();
            } catch (IOException ioe) {
                LOG.info("关闭文件流异常:" + ioe.getMessage());
            }
        }
    }

    /**
     * 模板转换为pdf(使用默认页眉页脚)
     *
     * @param templateFile
     * @return
     * @throws
     */
    public static byte[] html2Pdf(String templateFile) throws Exception {

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        Document document = null;
        try {
            document = new Document(PageSize.A4, 90, 90, 60, 60);
            PdfWriter writer = PdfWriter.getInstance(document, baos);
            PDFBuilder builder = new PDFBuilder();
            writer.setPageEvent(builder);
            document.open();
            XMLWorkerFontProvider fontImp = new XMLWorkerFontProvider();
            LOG.info("html2Pdf.parseXHtml,开始");
            com.itextpdf.tool.xml.XMLWorkerHelper.getInstance().parseXHtml(writer, document, new ByteArrayInputStream(templateFile.getBytes(ENCODE)), null, Charset.forName(ENCODE), fontImp);
            LOG.info("html2Pdf.parseXHtml,结束");
            document.close();
            baos.flush();
            baos.close();


        } catch (Exception e) {
            LOG.info("转换电子合同异常:" + e.getMessage());
            throw new Exception(e);
        }

        return baos.toByteArray();
    }

    /**
     * 模板转换为pdf(使用默认页眉页脚)
     *
     * @param templateFile
     * @return
     * @throws
     */
    public static byte[] html2PdfNew(String templateFile) throws Exception {

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        Document document = null;
        try {
            document = new Document(PageSize.A4, 90, 90, 60, 60);
            BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
            Font font = new Font(baseFont);
            Paragraph p = new Paragraph();
            p.setFont(font);
            PdfWriter writer = PdfWriter.getInstance(document, baos);
            PDFBuilder builder = new PDFBuilder();
            writer.setPageEvent(builder);
            document.open();
            document.add(p);
            XMLWorkerFontProvider fontImp = new XMLWorkerFontProvider();
            LOG.info("html2Pdf1.parseXHtml,开始");
            com.itextpdf.tool.xml.XMLWorkerHelper.getInstance().parseXHtml(writer, document, new ByteArrayInputStream(templateFile.getBytes(ENCODE)), null, Charset.forName(ENCODE), fontImp);
            LOG.info("html2Pdf1.parseXHtml,结束");
            document.close();
            baos.flush();
            baos.close();


        } catch (Exception e) {
            LOG.info("转换电子合同异常1:" + e.getMessage());
            throw new Exception(e);
        }

        return baos.toByteArray();
    }

    /**
     * 模板转换为pdf(使用自定义页眉页脚)
     *
     * @param templateFile
     * @param builder
     * @return
     * @throws
     */
    public static byte[] html2Pdf(String templateFile, PDFBuilder builder) throws ParamValidationException {

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            Document document = new Document(PageSize.A4, 90, 90, 60, 60);

            PdfWriter writer = PdfWriter.getInstance(document, baos);
            writer.setPageEvent(builder);
            document.open();
            XMLWorkerFontProvider fontImp = new XMLWorkerFontProvider();
            com.itextpdf.tool.xml.XMLWorkerHelper.getInstance().parseXHtml(writer, document, new ByteArrayInputStream(templateFile.getBytes()), null, Charset.forName(ENCODE), fontImp);


            document.close();
            baos.flush();
            baos.close();

        } catch (Exception e) {
            LOG.info("转换电子合同异常:" + e.getMessage());
            throw new ParamValidationException("转换电子合同异常");
        }

        return baos.toByteArray();
    }

    /**
     * 模板参数初始化
     *
     * @return
     */
    public static Configuration initConfig() {
        Configuration configuration = new Configuration();
        configuration.setDefaultEncoding(ENCODE);

        return configuration;
    }

    /**
     * 获取模板
     *
     * @param configuration
     * @return
     * @throws
     */
    public static Template getTemplate(Configuration configuration, byte[] templateFile) throws ParamValidationException {
        StringTemplateLoader stl = new StringTemplateLoader();
        stl.putTemplate("template", new String(templateFile));
        configuration.setTemplateLoader(stl);
        try {
            return configuration.getTemplate("template");
        } catch (Exception e) {
            LOG.info("获取模板异常:" + e.getMessage());
            throw new ParamValidationException("获取模板异常");
        }
    }
}

ImageEntity类

package com.midea.dmr.cont.ctr;

/**
 * Create by IntelliJ Idea 2018.2
 * <p>
 * 图片实体对象
 *
 * @author: qyp
 * Date: 2019-10-26 21:52
 */
public class ImageEntity {

    /**
     * 图片宽度
     */
    private int width = 400;

    /**
     * 图片高度
     */
    private int height = 300;

    /**
     * 图片地址
     */
    private String url;


    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }
}

ImageUtils类

package com.midea.dmr.cont.ctr;

import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlToken;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline;

/**
 * Create by IntelliJ Idea 2018.2
 *
 * @author: qyp
 * Date: 2019-10-26 21:55
 */
public class ImageUtils {

    /**
     * 图片类型枚举
     */
    enum ImageType {

        /**
         * 支持四种类型 JPG/JPEG, GIT, BMP, PNG
         */
        JPG("JPG", XWPFDocument.PICTURE_TYPE_JPEG),
        JPEG("JPEG", XWPFDocument.PICTURE_TYPE_JPEG),
        PNG("PNG", XWPFDocument.PICTURE_TYPE_PNG)
        ;
        private String name;
        private Integer typeId;
        ImageType(String name, Integer type) {
            this.name = name;
            this.typeId = type;
        }

        public String getName() {
            return name;
        }

        public Integer getTypeId() {
            return typeId;
        }

    }


    public static void createPicture(XWPFRun run, String blipId, int id, int width, int height) {
        final int EMU = 9525;
        width *= EMU;
        height *= EMU;
        CTInline inline = run.getCTR().addNewDrawing().addNewInline();

        String picXml = "" +
                "<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">" +
                "   <a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">" +
                "      <pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">" +
                "         <pic:nvPicPr>" +
                "            <pic:cNvPr id=\"" + id + "\" name=\"Generated\"/>" +
                "            <pic:cNvPicPr/>" +
                "         </pic:nvPicPr>" +
                "         <pic:blipFill>" +
                "            <a:blip r:embed=\"" + blipId + "\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"/>" +
                "            <a:stretch>" +
                "               <a:fillRect/>" +
                "            </a:stretch>" +
                "         </pic:blipFill>" +
                "         <pic:spPr>" +
                "            <a:xfrm>" +
                "               <a:off x=\"0\" y=\"0\"/>" +
                "               <a:ext cx=\"" + width + "\" cy=\"" + height + "\"/>" +
                "            </a:xfrm>" +
                "            <a:prstGeom prst=\"rect\">" +
                "               <a:avLst/>" +
                "            </a:prstGeom>" +
                "         </pic:spPr>" +
                "      </pic:pic>" +
                "   </a:graphicData>" +
                "</a:graphic>";

        XmlToken xmlToken = null;
        try {
            xmlToken = XmlToken.Factory.parse(picXml);
        } catch(XmlException xe) {
            xe.printStackTrace();
        }
        inline.set(xmlToken);

        inline.setDistT(0);
        inline.setDistB(0);
        inline.setDistL(0);
        inline.setDistR(0);

        CTPositiveSize2D extent = inline.addNewExtent();
        extent.setCx(width);
        extent.setCy(height);

        CTNonVisualDrawingProps docPr = inline.addNewDocPr();
        docPr.setId(id);
        docPr.setName("Picture " + id);
        docPr.setDescr("Generated");
    }

}

MapperUtils类

package com.midea.dmr.cont.ctr;

import ma.glasnost.orika.MapperFacade;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.impl.DefaultMapperFactory;

public class MapperUtils {
	
	private static MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
    private static MapperFacade mapper = null;
    
    static {
        mapper = mapperFactory.getMapperFacade();
    }

    public static MapperFacade getMapper() {
        return mapper;
    }

    public static void main(String[] args) {
    }

	   
}

PDFBuilder类

package com.midea.dmr.cont.ctr;

import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;

/**
 * 设置页眉页脚处理类
 */
public class PDFBuilder extends PdfPageEventHelper {

    // 页眉
    private String header = "                                                                                                                                                                                                      2020年V1.0版";
    // 页脚
    private String footer = "";
    // 字体大小
    private int presentFontSize = 9;
    // 纸张大小
    private Rectangle pageSize = PageSize.A4;
    // 模板
    private PdfTemplate pdfTemplate;
    // 基础字体对象
    private BaseFont baseFont = null;
    // 利用基础字体生成的字体对象,一般用于生成中文文字
    private Font headerFont = null;
    private Font footerFont = null;

    public PDFBuilder() {

    }

    public PDFBuilder(String header, int presentFontSize, Rectangle pageSize) {
        this.header = header;
        this.presentFontSize = presentFontSize;
        this.pageSize = pageSize;
    }

    public PDFBuilder(String header, String footer, int presentFontSize, Rectangle pageSize) {
        this.header = header;
        this.footer = footer;
        this.presentFontSize = presentFontSize;
        this.pageSize = pageSize;
    }

    /**
     * 文档打开时初始化
     *
     * @param writer
     * @param document
     */
    @Override
    public void onOpenDocument(PdfWriter writer, Document document) {
        // 设置边框长宽
        pdfTemplate = writer.getDirectContent().createTemplate(50, 50);// 共 页 的矩形的长宽高
        try {
            if (baseFont == null) {
                baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", false);
            }
            // 设置字体
            if (headerFont == null) {
                headerFont = new Font(baseFont, presentFontSize, Font.UNDERLINE);// 数据体字体
            }
            if (footerFont == null) {
                footerFont = new Font(baseFont, presentFontSize, Font.NORMAL);// 数据体字体
            }
        } catch (Exception e) {
//            LogUtil.error("初始化异常:", e);
//            throw new ServiceException("初始化异常");
        }
    }

    /**
     * 每页关闭写入页眉页脚
     *
     * @param writer
     * @param document
     */
    @Override
    public void onEndPage(PdfWriter writer, Document document) {
        try {
            if (baseFont == null) {
//                baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", false);
                baseFont = BaseFont.createFont();
            }
            if (footerFont == null) {
                // 数据体字体
                footerFont = new Font(baseFont, presentFontSize, Font.NORMAL);
            }

            float right = 505.0f;
            float top = 782.0f;
            float rightMargin = 90.0f;
            float leftMargin = 90.0f;
            float left = 90.0f;
            float bottom = 60.0f;
            if (document != null) {
                right = document.right();
                top = document.top();
                rightMargin = document.rightMargin();
                leftMargin = document.leftMargin();
                left = document.left();
                bottom = document.bottom();
            }
            // 1.写入页眉
            ColumnText.showTextAligned(writer.getDirectContent(), Element.ALIGN_RIGHT, new Phrase(header, headerFont), right, top + 20, 0);
            // 2.写入前半部分的 第 X页/共
            String foot1 = "";
            int align;
//        if (footer.isEmpty()) {
            if (org.apache.commons.lang.StringUtils.isBlank(this.footer)) {
                int pageS = writer.getPageNumber();
                foot1 = " " + pageS + "  /";
                align = Element.ALIGN_CENTER;
            } else {
                foot1 = this.footer;
                align = Element.ALIGN_LEFT;
            }
            Phrase phrase = new Phrase(foot1, footerFont);
            TabSettings tabSettings = new TabSettings();

            // 3.计算前半部分的foot1的长度,后面好定位最后一部分的'Y页'这俩字的x轴坐标,字体长度也要计算进去 = len
            float len = baseFont.getWidthPoint(foot1, presentFontSize);

            // 4.拿到当前的PdfContentByte
            PdfContentByte cb = writer.getDirectContent();

            // 5.写入页脚1,x轴就是(右margin+左margin + right() -left()- len)/2.0F
            ColumnText.showTextAligned(cb, align, phrase, (rightMargin + right + leftMargin - left - len) / 2.0F + 20F, bottom - 20, 0);
            // 6.写入页脚2的模板(就是页脚的Y页这俩字)添加到文档中,计算模板的和Y轴,X=(右边界-左边界 - 前半部分的len值)/2.0F +
            // len , y 轴和之前的保持一致,底边界-20
            cb.addTemplate(pdfTemplate, (rightMargin + right + leftMargin - left) / 2.0F + 20F, bottom - 20); // 调节模版显示的位置
        } catch (Exception e) {
//          LogUtil.error("系统异常:", e);
            System.err.println(e.getMessage());
            return;
        }
    }

    /**
     * 文档关闭时写入页眉页脚
     *
     * @param writer
     * @param document
     */
    @Override
    public void onCloseDocument(PdfWriter writer, Document document) {
        // 关闭文档的时候,将模板替换成实际的 Y 值,至此,page x of y 制作完毕。
        pdfTemplate.beginText();
        pdfTemplate.setFontAndSize(baseFont, presentFontSize);// 生成的模版的字体、颜色
        String foot2 = "";
//        if (footer.isEmpty()) {
        if (org.apache.commons.lang.StringUtils.isBlank(footer)) {
            foot2 = " " + (writer.getPageNumber()) + " ";
        }
        pdfTemplate.showText(foot2);// 模版显示的内容
        pdfTemplate.endText();
        pdfTemplate.closePath();
    }
}

PDFUtil类

package com.midea.dmr.cont.ctr;

import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.*;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.pdfbox.pdmodel.PDDocument;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

//import com.midea.jr.ecr.common.log.util.LogUtil;

public class PDFUtil {

    /**
     * 获取PDDocument对象
     *
     * @param bytes
     * @return
     */
    public static PDDocument getPDDocument(byte[] bytes) {
        PDDocument pdf = null;
        try {
            pdf = PDDocument.load(bytes);
            return pdf;
        } catch (Exception e) {
            //LogUtil.error("", e);
        }
        return null;
    }

    /**
     * 获取PDDocument对象
     *
     * @param file
     * @return
     */
    public static PDDocument getPDDocument(File file) {
        PDDocument pdf = null;
        try {
            pdf = PDDocument.load(file);
            return pdf;
        } catch (Exception e) {
            //LogUtil.error("", e);
        }
        return null;
    }

    /**
     * 获取PDDocument对象
     *
     * @param fileInputStream
     * @return
     */
    public static PDDocument getPDDocument(FileInputStream fileInputStream) {
        PDDocument pdf = null;
        try {
            pdf = PDDocument.load(fileInputStream);
            return pdf;
        } catch (Exception e) {
            //LogUtil.error("", e);
        }
        return null;
    }

    /**
     * 获取PDDocument对象
     *
     * @param pdfFilePath
     * @return
     */
    public static PDDocument getPDDocument(String pdfFilePath) {
        try {
            File file = new File(pdfFilePath);
            if (file.exists()) {
                throw new Exception("路径" + pdfFilePath + "文件不存在");
            }
            if (!file.isFile()) {
                throw new Exception("路径" + pdfFilePath + "不是文件");
            }

            if (!file.canRead()) {
                throw new Exception("文件" + pdfFilePath + "无法读取");
            }

            return getPDDocument(file);
        } catch (Exception e) {
            //LogUtil.error("", e);
        }
        return null;
    }

    /**
     * 自己设置压缩质量来把图片压缩成byte[]
     *
     * @param image
     *            压缩源图片
     * @param quality
     *            压缩质量,在0-1之间,
     * @return 返回的字节数组
     */
    public static byte[] bufferedImageTobytes(BufferedImage image, float quality) {
        // 如果图片空,返回空
        if (image == null) {
            return null;
        }
        // 得到指定Format图片的writer
        Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName("jpeg");// 得到迭代器
        ImageWriter writer = iter.next(); // 得到writer

        // 得到指定writer的输出参数设置(ImageWriteParam )
        ImageWriteParam iwp = writer.getDefaultWriteParam();
        iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); // 设置可否压缩
        iwp.setCompressionQuality(quality); // 设置压缩质量参数
        iwp.setProgressiveMode(ImageWriteParam.MODE_DISABLED);
        ColorModel colorModel = ColorModel.getRGBdefault();
        // 指定压缩时使用的色彩模式
        iwp.setDestinationType(
                new javax.imageio.ImageTypeSpecifier(colorModel, colorModel.createCompatibleSampleModel(16, 16)));
        // 开始打包图片,写入byte[]
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); // 取得内存输出流
        IIOImage iIamge = new IIOImage(image, null, null);
        byte[] bytes = null;
        try {
            // 此处因为ImageWriter中用来接收write信息的output要求必须是ImageOutput
            // 通过ImageIo中的静态方法,得到byteArrayOutputStream的ImageOutput
            writer.setOutput(ImageIO.createImageOutputStream(byteArrayOutputStream));
            writer.write(null, iIamge, iwp);
            bytes = byteArrayOutputStream.toByteArray();
        } catch (IOException e) {
            //LogUtil.error("", e);
        }
        return bytes;
    }

    /**
     * 向pdf表单填充数据
     *
     * @param fields
     * @param map
     * @throws IOException
     * @throws DocumentException
     */
    public static void fillData(AcroFields fields, Map<String, Object> map) throws IOException, DocumentException {
        List<String> keys = new ArrayList<String>();
        Map<String, AcroFields.Item> formFields = fields.getFields();
        for (String key : map.keySet()) {
            if (formFields.containsKey(key)) {
                String value = String.valueOf(map.get(key));
                fields.setField(key,value/*,true*/); // 为字段赋值,注意字段名称是区分大小写的
                keys.add(key);
            }
        }
        Iterator<String> itemsKey = formFields.keySet().iterator();
        while (itemsKey.hasNext()) {
            String itemKey = itemsKey.next();
            if (!keys.contains(itemKey)) {
                fields.setField(itemKey, " ");
            }
        }
    }

    /**
     * itext生成pdf
     *
     * @param map
     * @param file
     * @return
     */
    public static byte[] generatePDF(Map<String, Object> map, byte[] file) {

        try{
        	ByteArrayOutputStream bos = new ByteArrayOutputStream();
            PdfReader reader = new PdfReader(file);
            PdfStamper ps = new PdfStamper(reader, bos);
            /* 使用中文字体 */
            BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
            ArrayList<BaseFont> fontList = new ArrayList<BaseFont>();
            fontList.add(bf);
            /* 取出报表模板中的所有字段 */
            AcroFields fields = ps.getAcroFields();
            fields.setSubstitutionFonts(fontList);
            fillData(fields, map);
            /* 必须要调用这个,否则文档不会生成的 如果为false那么生成的PDF文件还能编辑,一定要设为true */
            ps.setFormFlattening(true);
            ps.close();
            return bos.toByteArray();
        } catch (Exception e) {
            //LogUtil.error("", e);
        }
        return null;
    }

    /**
     * 给pdf文件添加水印
     * @param InPdfFile
     * @param markImagePath
     * @return
     */
    public static byte[] addPdfMark(byte[] InPdfFile, byte[] markImagePath) {
        try {
        	ByteArrayOutputStream bos = new ByteArrayOutputStream();
            PdfReader reader = new PdfReader(InPdfFile, "PDF".getBytes());
            PdfStamper stamp = new PdfStamper(reader, bos);
            Image img = Image.getInstance(markImagePath);// 插入水印
            int pageSize = reader.getNumberOfPages();// 原pdf文件的总页数
            for(int i = 1; i <= pageSize; i++) {
                float pageWidth = reader.getPageSize(i).getWidth();
                float pageHeight = reader.getPageSize(i).getHeight();
                PdfContentByte under = stamp.getUnderContent(i);  //水印在文本之下
//						PdfGState gs = new PdfGState();
//						gs.setFillOpacity(0.8f);// 设置透明度
//						under.setGState(gs);
                float per =(pageWidth/img.getWidth()) <(pageHeight/img.getHeight())?(pageWidth/img.getWidth()):(pageHeight/img.getHeight());
                img.scalePercent(per*100);//依照比例缩放
                img.scaleAbsolute(pageWidth,pageHeight);//自定义大小
                img.setAbsolutePosition((pageWidth-img.getWidth())/2, (pageHeight-img.getHeight())/2);//图片坐标--居中
                under.addImage(img);
            }
            stamp.close();
            return bos.toByteArray();
        }
        catch(Exception e){
            //LogUtil.error("", e);
        }
        return null;
    }

    /**
     * 给pdf文件添加水印 -cfca用
     * @param InPdfFile
     * @param markImagePath
     * @return
     */
    public static byte[] addPdfMarkToCfca(byte[] InPdfFile, byte[] markImagePath) {
        try {
        	ByteArrayOutputStream bos = new ByteArrayOutputStream();
//        	try (ByteArrayOutputStream bos = new ByteArrayOutputStream();){
            PdfReader reader = new PdfReader(InPdfFile, "PDF".getBytes());
            PdfStamper stamp = new PdfStamper(reader, bos);
            Image img = Image.getInstance(markImagePath);// 插入水印
            int pageSize = reader.getNumberOfPages();// 原pdf文件的总页数
            for(int i = 1; i <= pageSize; i++) {
                float pageWidth = reader.getPageSize(i).getWidth();
                float pageHeight = reader.getPageSize(i).getHeight();
                PdfContentByte under = stamp.getUnderContent(i);  //水印在文本之下
//						PdfGState gs = new PdfGState();
//						gs.setFillOpacity(0.8f);// 设置透明度
//						under.setGState(gs);
//						img.scalePercent(50);//依照比例缩放
                float per =(pageWidth/img.getWidth()) <(pageHeight/img.getHeight())?(pageWidth/img.getWidth()):(pageHeight/img.getHeight());
                img.scalePercent(per*100);//依照比例缩放
                //img.scaleAbsolute(pageWidth,pageHeight);//自定义大小
                img.setAbsolutePosition(0, 0);//图片坐标--居中
                under.addImage(img);
            }
            stamp.close();
            return bos.toByteArray();
        }
        catch(Exception e){
            //LogUtil.error("", e);
        }
        return null;
    }
}

PoiWordUtils类

package com.midea.dmr.cont.ctr;

import org.apache.poi.xwpf.usermodel.*;

import java.util.List;
import java.util.Map;

/**
 * Create by IntelliJ Idea 2018.2
 *
 * @author: qyp
 * Date: 2019-10-26 2:12
 */
public class PoiWordUtils {

    /**
     * 占位符第一个字符
     */
    public static final String PREFIX_FIRST = "$";

    /**
     * 占位符第二个字符
     */
    public static final String PREFIX_SECOND = "{";

    /**
     * 占位符的前缀
     */
    public static final String PLACEHOLDER_PREFIX = PREFIX_FIRST + PREFIX_SECOND;

    /**
     * 占位符后缀
     */
    public static final String PLACEHOLDER_END = "}";

    /**
     * 表格中需要动态添加行的独特标记
     */
    public static final String addRowText = "tbAddRow:";

    public static final String addRowRepeatText = "tbAddRowRepeat:";

    /**
     * 表格中占位符的开头 ${tbAddRow:  例如${tbAddRow:tb1}
     */
    public static final String addRowFlag = PLACEHOLDER_PREFIX + addRowText;

    /**
     * 表格中占位符的开头 ${tbAddRowRepeat:  例如 ${tbAddRowRepeat:0,2,0,1} 第0行到第2行,第0列到第1列 为模板样式
     */
    public static final String addRowRepeatFlag = PLACEHOLDER_PREFIX + addRowRepeatText;

    /**
     * 重复矩阵的分隔符  比如:${tbAddRowRepeat:0,2,0,1} 分隔符为 ,
     */
    public static final String tbRepeatMatrixSeparator = ",";

    /**
     * 占位符的后缀
     */
    public static final String PLACEHOLDER_SUFFIX = "}";

    /**
     * 图片占位符的前缀
     */
    public static final String PICTURE_PREFIX = PLACEHOLDER_PREFIX + "image:";

    /**
     * 判断当前行是不是标志表格中需要添加行
     *
     * @param row
     * @return
     */
    public static boolean isAddRow(XWPFTableRow row) {
        return isDynRow(row, addRowFlag);
    }

    /**
     * 添加重复模板动态行(以多行为模板)
     * @param row
     * @return
     */
    public static boolean isAddRowRepeat(XWPFTableRow row) {
        return isDynRow(row, addRowRepeatFlag);
    }

    private static boolean isDynRow(XWPFTableRow row, String dynFlag) {
        if (row == null) {
            return false;
        }
        List<XWPFTableCell> tableCells = row.getTableCells();
        if (tableCells != null) {
            XWPFTableCell cell = tableCells.get(0);
            if (cell != null) {
                String text = cell.getText();
                if (text != null && text.startsWith(dynFlag)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 从参数map中获取占位符对应的值
     *
     * @param paramMap
     * @param key
     * @return
     */
    public static Object getValueByPlaceholder(Map<String, Object> paramMap, String key) {
        if (paramMap != null) {
            if (key != null) {
                return paramMap.get(getKeyFromPlaceholder(key));
            }
        }
        return null;
    }

    /**
     * 后去占位符的重复行列矩阵
     * @param key 占位符
     * @return {0,2,0,1}
     */
    public static String getTbRepeatMatrix(String key) {
        //Assert.assertNotNull("占位符为空", key);
        String $1 = key.replaceAll("\\" + PREFIX_FIRST + "\\" + PREFIX_SECOND + addRowRepeatText + "(.*)" + "\\" + PLACEHOLDER_SUFFIX, "$1");
        return $1;
    }

    /**
     * 从占位符中获取key
     *
     * @return
     */
    public static String getKeyFromPlaceholder(String placeholder) {
//        return Optional.ofNullable(placeholder).map(p -> p.replaceAll("[\\$\\{\\}]", "")).get();
        return placeholder.replaceAll("[\\$\\{\\}]", "");
    }

    public static void main(String[] args) {
        String s = "${aa}";
        s = s.replaceAll(PLACEHOLDER_PREFIX + PLACEHOLDER_SUFFIX , "");
        System.out.println(s);
//        String keyFromPlaceholder = getKeyFromPlaceholder("${tbAddRow:tb1}");
//        System.out.println(keyFromPlaceholder);
    }

    /**
     * 复制列的样式,并且设置值
     * @param sourceCell
     * @param targetCell
     * @param text
     */
    public static void copyCellAndSetValue(XWPFTableCell sourceCell, XWPFTableCell targetCell, String text) {
        //段落属性
        List<XWPFParagraph> sourceCellParagraphs = sourceCell.getParagraphs();
        if (sourceCellParagraphs == null || sourceCellParagraphs.size() <= 0) {
            return;
        }
        XWPFParagraph sourcePar = sourceCellParagraphs.get(0);
        XWPFParagraph targetPar = targetCell.getParagraphs().get(0);

        // 设置段落的样式
        targetPar.getCTP().setPPr(sourcePar.getCTP().getPPr());


        List<XWPFRun> sourceParRuns = sourcePar.getRuns();
        if (sourceParRuns != null && sourceParRuns.size() > 0) {
            // 如果当前cell中有run
            List<XWPFRun> runs = targetPar.getRuns();
//            Optional.ofNullable(runs).ifPresent(rs -> rs.stream().forEach(r -> r.setText("", 0)));
            if (runs != null && runs.size() > 0) {
                runs.get(0).setText(text, 0);
            } else {
                XWPFRun cellR = targetPar.createRun();
                cellR.setText(text, 0);
                // 设置列的样式位模板的样式
                targetCell.getCTTc().setTcPr(sourceCell.getCTTc().getTcPr());
            }
            setTypeface(sourcePar, targetPar);
        } else {
            targetCell.setText(text);
        }
    }

    /**
     * 复制字体
     */
    private static void setTypeface(XWPFParagraph sourcePar, XWPFParagraph targetPar) {
        XWPFRun sourceRun = sourcePar.getRuns().get(0);
        String fontFamily = sourceRun.getFontFamily();
        int fontSize = sourceRun.getFontSize();
//        String color = sourceRun.getColor();
//        String fontName = sourceRun.getFontName();
        boolean bold = sourceRun.isBold();
        boolean italic = sourceRun.isItalic();
//        int kerning = sourceRun.getKerning();
//        String style = sourcePar.getStyle();
        UnderlinePatterns underline = sourceRun.getUnderline();
        List<XWPFRun> runs = targetPar.getRuns();
        if(runs.isEmpty()){
        	return;
        }
        XWPFRun targetRun = targetPar.getRuns().get(0);
        targetRun.setFontFamily(fontFamily);
//        targetRun.setFontSize(fontSize == -1 ? 10 : fontSize);
        targetRun.setBold(bold);
//        targetRun.setColor(color);
        targetRun.setItalic(italic);
//        targetRun.setKerning(kerning);
        targetRun.setUnderline(underline);
        //targetRun.setFontSize(fontSize);
    }
    /**
     * 判断文本中时候包含$
     * @param text 文本
     * @return 包含返回true,不包含返回false
     */
    public static boolean checkText(String text){
        boolean check  =  false;
        if(text.indexOf(PLACEHOLDER_PREFIX)!= -1){
            check = true;
        }
        return check;
    }

    /**
     * 获得占位符替换的正则表达式
     * @return
     */
    public static String getPlaceholderReg(String text) {
        return "\\" + PREFIX_FIRST + "\\" + PREFIX_SECOND + text + "\\" + PLACEHOLDER_SUFFIX;
    }

    public static String getDocKey(String mapKey) {
        return PLACEHOLDER_PREFIX + mapKey + PLACEHOLDER_SUFFIX;
    }

    /**
     * 判断当前占位符是不是一个图片占位符
     * @param text
     * @return
     */
    public static boolean isPicture(String text) {
        return text.startsWith(PICTURE_PREFIX);
    }

    /**
     * 删除一行的列
     * @param row
     */
    public static void removeCells(XWPFTableRow row) {
        int size = row.getTableCells().size();
        try {
            for (int i = 0; i < size; i++) {
//                row.removeCell(i);
            }
        } catch (Exception e) {

        }
    }
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值