POI操作Word生成报告

wylc123 1年前 ⋅ 1251 阅读

一、使用情景

        以模板为基础,模板中可以包括poi操作比较困难的内容,比如有文本框布局的报告头,页眉页脚等。然后,用poi替换模板中的相关信息,包括表格,段落,文本框中的变量,比如期刊号,日期等。用Poi写入表格,带合并单元格的,段落,图片。

二、通过word模板生成新的word工具类

package cnki.jxjob.base;

import cnki.jxjob.config.ChromeDriverConf;
import org.apache.poi.POIXMLDocument;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlObject;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR;

import javax.xml.namespace.QName;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.*;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 通过word模板生成新的word工具类
 * @author SongBin on 2019/9/5.
 */

public class WorderToNewWordUtils {

    /**
     * 根据模板生成新word文档
     * 判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入
     * @param inputUrl 模板存放地址
     * @param outputUrl 新文档存放地址
     * @param textMap 需要替换的信息集合
     * @param tableList 需要插入的表格信息集合
     * @return 成功返回true,失败返回false
     */
    public static boolean changWord(String inputUrl, String outputUrl,
                                    Map<String, String> textMap, List<String[]> tableList, Map<String ,String> imgMap) {

        //模板转换默认成功
        boolean changeFlag = true;
        try {
            //获取docx解析对象
            XWPFDocument document = new XWPFDocument(POIXMLDocument.openPackage(inputUrl));
            //解析替换文本段落对象
            WorderToNewWordUtils.changeText(document, textMap,imgMap);
            //解析替换表格对象
            WorderToNewWordUtils.changeTable(document, textMap, tableList);

            //生成新的word
            File file = new File(outputUrl);
            FileOutputStream stream = new FileOutputStream(file);
            document.write(stream);
            stream.close();

        } catch (IOException e) {
            e.printStackTrace();
            changeFlag = false;
        }

        return changeFlag;

    }

    /**
     * 根据无表格模板生成新word文档
     * @param inputUrl 模板存放地址
     * @param outputUrl 新文档存放地址
     * @param textMap 需要替换的信息集合
     * @return 成功返回true,失败返回false
     */
    public static boolean changWord(String inputUrl, String outputUrl,
                                    Map<String, String> textMap, Map<String ,String> imgMap) {
        //模板转换默认成功
        boolean changeFlag = true;
        try {
            //获取docx解析对象
            XWPFDocument document = new XWPFDocument(POIXMLDocument.openPackage(inputUrl));
            //解析替换文本段落对象
            WorderToNewWordUtils.changeText(document, textMap,imgMap);
            //生成新的word
            File file = new File(outputUrl);
            FileOutputStream stream = new FileOutputStream(file);
            document.write(stream);
            stream.close();
        } catch (IOException e) {
            e.printStackTrace();
            changeFlag = false;
        }
        return changeFlag;
    }

    /**
     * 遍历word获取每种农产品需要统计的菜品类型
     * @param inputUrl 模板地址
     * @return
     */
    public static Map<String,String> getClassifyObj(String inputUrl){
        Map<String,String> map = new HashMap<>();
        try {
            //获取docx解析对象
            XWPFDocument document = new XWPFDocument(POIXMLDocument.openPackage(inputUrl));
            //获取段落集合
            List<XWPFParagraph> paragraphs = document.getParagraphs();
            int i = 1;
            for (XWPFParagraph paragraph : paragraphs) {
                //判断此段落时候需要进行替换
                String text = paragraph.getText();
                Matcher m = Pattern.compile("(?d)——(.+?))$").matcher(text);
                if (m.find()) {
                    Matcher matcher=Pattern.compile("(?d)((.+?))$").matcher(text);
                    if (matcher.find()){
                        String objstr = matcher.group(1).replace('、',',');
                        map.put("obj0"+i,objstr);
                        i++;
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return map;
    }

    /**
     * 替换段落文本
     * @param document docx解析对象
     * @param textMap 需要替换的信息集合
     */
    public static void changeText(XWPFDocument document, Map<String, String> textMap, Map<String ,String> imgMap){
        //获取段落集合
        List<XWPFParagraph> paragraphs = document.getParagraphs();

        for (XWPFParagraph paragraph : paragraphs) {
            //判断此段落时候需要进行替换
            String text = paragraph.getText();
            if(checkText(text)){
                List<XWPFRun> runs = paragraph.getRuns();
                XWPFRun run0 = runs.get(0);
                if(text.matches("(?d)^\\$img0[1-5]")){//插入图片
                    for (XWPFRun run : runs) {
                        //替换模板原来位置
                        run.setText("",0);
                    }
                    changeParagraphImg(run0,imgMap.get(text));
                }else{
                    if (text.indexOf(":")!= -1&&runs.size()>1){
                        run0.setText(text.substring(0,text.indexOf(":")+1),0);
                        XWPFRun run1 = runs.get(1);
                        for (int i=1;i<runs.size();i++) {
                            //替换模板原来位置
                            XWPFRun run = runs.get(i);
                            run.setText("",0);
                        }
                        text = text.replaceAll("(?d)^(.+?):","");
                        //替换模板原来位置
                        run1.setText(changeValue(text, textMap),0);
                        run1.setBold(false);
                    }else{
                        for (XWPFRun run : runs) {
                            //替换模板原来位置
                            run.setText("",0);
                        }
                        //替换模板原来位置
                        run0.setText(changeValue(text, textMap),0);
                    }
                }
            }
        }

    }
    /******************处理文本框内容*******************************/
    public static List<String>patternList=new ArrayList();
    //需要处理的节点名称
    static {
        patternList.add("mc:AlternateContent");
        patternList.add("mc:Choice");
        patternList.add("w:drawing");
        patternList.add("wp:anchor");
        patternList.add("a:graphic");
        patternList.add("a:graphicData");
        patternList.add("wps:wsp");
        patternList.add("wps:txbx");
        patternList.add("w:txbxContent");
        patternList.add("w:p");
        patternList.add("w:r");
        patternList.add("w:t");
    }

    public static void changeTextBox( XWPFDocument document,Map<String, String>map) {
        for(XWPFParagraph paragraph:document.getParagraphs())
            for(XmlObject object:paragraph.getCTP().getRArray())
            {
                XmlCursor cursor = object.newCursor();
                eachchild(cursor, 0,map);
            }
    }

    //回朔查找,因为并不是每一个文本框中只有一个可替换的地方
    public static void eachchild(XmlCursor cursor,int start,Map<String, String>map) {

        //预计子节点个数应该是小于10个节点
        for(int i=0;i<10;i++)
        {
            //如果可以移动到子节点i
            if(cursor.toChild(i)) {
                //如果移动到达的子节点正好是按照顺序是需要的节点 则继续前往下一层
                if(cursor.getDomNode().getNodeName().equals(patternList.get(start))) {
                    if(start==patternList.size()-1) {
                        String reString=cursor.getTextValue();
                        for(String e:map.keySet()) {
                            if(reString.contains(e)) {
                                //    执行替换
                                reString=reString.replaceAll(e, map.get(e));
                            }
                        }

                        //bingo  设置替换节点内容
                        cursor.setTextValue(reString);
                    }

                    //继续下一层  遍历
                    eachchild(cursor,start+1,map);
                }else {
                    cursor.toParent();
                }
            }
        }

//  此处很重要,如果命中或者未命中都需要 遍历其他节点
        cursor.toParent();
    }

    /******************处理文本框内容结束*******************************/
    /**
     * 替换段落文本
     * @param document docx解析对象
     * @param textMap 需要替换的信息集合
     */
    public static void changeText(XWPFDocument document, Map<String, String> textMap){
        //获取段落集合
        List<XWPFParagraph> paragraphs = document.getParagraphs();
        for (XWPFParagraph paragraph : paragraphs) {
            //判断此段落时候需要进行替换
            String text = paragraph.getText();
            if(checkText(text)){
                List<XWPFRun> runs = paragraph.getRuns();
                XWPFRun run0 = runs.get(0);
                for (XWPFRun run : runs) {
                    //替换模板原来位置
                    run.setText("",0);
                }
                //替换模板原来位置
                run0.setText(changeValue(text, textMap),0);
            }
        }

    }
    /**
     * 插入图片
     * @param run
     * @param imgGuid
     */
    public static void changeParagraphImg(XWPFRun run, String imgGuid){
        try {
            String basePath =StringUtil.isBlank(ChromeDriverConf.picSavePath)?"D:/imgupload/":ChromeDriverConf.picSavePath;
            String imgFile = basePath + imgGuid +".jpg";
            System.out.println("插入图表图片:" + imgFile);
            FileInputStream is = new FileInputStream(imgFile);
            run.addPicture(is, XWPFDocument.PICTURE_TYPE_JPEG, imgFile, Units.toEMU(400), Units.toEMU(300)); // 100x100 pixels
            is.close();
            run.setText("",0);
        } catch (Exception e) {
            System.out.println("Error: ========  插入单个图片时出错了:可能是图片路径不存在。不影响主流程");
            e.printStackTrace();
        }
    }

    /**
     * 替换表格对象方法
     * @param document docx解析对象
     * @param textMap 需要替换的信息集合
     * @param tableList 需要插入的表格信息集合
     */
    public static void changeTable(XWPFDocument document, Map<String, String> textMap,
                                   List<String[]> tableList){
        //获取表格对象集合
        List<XWPFTable> tables = document.getTables();
        for (int i = 0; i < tables.size(); i++) {
            //只处理行数大于等于2的表格,且不循环表头
            XWPFTable table = tables.get(i);
            if(table.getRows().size()>1){
                //判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入
                if(checkText(table.getText())){
                    List<XWPFTableRow> rows = table.getRows();
                    //遍历表格,并替换模板
                    eachTable(rows, textMap);
                }else{
//                  System.out.println("插入"+table.getText());
                    insertTable(table, tableList);
                }
            }
        }
    }





    /**
     * 遍历表格
     * @param rows 表格行对象
     * @param textMap 需要替换的信息集合
     */
    public static void eachTable(List<XWPFTableRow> rows ,Map<String, String> textMap){
        for (XWPFTableRow row : rows) {
            List<XWPFTableCell> cells = row.getTableCells();
            for (XWPFTableCell cell : cells) {
                //判断单元格是否需要替换
                if(checkText(cell.getText())){
                    List<XWPFParagraph> paragraphs = cell.getParagraphs();
                    for (XWPFParagraph paragraph : paragraphs) {
                        List<XWPFRun> runs = paragraph.getRuns();
                        for (XWPFRun run : runs) {
                            run.setText(changeValue(run.toString(), textMap),0);
                        }
                    }
                }
            }
        }
    }

    /**
     * 为表格插入数据,行数不够添加新行
     * @param table 需要插入数据的表格
     * @param tableList 插入数据集合
     */
    public static void insertTable(XWPFTable table, List<String[]> tableList){
        //创建行,根据需要插入的数据添加新行,不处理表头
        for(int i = 1; i < tableList.size(); i++){
            XWPFTableRow row =table.createRow();
        }
        //遍历表格插入数据
        List<XWPFTableRow> rows = table.getRows();
        for(int i = 1; i < rows.size(); i++){
            XWPFTableRow newRow = table.getRow(i);
            List<XWPFTableCell> cells = newRow.getTableCells();
            for(int j = 0; j < cells.size(); j++){
                XWPFTableCell cell = cells.get(j);
                cell.setText(tableList.get(i-1)[j]);
            }
        }

    }



    /**
     * 判断文本中是否包含$
     * @param text 文本
     * @return 包含返回true,不包含返回false
     */
    public static boolean checkText(String text){
        boolean check  =  false;
        if(text.indexOf("$")!= -1){
            check = true;
        }
        return check;

    }

    /**
     * 匹配传入信息集合与模板
     * @param value 模板需要替换的区域
     * @param textMap 传入信息集合
     * @return 模板需要替换区域信息集合对应值
     */
    public static String changeValue(String value, Map<String, String> textMap){
        Set<Entry<String, String>> textSets = textMap.entrySet();
        for (Entry<String, String> textSet : textSets) {
            //匹配模板与替换值 格式${key}
            String key = "${"+textSet.getKey()+"}";
            String regexstr = "(?d)\\$\\{"+textSet.getKey()+"\\}";
            if(value.indexOf(key)!= -1){
                value = value.replaceAll(regexstr,textSet.getValue());
            }
        }
        //模板未匹配到区域替换为空
        if(checkText(value)){
            value = value.replaceAll("(?d)\\$\\{(.+?)\\}","");
        }
        value = value.replaceAll("(以上所列全部类目)","");
        return value;
    }




    public static void main(String[] args) {
//        测试1
        //模板文件地址
        /*String inputUrl = "C:\\Users\\SongBin\\Desktop\\demo\\001.docx";
        //新生产的模板文件
        String outputUrl = "C:\\Users\\SongBin\\Desktop\\demo\\test.docx";

        Map<String, String> testMap = new HashMap<String, String>();
        testMap.put("name", "小明");
        testMap.put("sex", "男");
        testMap.put("age", "30");
        testMap.put("like", "IT");
        testMap.put("birthday", "2019-02-18");
        testMap.put("address", "软件园");
        testMap.put("phone", "18612100611");
        testMap.put("email", "1370811553@qq.com");

        List<String[]> testList = new ArrayList<String[]>();
        testList.add(new String[]{"1","1AA","1BB","1CC"});
        testList.add(new String[]{"2","2AA","2BB","2CC"});
        testList.add(new String[]{"3","3AA","3BB","3CC"});
        testList.add(new String[]{"4","4AA","4BB","4CC"});

        WorderToNewWordUtils.changWord(inputUrl, outputUrl, testMap, testList);*/



//        测试2
        //模板文件地址
        String inputUrl2 = "C:\\Users\\SongBin\\Desktop\\demo\\报告模板-价格.docx";
        //新生产的模板文件
        String outputUrl2 = "C:\\Users\\SongBin\\Desktop\\demo\\test.docx";

        Map<String, String> testMap2 = new HashMap<String, String>();
        testMap2.put("datetime", "2019-02-06");
        testMap2.put("粳米(普通)","粳米(普通)25元/公斤;");
        testMap2.put("大米","大米25元/公斤;");
        testMap2.put("week","07.16-7-22 ");
        Map<String ,String> imgMap = new HashMap<>();
        imgMap.put("$img01","3f956a32-f236-4baa-a8be-f465fa844580");
        imgMap.put("$img02","3f956a32-f236-4baa-a8be-f465fa844580");
        imgMap.put("$img03","3f956a32-f236-4baa-a8be-f465fa844580");
        imgMap.put("$img04","3f956a32-f236-4baa-a8be-f465fa844580");
        imgMap.put("$img05","3f956a32-f236-4baa-a8be-f465fa844580");
        WorderToNewWordUtils.changWord(inputUrl2, outputUrl2, testMap2,imgMap);

        String content = "在一些字里面放进去高中这两个字";

        Matcher matcher = Pattern.compile("高中").matcher(content);
        while (matcher.find()) {
            System.out.println(matcher.group(1));
        }
        //判断此段落时候需要进行替换
        /*String text = "近一周09.05-09.11农产品价格走势图——蔬菜(大白菜、小白菜、油菜、白萝卜、西红柿、黄瓜、茄子、香菇、平菇)";
        Matcher m = Pattern.compile("(?d)——(.+?))$").matcher(text);
        if (m.find()) {
            Matcher matcher=Pattern.compile("(?d)((.+?))$").matcher(text);
            if (matcher.find()){
                String objstr = matcher.group(1).replace('、',',');
                System.out.println(objstr);
            }
        }*/

        //测试但斜杠转转双斜杠
        //模板文件地址
        /*String inputUrl = null;
        try {
            inputUrl = ResourceUtils.getURL("classpath:static/wordmodel/报告模板-价格.docx").getPath().substring(1);
            inputUrl = inputUrl.replaceAll("/", "\\\\\\\\");
            try {
                inputUrl = java.net.URLDecoder.decode(inputUrl,"utf-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            System.out.println(inputUrl);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }*/
    }
}

三、写入Word工具类

/**
 * @author SongBin on 2020/9/3.
 */
package cnki.jxjob.base;

import java.io.*;
import java.math.BigInteger;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import cnki.jxjob.entity.ParagraphStyle;
import cnki.jxjob.entity.TextStyle;
import org.apache.poi.POIXMLDocument;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
import org.apache.poi.xwpf.usermodel.TextAlignment;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFPicture;
import org.apache.poi.xwpf.usermodel.XWPFPictureData;
import org.apache.poi.xwpf.usermodel.XWPFRelation;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTFonts;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHyperlink;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTInd;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSpacing;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTText;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STLineSpacingRule;


/**
 * @Description 设置docx文档的样式及一些操作
 * 2020年09月03日  下午4:20:05
 * @Author SongBin
 * 基本概念说明:XWPFDocument代表一个docx文档,其可以用来读docx文档,也可以用来写docx文档
 *     XWPFParagraph代表文档、表格、标题等种的段落,由多个XWPFRun组成
 *     XWPFRun代表具有同样风格的一段文本
 *  XWPFTable代表一个表格
 *  XWPFTableRow代表表格的一行
 *  XWPFTableCell代表表格的一个单元格
 *  XWPFChar 表示.docx文件中的图表
 *  XWPFHyperlink 表示超链接
 *  XWPFPicture  代表图片
 *
 *  注意:直接调用XWPFRun的setText()方法设置文本时,在底层会重新创建一个XWPFRun。
 */
public class XWPFHelper {
    private static Logger logger = Logger.getLogger(XWPFHelper.class.toString());

    /**
     * 在模板基础上创建一个word对象
     * @return
     * @Author Huangxiaocong 2018年12月1日 上午11:56:35
     */
    public XWPFDocument createDocumentLikeModel(String inputUrl) {
        //模板转换默认成功
        XWPFDocument document = null;
        try {
            //获取docx解析对象
            document = new XWPFDocument(POIXMLDocument.openPackage(inputUrl));
        } catch (IOException e) {
            e.printStackTrace();
        }

        return document;
    }

    /**
     * 创建一个word对象
     * @return
     * @Author Huangxiaocong 2018年12月1日 上午11:56:35
     */
    public XWPFDocument createDocument() {
        XWPFDocument document = new XWPFDocument();
        return document;
    }
    /**
     * 打开word文档
     * @param path 文档所在路径
     * @return
     * @throws IOException
     * @Author Huangxiaocong 2018年12月1日 下午12:30:07
     */
    public XWPFDocument openDoc(String path) throws IOException {
        InputStream is = new FileInputStream(path);
        return new XWPFDocument(is);
    }
    /**
     * 保存word文档
     * @param document 文档对象
     * @param savePath    保存路径
     * @throws IOException
     * @Author Huangxiaocong 2018年12月1日 下午12:32:37
     */
    public void saveDocument(XWPFDocument document, String savePath) throws IOException {
        OutputStream os = new FileOutputStream(savePath);
        document.write(os);
        os.close();
    }
    /**
     * 设置段落文本样式  设置超链接及样式
     * @param paragraph
     * @param textStyle
     * @param url
     * @Author Huangxiaocong 2018年12月1日 下午3:56:32
     */
    public void addParagraphTextHyperlink(XWPFParagraph paragraph, TextStyle textStyle) {
        String id = paragraph.getDocument().getPackagePart().
                addExternalRelationship(textStyle.getUrl(),
                        XWPFRelation.HYPERLINK.getRelation()).getId();
        //追加链接并将其绑定到关系中
        CTHyperlink cLink = paragraph.getCTP().addNewHyperlink();
        cLink.setId(id);
        //创建链接文本
        CTText ctText = CTText.Factory.newInstance();
        ctText.setStringValue(textStyle.getText());
        CTR ctr = CTR.Factory.newInstance();
        CTRPr rpr = ctr.addNewRPr();
        //以下设置各种样式 详情看TextStyle类
        if(textStyle.getFontFamily() != "" && textStyle.getFontFamily() != null     ) {
            CTFonts fonts = rpr.isSetRFonts() ? rpr.getRFonts() : rpr.addNewRFonts();
            fonts.setAscii(textStyle.getFontFamily());
            //...
        }
        //设置字体大小
    }
    /**
     * 设置段落的基本样式  设置段落间距信息, 一行 = 100    一磅=20
     * @param paragraph
     * @param paragStyle
     * @Author Huangxiaocong 2018年12月1日 下午4:27:17
     */
    public void setParagraphSpacingInfo(XWPFParagraph paragraph, ParagraphStyle paragStyle, STLineSpacingRule.Enum lineValue) {
        CTPPr pPPr = getParagraphCTPPr(paragraph);
        CTSpacing pSpacing = pPPr.getSpacing() != null ? pPPr.getSpacing() : pPPr.addNewSpacing();
        if(paragStyle.isSpace()) {
            //段前磅数
            if(paragStyle.getBefore() != null) {
                pSpacing.setBefore(new BigInteger(paragStyle.getBefore()));
            }
            //段后磅数
            if(paragStyle.getAfter() != null) {
                pSpacing.setAfter(new BigInteger(paragStyle.getAfter()));
            }
            //依次设置段前行数、段后行数
            //...
        }
        //间距
        if(paragStyle.isLine()) {
            if(paragStyle.getLine() != null) {
                pSpacing.setLine(new BigInteger(paragStyle.getLine()));
            }
            if(lineValue != null) {
                pSpacing.setLineRule(lineValue);    //
            }
        }
    }
    /**
     * 设置段落缩进信息  1厘米 约等于 567
     * @param paragraph
     * @param paragStyle
     * @Author Huangxiaocong 2018年12月1日 下午7:59:35
     */
    public void setParagraphIndInfo(XWPFParagraph paragraph, ParagraphStyle paragStyle) {
        CTPPr pPPr = getParagraphCTPPr(paragraph);
        CTInd pInd = pPPr.getInd() != null ? pPPr.getInd() : pPPr.addNewInd();
        if(paragStyle.getFirstLine() != null) {
            pInd.setFirstLine(new BigInteger(paragStyle.getFirstLine()));
        }
        //再进行其他设置
        //...
    }
    /**
     * 设置段落对齐 方式
     * @param paragraph
     * @param pAlign
     * @param valign
     * @Author Huangxiaocong 2018年12月1日 下午8:54:43
     */
    public void setParagraphAlignInfo(XWPFParagraph paragraph, ParagraphAlignment pAlign, TextAlignment valign) {
        if(pAlign != null) {
            paragraph.setAlignment(pAlign);
        }
        if(valign != null) {
            paragraph.setVerticalAlignment(valign);
        }
    }
    /**
     * 得到段落的CTPPr
     * @param paragraph
     * @return
     * @Author Huangxiaocong 2018年12月1日 下午7:36:10
     */
    public CTPPr getParagraphCTPPr(XWPFParagraph paragraph) {
        CTPPr pPPr = null;
        if(paragraph.getCTP() != null) {
            if(paragraph.getCTP().getPPr() != null) {
                pPPr = paragraph.getCTP().getPPr();
            } else {
                pPPr = paragraph.getCTP().addNewPPr();
            }
        }
        return pPPr;
    }
    /**
     * 得到XWPFRun的CTRPr
     * @param paragraph
     * @param pRun
     * @return
     * @Author Huangxiaocong 2018年12月1日 下午7:46:01
     */
    public CTRPr getRunCTRPr(XWPFParagraph paragraph, XWPFRun pRun) {
        CTRPr ctrPr = null;
        if(pRun.getCTR() != null) {
            ctrPr = pRun.getCTR().getRPr();
            if(ctrPr == null) {
                ctrPr = pRun.getCTR().addNewRPr();
            }
        } else {
            ctrPr = paragraph.getCTP().addNewR().addNewRPr();
        }
        return ctrPr;
    }


    /**
     * 复制表格
     * @param targetTable
     * @param sourceTable
     * @Author Huangxiaocong 2018年12月1日 下午1:40:01
     */
    public void copyTable(XWPFTable targetTable, XWPFTable sourceTable) {
        //复制表格属性
        targetTable.getCTTbl().setTblPr(sourceTable.getCTTbl().getTblPr());
        //复制行
        for(int i = 0; i < sourceTable.getRows().size(); i++) {
            XWPFTableRow targetRow = targetTable.getRow(i);
            XWPFTableRow sourceRow = sourceTable.getRow(i);
            if(targetRow == null) {
                targetTable.addRow(sourceRow);
            } else {
                copyTableRow(targetRow, sourceRow);
            }
        }
    }
    /**
     * 复制单元格
     * @param targetRow
     * @param sourceRow
     * @Author Huangxiaocong 2018年12月1日 下午1:33:22
     */
    public void copyTableRow(XWPFTableRow targetRow, XWPFTableRow sourceRow) {
        //复制样式
        if(sourceRow != null) {
            targetRow.getCtRow().setTrPr(sourceRow.getCtRow().getTrPr());
        }
        //复制单元格
        for(int i = 0; i < sourceRow.getTableCells().size(); i++) {
            XWPFTableCell tCell = targetRow.getCell(i);
            XWPFTableCell sCell = sourceRow.getCell(i);
            if(tCell == sCell) {
                tCell = targetRow.addNewTableCell();
            }
            copyTableCell(tCell, sCell);
        }
    }
    /**
     * 复制单元格(列) 从sourceCell到targetCell
     * @param targetCell
     * @param sourceCell
     * @Author Huangxiaocong 2018年12月1日 下午1:27:38
     */
    public void copyTableCell(XWPFTableCell targetCell, XWPFTableCell sourceCell) {
        //表格属性
        if(sourceCell.getCTTc() != null) {
            targetCell.getCTTc().setTcPr(sourceCell.getCTTc().getTcPr());
        }
        //删除段落
        for(int pos = 0; pos < targetCell.getParagraphs().size(); pos++) {
            targetCell.removeParagraph(pos);
        }
        //添加段落
        for(XWPFParagraph sourceParag : sourceCell.getParagraphs()) {
            XWPFParagraph targetParag = targetCell.addParagraph();
            copyParagraph(targetParag, sourceParag);
        }
    }
    /**
     * 复制段落,从sourceParag到targetParag
     * @param targetParag
     * @param sourceParag
     * @Author Huangxiaocong 2018年12月1日 下午1:16:26
     */
    public void copyParagraph(XWPFParagraph targetParag, XWPFParagraph sourceParag) {
        targetParag.getCTP().setPPr(sourceParag.getCTP().getPPr());    //设置段落样式
        //移除所有的run
        for(int pos = targetParag.getRuns().size() - 1; pos >= 0; pos-- ) {
            targetParag.removeRun(pos);
        }
        //copy新的run
        for(XWPFRun sRun : sourceParag.getRuns()) {
            XWPFRun tarRun = targetParag.createRun();
            copyRun(tarRun, sRun);
        }
    }
    /**
     * 复制XWPFRun 从sourceRun到targetRun
     * @param targetRun
     * @param sourceRun
     * @Author Huangxiaocong 2018年12月1日 下午12:56:53
     */
    public void copyRun(XWPFRun targetRun, XWPFRun sourceRun) {
        //设置targetRun属性
        targetRun.getCTR().setRPr(sourceRun.getCTR().getRPr());
        targetRun.setText(sourceRun.text());//设置文本
        //处理图片
        List<XWPFPicture> pictures = sourceRun.getEmbeddedPictures();
        for(XWPFPicture picture : pictures) {
            try {
                copyPicture(targetRun, picture);
            } catch (InvalidFormatException e) {
                e.printStackTrace();
                logger.log(Level.WARNING, "copyRun", e);
            } catch (IOException e) {
                e.printStackTrace();
                logger.log(Level.WARNING, "copyRun", e);
            }
        }
    }
    /**
     * 复制图片从sourcePicture到 targetRun(XWPFPicture --> XWPFRun)
     * @param targetRun
     * @param source
     * @throws IOException
     * @throws InvalidFormatException
     * @Author Huangxiaocong 2018年12月1日 下午12:57:33
     */
    public void copyPicture(XWPFRun targetRun, XWPFPicture sourcePicture) throws InvalidFormatException, IOException {
        XWPFPictureData picData = sourcePicture.getPictureData();
        String fileName = picData.getFileName();    //图片的名称
        InputStream picInIsData = new ByteArrayInputStream(picData.getData());
        int picType = picData.getPictureType();
        int width = (int) sourcePicture.getCTPicture().getSpPr().getXfrm().getExt().getCx();
        int height =  (int) sourcePicture.getCTPicture().getSpPr().getXfrm().getExt().getCy();
        targetRun.addPicture(picInIsData, picType, fileName, width, height);
//        targetRun.addBreak();//分行
    }
}

四、Word中表格操作工具类

/**
 * @author SongBin on 2020/9/3.
 */
package cnki.jxjob.base;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.poi.xwpf.usermodel.BodyElementType;
import org.apache.poi.xwpf.usermodel.IBodyElement;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHMerge;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHeight;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTJc;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblGrid;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblGridCol;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblWidth;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTrPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTVMerge;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STJc;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTblWidth;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STVerticalJc;

/**
 * @Description 操作word的基本工具类
 * 2020年09月03日  下午4:20:05
 * @Author SongBin
 */
public class XWPFHelperTable {

    /**
     * 删除指定位置的表格,被删除表格后的索引位置
     * @param document
     * @param pos
     * @Author Huangxiaocong 2018年12月1日 下午10:32:43
     */
    public void deleteTableByIndex(XWPFDocument document, int pos) {
        Iterator<IBodyElement> bodyElement = document.getBodyElementsIterator();
        int eIndex = 0, tableIndex = -1;
        while(bodyElement.hasNext()) {
            IBodyElement element = bodyElement.next();
            BodyElementType elementType = element.getElementType();
            if(elementType == BodyElementType.TABLE) {
                tableIndex++;
                if(tableIndex == pos) {
                    break;
                }
            }
            eIndex++;
        }
        document.removeBodyElement(eIndex);
    }
    /**
     * 获得指定位置的表格
     * @param document
     * @param index
     * @return
     * @Author Huangxiaocong 2018年12月1日 下午10:34:14
     */
    public XWPFTable getTableByIndex(XWPFDocument document, int index) {
        List<XWPFTable> tableList = document.getTables();
        if(tableList == null || index < 0 || index > tableList.size()) {
            return null;
        }
        return tableList.get(index);
    }
    /**
     * 得到表格的内容(第一次跨行单元格视为一个,第二次跳过跨行合并的单元格)
     * @param table
     * @return
     * @Author Huangxiaocong 2018年12月1日 下午10:46:41
     */
    public List<List<String>> getTableRConten(XWPFTable table) {
        List<List<String>> tableContextList = new ArrayList<List<String>>();
        for(int rowIndex = 0, rowLen = table.getNumberOfRows(); rowIndex < rowLen; rowIndex++) {
            XWPFTableRow row = table.getRow(rowIndex);
            List<String> cellContentList = new ArrayList<String>();
            for(int colIndex = 0, colLen = row.getTableCells().size(); colIndex < colLen; colIndex++ ) {
                XWPFTableCell cell = row.getCell(colIndex);
                CTTc ctTc = cell.getCTTc();
                if(ctTc.isSetTcPr()) {
                    CTTcPr tcPr = ctTc.getTcPr();
                    if(tcPr.isSetHMerge()) {
                        CTHMerge hMerge = tcPr.getHMerge();
                        if(STMerge.RESTART.equals(hMerge.getVal())) {
                            cellContentList.add(getTableCellContent(cell));
                        }
                    } else if(tcPr.isSetVMerge()) {
                        CTVMerge vMerge = tcPr.getVMerge();
                        if(STMerge.RESTART.equals(vMerge.getVal())) {
                            cellContentList.add(getTableCellContent(cell));
                        }
                    } else {
                        cellContentList.add(getTableCellContent(cell));
                    }
                }
            }
            tableContextList.add(cellContentList);
        }
        return tableContextList;
    }

    /**
     * 获得一个表格的单元格的内容
     * @param cell
     * @return
     * @Author Huangxiaocong 2018年12月2日 下午7:39:23
     */
    public String getTableCellContent(XWPFTableCell cell) {
        StringBuffer sb = new StringBuffer();
        List<XWPFParagraph> cellParagList = cell.getParagraphs();
        if(cellParagList != null && cellParagList.size() > 0) {
            for(XWPFParagraph xwpfPr: cellParagList) {
                List<XWPFRun> runs = xwpfPr.getRuns();
                if(runs != null && runs.size() > 0) {
                    for(XWPFRun xwpfRun : runs) {
                        sb.append(xwpfRun.getText(0));
                    }
                }
            }
        }
        return sb.toString();
    }
    /**
     * 得到表格内容,合并后的单元格视为一个单元格
     * @param table
     * @return
     * @Author Huangxiaocong 2018年12月2日 下午7:47:19
     */
    public List<List<String>> getTableContent(XWPFTable table) {
        List<List<String>> tableContentList = new ArrayList<List<String>>();
        for (int rowIndex = 0, rowLen = table.getNumberOfRows(); rowIndex < rowLen; rowIndex++) {
            XWPFTableRow row = table.getRow(rowIndex);
            List<String> cellContentList = new ArrayList<String>();
            for (int colIndex = 0, colLen = row.getTableCells().size(); colIndex < colLen; colIndex++) {
                XWPFTableCell cell = row.getCell(colIndex);
                cellContentList.add(getTableCellContent(cell));
            }
            tableContentList.add(cellContentList);
        }
        return tableContentList;
    }

    /**
     * 跨列合并
     * @param table
     * @param row    所合并的行
     * @param fromCell    起始列
     * @param toCell    终止列
     * @Description
     * @Author Huangxiaocong 2018年11月26日 下午9:23:22
     */
    public void mergeCellsHorizontal(XWPFTable table, int row, int fromCell, int toCell) {
        for(int cellIndex = fromCell; cellIndex <= toCell; cellIndex++ ) {
            XWPFTableCell cell = table.getRow(row).getCell(cellIndex);
            if(cellIndex == fromCell) {
                cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);
            } else {
                cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
            }
        }
    }
    /**
     * 跨行合并
     * @param table
     * @param col    合并的列
     * @param fromRow    起始行
     * @param toRow    终止行
     * @Description
     * @Author Huangxiaocong 2018年11月26日 下午9:09:19
     */
    public void mergeCellsVertically(XWPFTable table, int col, int fromRow, int toRow) {
        System.out.println(col+"####"+fromRow+"############"+toRow);
        for(int rowIndex = fromRow; rowIndex <= toRow; rowIndex++) {
            if (table!=null){
                System.out.println(rowIndex+"####"+col);
                XWPFTableCell cell = table.getRow(rowIndex).getCell(col);
                //第一个合并单元格用重启合并值设置
                if(rowIndex == fromRow) {
                    cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART);
                } else {
                    //合并第一个单元格的单元被设置为“继续”
                    cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE);
                }
            }else {
                System.out.println("失败!");
            }
        }
    }

    /**
     * @Description: 创建表格,创建后表格至少有1行1列,设置列宽
     */
    public XWPFTable createTable(XWPFDocument xdoc, int rowSize, int cellSize,
                                 boolean isSetColWidth, int[] colWidths) {
        XWPFTable table = xdoc.createTable(rowSize, cellSize);
        if (isSetColWidth) {
            CTTbl ttbl = table.getCTTbl();
            CTTblGrid tblGrid = ttbl.addNewTblGrid();
            for (int j = 0, len = Math.min(cellSize, colWidths.length); j < len; j++) {
                CTTblGridCol gridCol = tblGrid.addNewGridCol();
                gridCol.setW(new BigInteger(String.valueOf(colWidths[j])));
            }
        }
        return table;
    }

    /**
     * @Description: 设置表格总宽度与水平对齐方式
     */
    public void setTableWidthAndHAlign(XWPFTable table, String width,
                                       STJc.Enum enumValue) {
        CTTblPr tblPr = getTableCTTblPr(table);
        // 表格宽度
        CTTblWidth tblWidth = tblPr.isSetTblW() ? tblPr.getTblW() : tblPr.addNewTblW();
        if (enumValue != null) {
            CTJc cTJc = tblPr.addNewJc();
            cTJc.setVal(enumValue);
        }
        // 设置宽度
        tblWidth.setW(new BigInteger(width));
        tblWidth.setType(STTblWidth.DXA);
    }

    /**
     * @Description: 得到Table的CTTblPr,不存在则新建
     */
    public CTTblPr getTableCTTblPr(XWPFTable table) {
        CTTbl ttbl = table.getCTTbl();
        // 表格属性
        CTTblPr tblPr = ttbl.getTblPr() == null ? ttbl.addNewTblPr() : ttbl.getTblPr();
        return tblPr;
    }

    /**
     * 设置表格行高
     * @param infoTable
     * @param heigth 高度
     * @param vertical 表格内容的显示方式:居中、靠右...
     * @Author Huangxiaocong 2018年12月16日
     */
    public void setTableHeight(XWPFTable infoTable, int heigth, STVerticalJc.Enum vertical) {
        List<XWPFTableRow> rows = infoTable.getRows();
        for(XWPFTableRow row : rows) {
            CTTrPr trPr = row.getCtRow().addNewTrPr();
            CTHeight ht = trPr.addNewTrHeight();
            ht.setVal(BigInteger.valueOf(heigth));
            List<XWPFTableCell> cells = row.getTableCells();
            for(XWPFTableCell tableCell : cells ) {
                CTTcPr cttcpr = tableCell.getCTTc().addNewTcPr();
                cttcpr.addNewVAlign().setVal(vertical);
            }
        }
    }
}

五、报告导出工具类

/**
 * @author SongBin on 2020/9/3.
 */
package cnki.jxjob.base;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

import cnki.jxjob.config.ChromeDriverConf;
import cnki.jxjob.entity.PriceData;
import cnki.jxjob.entity.PriceTabData;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STJc;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STVerticalJc;
import org.springframework.util.ResourceUtils;


/**
 * @Description 导出word文档
 * @Author  Huangxiaocong
 * 2018年12月1日  下午12:12:15
 */
public class ExportWordUtil {
    private XWPFHelperTable xwpfHelperTable = null;
    private XWPFHelper xwpfHelper = null;
    public ExportWordUtil() {
        xwpfHelperTable = new XWPFHelperTable();
        xwpfHelper = new XWPFHelper();
    }
    /**
     * 创建好文档的基本 标题,表格  段落等部分
     * @param inputUrl 报告模板地址
     * @return
     * @Author Huangxiaocong 2018年12月16日
     */
    public XWPFDocument createXWPFDocument(String inputUrl) {
        XWPFDocument doc = xwpfHelper.createDocumentLikeModel(inputUrl);
        return doc;
    }
    /**
     * 创建表格的标题样式
     * @param document
     * @Author Huangxiaocong 2018年12月16日 下午5:28:38
     */
    public void createTitleParagraph(XWPFDocument document) {
        XWPFParagraph titleParagraph = document.createParagraph();    //新建一个标题段落对象(就是一段文字)
        titleParagraph.setAlignment(ParagraphAlignment.CENTER);//样式居中
        XWPFRun titleFun = titleParagraph.createRun();    //创建文本对象
//        titleFun.setText(titleName); //设置标题的名字
        titleFun.setBold(true); //加粗
        titleFun.setColor("000000");//设置颜色
        titleFun.setFontSize(25);    //字体大小
//        titleFun.setFontFamily("");//设置字体
        //...
        titleFun.addBreak();    //换行
    }

    /**
     * 创建章节标题
     * @param document
     * @Author Huangxiaocong 2018年12月16日 下午5:28:38
     */
    public void createSectionTitle(XWPFDocument document,String titleName) {
        XWPFParagraph titleParagraph = document.createParagraph();    //新建一个标题段落对象(就是一段文字)
        titleParagraph.setAlignment(ParagraphAlignment.LEFT);//样式居中
        XWPFRun titleFun = titleParagraph.createRun();    //创建文本对象
        titleFun.setText(titleName); //设置标题的名字
        titleFun.setBold(true); //加粗
        titleFun.setColor("000000");//设置颜色
        titleFun.setFontSize(12);    //字体大小
        titleFun.setFontFamily("宋体");//设置字体
        titleFun.addBreak();    //换行
    }

    /**
     * 创建章节简介
     * @param document
     * @Author Huangxiaocong 2018年12月16日 下午5:28:38
     */
    public void createContent(XWPFDocument document,String content) {
        XWPFParagraph paragraph = document.createParagraph();    //新建一个标题段落对象(就是一段文字)
        XWPFRun sectionContentFun = paragraph.createRun();    //创建文本对象
        sectionContentFun.setText(content); //设置标题的名字
        sectionContentFun.setColor("000000");//设置颜色
        sectionContentFun.setFontSize(10);    //字体大小
        sectionContentFun.setFontFamily("宋体");//设置字体
    }

    /**
     * 创建章节简介
     * @param document
     * @Author Huangxiaocong 2018年12月16日 下午5:28:38
     */
    public void createSection(XWPFDocument document,String sectionAbstract,String sectionContent) {
        XWPFParagraph paragraph = document.createParagraph();    //新建一个标题段落对象(就是一段文字)
        paragraph.setIndentationFirstLine(400);//首行缩进
        paragraph.setAlignment(ParagraphAlignment.LEFT);//样式居中
        XWPFRun sectionAbstractFun = paragraph.createRun();    //创建文本对象
        sectionAbstractFun.setText(sectionAbstract); //设置标题的名字
        sectionAbstractFun.setBold(true); //加粗
        sectionAbstractFun.setColor("000000");//设置颜色
        sectionAbstractFun.setFontSize(10);    //字体大小
        sectionAbstractFun.setFontFamily("宋体");//设置字体
        XWPFRun sectionContentFun = paragraph.createRun();    //创建文本对象
        sectionContentFun.setText(sectionContent); //设置标题的名字
        sectionContentFun.setColor("000000");//设置颜色
        sectionContentFun.setFontSize(10);    //字体大小
        sectionContentFun.setFontFamily("宋体");//设置字体
    }

    /**
     * 设置表格
     * @param document
     * @param rows
     * @param cols
     * @Author Huangxiaocong 2018年12月16日
     */
    public XWPFTable createTableParagraph(XWPFDocument document, int rows, int cols,List<Map<String,Integer>> verticallyMapList) {
        XWPFTable infoTable = document.createTable(rows, cols);
        xwpfHelperTable.setTableWidthAndHAlign(infoTable, "9072", STJc.CENTER);
        //合并表格
        if(verticallyMapList!=null&&verticallyMapList.size()>0){
            for(Map<String,Integer> map: verticallyMapList){
                System.out.println("表格容量####"+rows+"############"+cols);
                xwpfHelperTable.mergeCellsVertically(infoTable, map.get("col"), map.get("fromRow"), map.get("toRow"));
            }
        }
        //设置表格样式
        List<XWPFTableRow> rowList = infoTable.getRows();
        for(int i = 0; i < rowList.size(); i++) {
            XWPFTableRow infoTableRow = rowList.get(i);
            List<XWPFTableCell> cellList = infoTableRow.getTableCells();
            for(int j = 0; j < cellList.size(); j++) {
                XWPFParagraph cellParagraph = cellList.get(j).getParagraphArray(0);
                cellParagraph.setAlignment(ParagraphAlignment.CENTER);
                XWPFRun cellParagraphRun = cellParagraph.createRun();
                cellParagraphRun.setFontSize(10);
//                if(i % 2 != 0) {
                if(i == 0) {
                    cellParagraphRun.setBold(true);
                }
            }
        }
        xwpfHelperTable.setTableHeight(infoTable, 560, STVerticalJc.CENTER);
        return infoTable;
    }

    /**
     * 往表格中填充数据
     * @param dataList
     * @param document
     * @throws IOException
     * @Author Huangxiaocong 2018年12月16日
     */
    @SuppressWarnings("unchecked")
    public void exportCheckWord(List<List<Object>> dataList, XWPFDocument document, int pos) throws IOException {
        List<List<Object>> tableData = dataList;
        XWPFTable table = document.getTableArray(pos);
        fillTableData(table, tableData);
//        xwpfHelper.saveDocument(document, savePath);
    }
    /**
     * 往表格中填充数据
     * @param table
     * @param tableData
     * @Author Huangxiaocong 2018年12月16日
     */
    public void fillTableData(XWPFTable table, List<List<Object>> tableData) {
        List<XWPFTableRow> rowList = table.getRows();
        for(int i = 0; i < tableData.size(); i++) {
            List<Object> list = tableData.get(i);
            List<XWPFTableCell> cellList = rowList.get(i).getTableCells();
            for(int j = 0; j < list.size(); j++) {
                XWPFParagraph cellParagraph = cellList.get(j).getParagraphArray(0);
                XWPFRun cellParagraphRun = cellParagraph.getRuns().get(0);
                cellParagraphRun.setText(String.valueOf(list.get(j)));
            }
        }
    }

    /**
     * 插入图片
     * @param document
     * @param imgGuid
     */
    public static void inseartParagraphImg(XWPFDocument document, String imgGuid){
        try {
            XWPFParagraph paragraph = document.createParagraph();
            XWPFRun run = paragraph.createRun();
            String basePath =StringUtil.isBlank(ChromeDriverConf.picSavePath)?"D:/imgupload/":ChromeDriverConf.picSavePath;
            String imgFile = basePath + imgGuid +".jpg";
            System.out.println("插入图表图片:" + imgFile);
            FileInputStream is = new FileInputStream(imgFile);
            run.addPicture(is, XWPFDocument.PICTURE_TYPE_JPEG, imgFile, Units.toEMU(400), Units.toEMU(300)); // 100x100 pixels
            is.close();
            run.setText("",0);
        } catch (Exception e) {
            System.out.println("Error: ========  插入单个图片时出错了:可能是图片路径不存在。不影响主流程");
            e.printStackTrace();
        }
    }

    /**
     * 保存word文档
     * @param document 文档对象
     * @param savePath    保存路径
     * @throws IOException
     * @Author Huangxiaocong 2018年12月1日 下午12:32:37
     */
    public void saveDocument(XWPFDocument document, String savePath) throws IOException {
        xwpfHelper.saveDocument(document,savePath);
    }

    public static void main(String[] args) throws Exception {
        ExportWordUtil ew = new ExportWordUtil();
        //模板文件地址
        String initWordFile = null;
//        try {
//            //根据操作系统的不同,获取不同的上传路径
//            String os = System.getProperty("os.name");
//            if(os.toLowerCase().startsWith("win")){
//                initWordFile = ResourceUtils.getURL("classpath:static/wordmodel/江西农产品批发市场价格行情模板.docx").getPath().substring(1);
//            }else {
//                initWordFile = ResourceUtils.getURL("classpath:static/wordmodel/江西农产品批发市场价格行情模板.docx").getPath();
//            }
//        } catch (FileNotFoundException e) {
//            e.printStackTrace();
//        }
        initWordFile = "e:/x.docx";
        initWordFile = initWordFile.replaceAll("/", "\\\\\\\\");
        initWordFile = java.net.URLDecoder.decode(initWordFile,"utf-8");
        String today = Constant.NOWDATE;
        XWPFDocument document = ew.createXWPFDocument(initWordFile);
        Map<String, String> changeTextBoxMap = new HashMap<String, String>();
        changeTextBoxMap.put("datetime", DateUtil.formatZhDate(today));
        int periods = DailyPriceUtil.searchPeriods()+1;
        changeTextBoxMap.put("periods", String.valueOf(periods));
        WorderToNewWordUtils.changeText(document,changeTextBoxMap);
        WorderToNewWordUtils.changeTextBox(document,changeTextBoxMap);
        ew.saveDocument(document,"e:\\y.docx");


        today = "2020-08-27";
        List<PriceData> pds = DailyPriceUtil.getDistinctKindNamesByDay(today);
        String sectionTitle = "";//章节标题
        String[] sectionNum = {"一","二","三","四","五","六","七","八","九","十","十一","十二","十三","十四","十五","十六","十七","十八","十九","二十"};
        int currentSection = 0; //当前章节
        for(PriceData pd : pds){
            String kindName = pd.getKindname();
            sectionTitle = sectionNum[currentSection]+"、"+kindName+"价格行情";
            /******************************开始加载表格数据***************************************/
            List<PriceTabData> ptd = DailyPriceUtil.getDailyPriceTabData(today,kindName);
            Map<String,Object> dataAnalyResult =  DailyPriceUtil.dataAnalysis(ptd);
            //创建表格行数
            int rows = Integer.valueOf(dataAnalyResult.get("rows").toString());
            //创建表格列数
            int cols = Integer.valueOf(dataAnalyResult.get("cols").toString());
            //需要合并单元格的坐标
            List<Map<String,Integer>> verticallyMapList = (List<Map<String,Integer>>)dataAnalyResult.get("verticallyMapList");
            //插入表格的格式数据
            List<List<Object>> tabDataList = (List<List<Object>>)dataAnalyResult.get("tabDataList");
            //章节简介
            String sectionAbstract = dataAnalyResult.get("sectionAbstract").toString();
            //章节正文
            String sectionContent = dataAnalyResult.get("sectionContent").toString();

            //###########################开始写入############################
            System.out.println(sectionTitle+"################");
            ew.createSectionTitle(document,sectionTitle);//章节标题
            ew.createSection(document,sectionAbstract,sectionContent);//章节
            XWPFTable infoTable = ew.createTableParagraph(document, rows, cols,verticallyMapList);//创建表格并合并单元格
//            int pos = currentSection;
//            ew.exportCheckWord(tabDataList, document ,pos);
            ew.fillTableData(infoTable,tabDataList);
            /******************************表格数据加载完毕***************************************/

            /******************************插入图表***************************************/
            List<PriceData> prds = DailyPriceUtil.getProductNamesByKindNameToday(today,kindName);
            if(prds==null || prds.size()<=0){
                prds = DailyPriceUtil.getProductNamesByKindNameToday(DateUtil.getBeforeDay(today),kindName);
            }
            if(prds==null || prds.size()<=0){
                prds = DailyPriceUtil.getProductNamesByKindName(today,kindName);
            }
            List<String> productNames = prds.stream().map(prd -> "'"+pd.getProductname()+"'").collect(Collectors.toList());
            Map<String ,String> imgMap = new HashMap<>();
            List<String> parms = new ArrayList<>();
            for(int i=1;i<6;i++){
                String uid = UUID.randomUUID().toString();
                imgMap.put("$img0"+i,uid);
                parms.add("uid0"+i+"="+uid);
            }
            /******************************插入图表结束***************************************/
            currentSection ++;
        }
        String savePath = "E:/expWordTest.docx";
        ew.xwpfHelper.saveDocument(document, savePath);

//        List<List<Object>> list = new ArrayList<List<Object>>();
//
//        List<Object> tempList = new ArrayList<Object>();
//        tempList.add("姓名");
//        tempList.add("黄xx");
//        tempList.add("性别");
//        tempList.add("男");
//        tempList.add("出生日期");
//        tempList.add("2018-10-10");
//        list.add(tempList);
//        tempList = new ArrayList<Object>();
//        tempList.add("身份证号");
//        tempList.add("36073xxxxxxxxxxx");
//        list.add(tempList);
//        tempList = new ArrayList<Object>();
//        tempList.add("出生地");
//        tempList.add("江西");
//        tempList.add("名族");
//        tempList.add("汉");
//        tempList.add("婚否");
//        tempList.add("否");
//        list.add(tempList);
//        tempList = new ArrayList<Object>();
//        tempList.add("既往病史");
//        tempList.add("无");
//        list.add(tempList);
//
//        Map<String, Object> dataList = new HashMap<String, Object>();
//        dataList.put("TITLE", "个人体检表");
//        dataList.put("TABLEDATA", list);
//        ew.exportCheckWord(dataList, document, "E:/expWordTest.docx");
        System.out.println("文档生成成功");
    }
}
更多内容请访问:IT源点

相关文章推荐

全部评论: 0

    我有话说: