当前位置: 首页 > 工具软件 > log4j-finder > 使用案例 >

dox4j笔记

章兴发
2023-12-01
package org.jeecg.modules.system.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.docx4j.TraversalUtil;
import org.docx4j.XmlUtils;
import org.docx4j.finders.ClassFinder;
import org.docx4j.jaxb.Context;
import org.docx4j.model.fields.FieldUpdater;
import org.docx4j.openpackaging.io3.Save;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.wml.Document;
import org.docx4j.wml.Tbl;
import org.docx4j.wml.Tr;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
@Component
public class VariableReplace {

    private static final Logger LOGGER = LoggerFactory.getLogger(VariableReplace.class);

    static {
        preLoadWordTemptal();
    }


    private static void preLoadWordTemptal () {
        try {
            String wordTemplateFilePath = CreditWordTemplateUtils.getCreditWordTemplateResourcePath("wordTemplateDir", 1);
            LOGGER.info("wordTemplateFilePath:{}", wordTemplateFilePath);
            ClassPathResource resource = new ClassPathResource(wordTemplateFilePath);
            try(InputStream rs = resource.getInputStream()) {
                //获取word模板文件的路径
                WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage
                        .load(rs);
            }
        }catch (Exception e){
            LOGGER.error("preLoadWordTemplate load fail");
        }
    }


    public static String  getNewWord(String flag, Map<String, String> mappings , List<Map<String, String>> getDataList1
            , HttpServletResponse response, String wordTemplateDir) throws Exception {


        //获取word模板文件的路径
        String wordTemplateFilePath = CreditWordTemplateUtils.getCreditWordTemplateResourcePath(wordTemplateDir, Integer.valueOf(flag));

        LOGGER.info("wordTemplateFilePath:{}", wordTemplateFilePath);

        ClassPathResource resource = new ClassPathResource(wordTemplateFilePath);
        WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage
                .load(resource.getInputStream());
        MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart();

        cleanDocumentPart(documentPart);

        int startIndex = 11;
        //单一
        if ("1".equals(flag)) {
            //替换表格1
            startIndex = 11;
        } else if ("2".equals(flag)) {
            startIndex = 12;
        }else if ("3".equals(flag)){
            startIndex = 7;
        }
        //替换表格1
        ClassFinder find = new ClassFinder(Tbl.class);
        new TraversalUtil(wordMLPackage.getMainDocumentPart().getContent(), find);
        Tbl table = (Tbl) find.results.get(0);


        if (ObjectUtils.isNotEmpty(getDataList1)) {
            Tr dynamicTr = (Tr) table.getContent().get(startIndex);
            String dynamicTrXml = XmlUtils.marshaltoString(dynamicTr);
            for (Map<String, String> dataMap : getDataList1) {
                // cleanDocumentPart(documentPart);
                Tr newTr = (Tr) XmlUtils.unmarshallFromTemplate(dynamicTrXml, dataMap);
                table.getContent().add(startIndex, newTr);
                startIndex++;
            }
            table.getContent().remove(startIndex);
        }


        //替换内容
        long start = System.currentTimeMillis();
        documentPart.variableReplace(mappings);
        long end = System.currentTimeMillis();
        long total = end - start;
        LOGGER.info("Time-------: {}", total);

        FieldUpdater fieldUpdater = new FieldUpdater(wordMLPackage);
        fieldUpdater.update(false);

        Save save1 = new Save(wordMLPackage);
        save1.save(response.getOutputStream());
        LOGGER.info("刷新输出流.....");
        response.getOutputStream().flush();

        return "";
    }


    public static  boolean cleanDocumentPart(MainDocumentPart documentPart) throws Exception {
        if (documentPart == null) {
            return false;
        }
        Document document = documentPart.getContents();
        String wmlTemplate =
                XmlUtils.marshaltoString(document, true, false, Context.jc);
        document = (Document) XmlUtils.unwrap(DocxVariableClearUtils.doCleanDocumentPart(wmlTemplate, Context.jc));
        documentPart.setContents(document);
        return true;
    }

    /**
     * 将金额格式转为三位一逗
     *
     * @return
     */
    public static String convertAccountFormat(String str) {
        if (StringUtils.isBlank(str)) {
            return "0.00";
        }
        //判断是否为数值型
        boolean matches = str.matches("-?[0-9]+.?[0-9]*");
        if (matches) {
            DecimalFormat df = new DecimalFormat("#,##0.00");
            String data = df.format(new BigDecimal(str));
            return data;
        }
        return str;
    }

    /**
     * 将日期中的“/”转化为“-”
     * 和yyyyMMdd格式的转换为yyyy-MM-dd
     *
     * @param dateStr
     * @return
     */
    public static String converDateFormat(String dateStr) {
        if (StringUtils.isNotBlank(dateStr)) {
            String str = null;
            if (dateStr.matches("^[0-9]{8}$")) {
                SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
                Date date = null;
                try {
                    date = format.parse(dateStr);
                } catch (ParseException e) {
                    e.printStackTrace();
                }
//                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日");
                str = dateFormat.format(date);
                return str;
            } else if (dateStr.length() > 8) {
                str = dateStr.replaceAll("/", "-");
                return str;
            } else {
                return dateStr;
            }
        }
        return "";
    }


    public static String extractFinanceNumber(String str) {
        try {
            double number = Double.parseDouble(str);
            return str;
        } catch (Exception e) {
            log.info("尽责报告表头获取金额为脏数据,用正则表达式提取");
            String regex = "[\\d|,|, ]+";
            Pattern pattern = Pattern.compile(regex);
            Matcher matcher = pattern.matcher(str);
            return matcher.find() ? matcher.group(0).replaceAll(",|,", "") : "";
        }
    }

    /**
     * 日期处理:
     "20211001",
     "2021-10-01",
     "2021/10/01",
     "2021-10-01/12:23:00",
     "2021/10/01 12:23:00",
     "2021/10/01 12:23:00"
     * */
    public static String converDateString(String str){
        String date;
        Pattern pattern1 = Pattern.compile("^\\d{4}-\\d{1,2}-\\d{1,2}");
        Matcher matcher1 = pattern1.matcher(str);
        if (matcher1.find()){
            date=matcher1.group();
            String[] dateStrs=date.split("-");
            return dateStrs[0]+
                    (dateStrs[1].length()==1?"-0"+dateStrs[1]:"-"+dateStrs[1])+
                    (dateStrs[2].length()==1?"-0"+dateStrs[2]:"-"+dateStrs[2]);
        }

        Pattern pattern2 = Pattern.compile("^\\d{8}");
        Matcher matcher2 = pattern2.matcher(str);
        if (matcher2.find()){
            date=matcher2.group();
            return date.replaceAll("(?<=^\\d{4})|(?<=^\\d{6})","-");
        }

        Pattern pattern3 = Pattern.compile("^\\d{4}/\\d{1,2}/\\d{1,2}");
        Matcher matcher3 = pattern3.matcher(str);
        if (matcher3.find()){
            date=matcher3.group();
            String[] dateStrs=date.split("/");
            return dateStrs[0]+
                    (dateStrs[1].length()==1?"-0"+dateStrs[1]:"-"+dateStrs[1])+
                    (dateStrs[2].length()==1?"-0"+dateStrs[2]:"-"+dateStrs[2]);
        }
        return str;
    }
}







扫清${variable}格式

package com.amarsoft.app.afrs.core.utils;

import org.docx4j.XmlUtils;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import java.util.regex.Pattern;

/**
 * 清扫 docx4j 模板变量字符,通常以${variable}形式
 *

 * XXX: 主要在上传模板时处理一下, 后续
 *
 * @author liliang
 * @since 2018-11-07
 */
public class DocxVariableClearUtils {


    /**
     * 去任意XML标签
     */
    private static final Pattern XML_PATTERN = Pattern.compile("<[^>]*>");

    private DocxVariableClearUtils() {
    }

    /**
     * start符号
     */
    private static final char PREFIX = '$';

    /**
     * 中包含
     */
    private static final char LEFT_BRACE = '{';

    /**
     * 结尾
     */
    private static final char RIGHT_BRACE = '}';

    /**
     * 未开始
     */
    private static final int NONE_START = -1;

    /**
     * 未开始
     */
    private static final int NONE_START_INDEX = -1;

    /**
     * 开始
     */
    private static final int PREFIX_STATUS = 1;

    /**
     * 左括号
     */
    private static final int LEFT_BRACE_STATUS = 2;

    /**
     * 右括号
     */
    private static final int RIGHT_BRACE_STATUS = 3;


    /**
     * doCleanDocumentPart
     *
     * @param wmlTemplate
     * @param jc
     * @return
     * @throws JAXBException
     */
    public static Object doCleanDocumentPart(String wmlTemplate, JAXBContext jc) throws JAXBException {
        // 进入变量块位置
        int curStatus = NONE_START;
        // 开始位置
        int keyStartIndex = NONE_START_INDEX;
        // 当前位置
        int curIndex = 0;
        char[] textCharacters = wmlTemplate.toCharArray();
        StringBuilder documentBuilder = new StringBuilder(textCharacters.length);
        documentBuilder.append(textCharacters);
        // 新文档
        StringBuilder newDocumentBuilder = new StringBuilder(textCharacters.length);
        // 最后一次写位置
        int lastWriteIndex = 0;
        for (char c : textCharacters) {
            switch (c) {
                case PREFIX:
                    // TODO 不管其何状态直接修改指针,这也意味着变量名称里面不能有PREFIX
                    keyStartIndex = curIndex;
                    curStatus = PREFIX_STATUS;
                    break;
                case LEFT_BRACE:
                    if (curStatus == PREFIX_STATUS) {
                        curStatus = LEFT_BRACE_STATUS;
                    }
                    break;
                case RIGHT_BRACE:
                    if (curStatus == LEFT_BRACE_STATUS) {
                        // 接上之前的字符
                        newDocumentBuilder.append(documentBuilder.substring(lastWriteIndex, keyStartIndex));
                        // 结束位置
                        int keyEndIndex = curIndex + 1;
                        // 替换
                        String rawKey = documentBuilder.substring(keyStartIndex, keyEndIndex);
                        // 干掉多余标签
                        String mappingKey = XML_PATTERN.matcher(rawKey).replaceAll("");
                        if (!mappingKey.equals(rawKey)) {
                            char[] rawKeyChars = rawKey.toCharArray();
                            // 保留原格式
                            StringBuilder rawStringBuilder = new StringBuilder(rawKey.length());
                            // 去掉变量引用字符
                            for (char rawChar : rawKeyChars) {
                                if (rawChar == PREFIX || rawChar == LEFT_BRACE || rawChar == RIGHT_BRACE) {
                                    continue;
                                }
                                rawStringBuilder.append(rawChar);
                            }
                            // FIXME 要求变量连在一起
                            String variable = mappingKey.substring(2, mappingKey.length() - 1);
                            int variableStart = rawStringBuilder.indexOf(variable);
                            if (variableStart > 0) {
                                rawStringBuilder = rawStringBuilder.replace(variableStart, variableStart + variable.length(), mappingKey);
                            }
                            newDocumentBuilder.append(rawStringBuilder.toString());
                        } else {
                            newDocumentBuilder.append(mappingKey);
                        }
                        lastWriteIndex = keyEndIndex;

                        curStatus = NONE_START;
                        keyStartIndex = NONE_START_INDEX;
                    }
                default:
                    break;
            }
            curIndex++;
        }
        // 余部
        if (lastWriteIndex < documentBuilder.length()) {
            newDocumentBuilder.append(documentBuilder.substring(lastWriteIndex));
        }
        return XmlUtils.unmarshalString(newDocumentBuilder.toString(), jc);
    }

}

合并单元格子

package com.amarsoft.app;

import org.docx4j.wml.*;

import javax.xml.bind.JAXBElement;
import java.util.ArrayList;
import java.util.List;

public class MergeCell {

  public static void main(String[] args) {
        //替换表格
        ClassFinder find = new ClassFinder(Tbl.class);
        new TraversalUtil(wordMLPackage.getMainDocumentPart().getContent(),find);

        Tbl table = (Tbl) find.results.get(0);
        Tr dynamicTr = (Tr) table.getContent().get(11);
        String dynamicTrXml = XmlUtils.marshaltoString(dynamicTr);
        int startIndex = 11;
        List<Map<String, Object>> dataList = getDataList();
        for(Map<String, Object> dataMap : dataList){
            // cleanDocumentPart(documentPart);
            Tr newTr = (Tr) XmlUtils.unmarshallFromTemplate(dynamicTrXml,dataMap);

            table.getContent().add(startIndex,newTr);
            startIndex++;
        }
        table.getContent().remove(startIndex);

        new MergeCell().mergeCellsVertically(table,0,11,20);
    }



    /**
     * @Description: 跨列合并
     */
    public void mergeCellsHorizontal(Tbl tbl, int row, int fromCell, int toCell) {
        if (row < 0 || fromCell < 0 || toCell < 0) {
            return;
        }
        List<Tr> trList = getTblAllTr(tbl);
        if (row > trList.size()) {
            return;
        }
        Tr tr = trList.get(row);
        List<Tc> tcList = getTrAllCell(tr);
        for (int cellIndex = fromCell, len = Math
                .min(tcList.size() - 1, toCell); cellIndex <= len; cellIndex++) {
            Tc tc = tcList.get(cellIndex);
            TcPr tcPr = getTcPr(tc);
            TcPrInner.HMerge hMerge = tcPr.getHMerge();
            if (hMerge == null) {
                hMerge = new TcPrInner.HMerge();
                tcPr.setHMerge(hMerge);
            }
            if (cellIndex == fromCell) {
                hMerge.setVal("restart");
            } else {
                hMerge.setVal("continue");
            }
        }
    }

    /**
     * @Description: 跨行合并
     */
    public void mergeCellsVertically(Tbl tbl, int col, int fromRow, int toRow) {
        if (col < 0 || fromRow < 0 || toRow < 0) {
            return;
        }
        for (int rowIndex = fromRow; rowIndex <= toRow; rowIndex++) {
            Tc tc = getTc(tbl, rowIndex, col);
            if (tc == null) {
                break;
            }
            TcPr tcPr = getTcPr(tc);
            TcPrInner.VMerge vMerge = tcPr.getVMerge();
            if (vMerge == null) {
                vMerge = new TcPrInner.VMerge();
                tcPr.setVMerge(vMerge);
            }
            if (rowIndex == fromRow) {
                vMerge.setVal("restart");
            } else {
                vMerge.setVal("continue");
            }
        }
    }

    /**
     * @Description:得到指定位置的表格
     */
    public Tc getTc(Tbl tbl, int row, int cell) {
        if (row < 0 || cell < 0) {
            return null;
        }
        List<Tr> trList = getTblAllTr(tbl);
        if (row >= trList.size()) {
            return null;
        }
        List<Tc> tcList = getTrAllCell(trList.get(row));
        if (cell >= tcList.size()) {
            return null;
        }
        return tcList.get(cell);
    }

    /**
     * @Description: 获取所有的单元格
     */
    public List<Tc> getTrAllCell(Tr tr) {
        List<Object> objList = getAllElementFromObject(tr, Tc.class);
        List<Tc> tcList = new ArrayList<Tc>();
        if (objList == null) {
            return tcList;
        }
        for (Object tcObj : objList) {
            if (tcObj instanceof Tc) {
                Tc objTc = (Tc) tcObj;
                tcList.add(objTc);
            }
        }
        return tcList;
    }

    public TcPr getTcPr(Tc tc) {
        TcPr tcPr = tc.getTcPr();
        if (tcPr == null) {
            tcPr = new TcPr();
            tc.setTcPr(tcPr);
        }
        return tcPr;
    }

    /**
     * @Description: 得到表格所有的行
     */
    public List<Tr> getTblAllTr(Tbl tbl) {
        List<Object> objList = getAllElementFromObject(tbl, Tr.class);
        List<Tr> trList = new ArrayList<Tr>();
        if (objList == null) {
            return trList;
        }
        for (Object obj : objList) {
            if (obj instanceof Tr) {
                Tr tr = (Tr) obj;
                trList.add(tr);
            }
        }
        return trList;
    }

    /**
     * @Description:得到指定类型的元素
     */
    public static List<Object> getAllElementFromObject(Object obj,
                                                       Class<?> toSearch) {
        List<Object> result = new ArrayList<Object>();
        if (obj instanceof JAXBElement)
            obj = ((JAXBElement<?>) obj).getValue();
        if (obj.getClass().equals(toSearch))
            result.add(obj);
        else if (obj instanceof ContentAccessor) {
            List<?> children = ((ContentAccessor) obj).getContent();
            for (Object child : children) {
                result.addAll(getAllElementFromObject(child, toSearch));
            }
        }
        return result;
    }

}

添加响应头信息

   /**
     * 添加响应头信息
     *
     * @param response
     * @param fileName
     * @throws Exception
     */
    private void setResponseHeader(HttpServletResponse response, String fileName) throws Exception {
        try {
            try {
                fileName = new String(fileName.getBytes(), "ISO8859-1");
            } catch (UnsupportedEncodingException e) {
                log.error("尽责报告导出失败", e);
                throw e;
            }
            response.setContentType("application/octet-stream;charset=ISO8859-1");
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
            response.addHeader("Pargam", "no-cache");
            response.addHeader("Cache-Control", "no-cache");
        } catch (Exception e) {
            log.error("尽责报告导出失败", e);
            throw e;
        }
    }
 类似资料: