Android word文档 poi 表格 段落使用记录

需求:Android端根据数据,生成word保存到本地.
查了一些资料好像android 没什么正式的word操作库,基本都是用Java API,Apache POI实现的,但是这个版本比较多android这边兼容不太好,坑比较多…
这边本来是需要word操作雷达图,折线图,柱状图这个些的,需要POI4.x版本,各种姿势依赖,好像都问题,编译或者运行各种不行(可能本人太菜…),没办法只能用3.x版本,图表再说吧…

1.gradle 依赖POI

app目录build.gradle,添加完整依赖:


dependencies {
    
    
	...
    implementation group: 'org.apache.poi', name: 'poi-ooxml', version: '3.17'
    implementation group: 'org.apache.xmlbeans', name: 'xmlbeans', version: '3.1.0'
    implementation 'javax.xml.stream:stax-api:1.0'
    implementation 'com.fasterxml:aalto-xml:1.2.2'
    ...
    }
2.新增段落
		/**
     * 添加段落内容
     *
     * @param document   word文档对象 XWPFDocument document = new XWPFDocument()
     * @param fontSize   字体大小
     * @param fontFamily 字体类型
     * @param text       标题
     */
    public static void addParagraph(XWPFDocument document, int fontSize, String fontFamily, String text) {
    
    
    	//创建空白word文档
		//XWPFDocument document = new XWPFDocument()
        XWPFParagraph paragraph = document.createParagraph();
        //内容左对齐
        paragraph.setAlignment(ParagraphAlignment.valueOf(STJc.INT_LEFT));
        XWPFRun run = paragraph.createRun();
        run.setFontSize(13);
        run.setFontFamily("黑体");
        run.addTab();
        run.setText(text);
        run.addBreak();
    }
3.新增表格
  • document.createTable(1, 2);
    创建1行 2列表格
    table.getRow(0).getCell(0).setText()
    table.getRow(0).getCell(1).setText()
  • document.createTable();
    默认创建1行1列
    table.getRow(0).getCell(0).setText()
    table.getRow(0).addNewTableCell().setText()

 /**
     * 添加表格
     * XWPFDocument document = new XWPFDocument()
     *
     * @param document word文档对象.
     */
    public static void addTable(XWPFDocument document) {
    
    
        //创建表格 1行  list.size 列
        //XWPFTable table = document.createTable(1, 2);
        XWPFTable table = document.createTable();

        CTTbl tTbl = table.getCTTbl();
        CTTblPr tTblPr = tTbl.getTblPr() == null ? tTbl.addNewTblPr() : tTbl.getTblPr();
        CTTblWidth tblWidth = tTblPr.isSetTblW() ? tTblPr.getTblW() : tTblPr.addNewTblW();

        //设置表格宽度
        tblWidth.setType(STTblWidth.DXA);
        tblWidth.setW(new BigInteger("8000"));

        table.getRow(0).setHeight(1000);
        //第一列
        setCellStr(table.getRow(0).getCell(0), "主题一", 3000);
        //setCellStr(table.getRow(0).getCell(1), "孤勇者-陈奕迅", 5000);
        //第二列
        setCellStr(table.getRow(0).addNewTableCell(), "孤勇者-陈奕迅", 5000);

        XWPFTableRow row_1 = table.createRow();
        row_1.setHeight(1000);
        setCellStr(row_1.getCell(0), "主题二", 3000);
        setCellStr(row_1.getCell(1), "再回首-岩贵|再回首恍然如梦", 5000);

        XWPFTableRow row_2 = table.createRow();
        row_2.setHeight(1000);
        setCellStr(row_2.getCell(0), "主题三", 3000);
        setCellStr(row_2.getCell(1), "光辉岁月-黄家驹", 5000);
    }

设置单元格属性
注意水平居中:这个有点坑,差了好多,都是ctTc.getPList().get(0).addNewPPr().addNewJc().setVal(STJc.CENTER);,因为版本问题需要改成ctTc.getPArray()[0].addNewPPr().addNewJc().setVal(STJc.CENTER);,编译不报错,一运行就找不到方法,关键代码你点进去还有这个方法…

private static void setCellStr(XWPFTableCell cell, String str, int w) {
    
    

        CTTc ctTc = cell.getCTTc();
        CTTcPr ctTcPr = ctTc.addNewTcPr();
        ctTcPr.addNewTcW().setW(BigInteger.valueOf(w));
        //上下居中
        cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
        //水平居中
        //ctTc.getPList().get(0).addNewPPr().addNewJc().setVal(STJc.CENTER);
        ctTc.getPArray()[0].addNewPPr().addNewJc().setVal(STJc.CENTER);
        cell.setText(str);
    }
4.根据模版生成新的word

模版我是放在assets目录,然后判断字段是是否包含$.然后替换成我们需要的内容.
在这里插入图片描述

4.1替换段落
/**
     * 替换段落文本
     *
     * @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();
            Log.i(TAG, "changeText:行 " + text);
            if (text.contains("$")) {
    
    
                List<XWPFRun> runs = paragraph.getRuns();
                for (XWPFRun run : runs) {
    
    
                    //替换模板原来位置
                    Log.i(TAG, "changeText:行内 " + run.getText(run.getTextPosition()));
                    run.setText(changeValue(run.toString(), textMap), 0);
                }
            }
        }

    }
4.2替换表格
  /**
     * 替换表格对象方法
     *
     * @param document docx解析对象
     * @param textMap  需要替换的信息集合
     */
    public static void changeTable(XWPFDocument document, Map<String, String> textMap) {
    
    
        //获取表格对象集合
        List<XWPFTable> tables = document.getTables();

        for (int i = 0; i < tables.size(); i++) {
    
    
            Log.i(TAG, "changeTable: 1" + tables.get(i).getText());
            //只处理行数大于等于2的表格,且不循环表头
            XWPFTable table = tables.get(i);
            if (table.getRows().size() > 1) {
    
    
                //判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入
                if (table.getText().contains("$")) {
    
    
                    List<XWPFTableRow> rows = table.getRows();
                    //遍历表格,并替换模板
                    eachTable(rows, textMap);
                }
            }
        }
    }
5.完整工具代码
public class PoiWordUtils {
    
    

    private static final String TAG = "";

    /**
     * 添加段落标题
     *
     * @param document   word文档对象 XWPFDocument document = new XWPFDocument()
     * @param fontSize   字体大小
     * @param fontFamily 字体类型
     * @param isBreak    是否换行
     * @param title      标题
     */
    public static void addParagraphTitle(XWPFDocument document, int fontSize, String fontFamily, boolean isBreak, int gravity, String title) {
    
    
        XWPFParagraph paragraph = document.createParagraph();
        //设置段落居中 / STJc.INT_LEFT - STJc.INT_RIGHT
        paragraph.setAlignment(ParagraphAlignment.valueOf(gravity));
        //行间距
        //paragraph.setSpacingBefore(1);
        XWPFRun run = paragraph.createRun();
        run.setFontSize(fontSize);
        run.setFontFamily("宋体");
        run.setBold(true);
        run.setText(title);
        //换行
        if (isBreak)
            run.addBreak();

        run.addTab();
    }

    /**
     * 添加段落内容
     *
     * @param document   word文档对象 XWPFDocument document = new XWPFDocument()
     * @param fontSize   字体大小
     * @param fontFamily 字体类型
     * @param text       标题
     */
    public static void addParagraph(XWPFDocument document, int fontSize, String fontFamily, String text) {
    
    

        XWPFParagraph paragraph = document.createParagraph();
        //内容左对齐
        paragraph.setAlignment(ParagraphAlignment.valueOf(STJc.INT_LEFT));
        XWPFRun run = paragraph.createRun();
        run.setFontSize(13);
        run.setFontFamily("黑体");
        run.addTab();
        run.setText(text);
        run.addBreak();
    }


    /**
     * 添加表格
     * XWPFDocument document = new XWPFDocument()
     *
     * @param document word文档对象.
     */
    public static void addTable(XWPFDocument document) {
    
    
        //创建表格 1行  list.size 列
        //XWPFTable table = document.createTable(1, 2);
        XWPFTable table = document.createTable();

        CTTbl tTbl = table.getCTTbl();
        CTTblPr tTblPr = tTbl.getTblPr() == null ? tTbl.addNewTblPr() : tTbl.getTblPr();
        CTTblWidth tblWidth = tTblPr.isSetTblW() ? tTblPr.getTblW() : tTblPr.addNewTblW();

        //设置表格宽度
        tblWidth.setType(STTblWidth.DXA);
        tblWidth.setW(new BigInteger("8000"));


        table.getRow(0).setHeight(1000);
        //第一列
        setCellStr(table.getRow(0).getCell(0), "主题一", 3000);
        //第二列
        //setCellStr(table.getRow(0).getCell(1), "孤勇者-陈奕迅", 5000);
        setCellStr(table.getRow(0).addNewTableCell(), "孤勇者-陈奕迅", 5000);

        XWPFTableRow row_1 = table.createRow();
        row_1.setHeight(1000);
        setCellStr(row_1.getCell(0), "主题二", 3000);
        setCellStr(row_1.getCell(1), "再回首-岩贵|再回首恍然如梦", 5000);

        XWPFTableRow row_2 = table.createRow();
        row_2.setHeight(1000);
        setCellStr(row_2.getCell(0), "主题三", 3000);
        setCellStr(row_2.getCell(1), "光辉岁月-黄家驹", 5000);
    }


    private static void setCellStr(XWPFTableCell cell, String str, int w) {
    
    

        CTTc ctTc = cell.getCTTc();
        CTTcPr ctTcPr = ctTc.addNewTcPr();
        ctTcPr.addNewTcW().setW(BigInteger.valueOf(w));
        //上下居中
        cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
        //水平居中
        //ctTc.getPList().get(0).addNewPPr().addNewJc().setVal(STJc.CENTER);
        ctTc.getPArray()[0].addNewPPr().addNewJc().setVal(STJc.CENTER);
        cell.setText(str);
    }


/**-----------------------------------------模版相关---------------------------------------------**/


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

        //模板转换默认成功
        boolean changeFlag = true;
        try {
    
    
            //获取docx解析对象
            XWPFDocument document = new XWPFDocument(POIXMLDocument.openPackage(inputUrl));
            //解析替换文本段落对象
            changeText(document, textMap);
            //解析替换表格对象
            changeTable(document, textMap);
            //生成新的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;

    }


    public static boolean changWord(InputStream is, String outputUrl,
                                    Map<String, String> textMap) {
    
    

        //模板转换默认成功
        boolean changeFlag = true;
        try {
    
    
            //获取docx解析对象
            XWPFDocument document = new XWPFDocument(is);
            //解析替换文本段落对象
            changeText(document, textMap);
            //解析替换表格对象
            changeTable(document, textMap);
            //生成新的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;

    }


    /**
     * 替换段落文本
     *
     * @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();
            Log.i(TAG, "changeText:行 " + text);
            if (text.contains("$")) {
    
    
                List<XWPFRun> runs = paragraph.getRuns();
                for (XWPFRun run : runs) {
    
    
                    //替换模板原来位置
                    Log.i(TAG, "changeText:行内 " + run.getText(run.getTextPosition()));
                    run.setText(changeValue(run.toString(), textMap), 0);
                }
            }
        }

    }

    /**
     * 替换表格对象方法
     *
     * @param document docx解析对象
     * @param textMap  需要替换的信息集合
     */
    public static void changeTable(XWPFDocument document, Map<String, String> textMap) {
    
    
        //获取表格对象集合
        List<XWPFTable> tables = document.getTables();

        for (int i = 0; i < tables.size(); i++) {
    
    
            Log.i(TAG, "changeTable: 1" + tables.get(i).getText());
            //只处理行数大于等于2的表格,且不循环表头
            XWPFTable table = tables.get(i);
            if (table.getRows().size() > 1) {
    
    
                //判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入
                if (table.getText().contains("$")) {
    
    
                    List<XWPFTableRow> rows = table.getRows();
                    //遍历表格,并替换模板
                    eachTable(rows, textMap);
                }
            }
        }
    }


    /**
     * 遍历表格
     *
     * @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) {
    
    
                Log.i(TAG, "eachTable: 2 " + cell.getText());
                //判断单元格是否需要替换
                if (cell.getText().contains("$")) {
    
    
                    List<XWPFParagraph> paragraphs = cell.getParagraphs();
                    for (XWPFParagraph paragraph : paragraphs) {
    
    
                        Log.i(TAG, "eachTable: 3" + paragraph.getText());
                        List<XWPFRun> runs = paragraph.getRuns();
                        for (XWPFRun run : runs) {
    
    
                            Log.i(TAG, "eachTable: 4 " + run.getText(run.getTextPosition()));
                            run.setText(changeValue(run.toString(), textMap), 0);
                        }
                    }
                }
            }
        }
    }

    /**
     * 匹配传入信息集合与模板
     *
     * @param value   模板需要替换的区域
     * @param textMap 传入信息集合
     * @return 模板需要替换区域信息集合对应值
     */
    public static String changeValue(String value, Map<String, String> textMap) {
    
    
        Set<Map.Entry<String, String>> textSets = textMap.entrySet();
        for (Map.Entry<String, String> textSet : textSets) {
    
    
            //匹配模板与替换值 格式${key}
            String key = "${" + textSet.getKey() + "}";
            if (value.contains(key)) {
    
    
                value = textSet.getValue();
            }
        }
        //模板未匹配到区域替换为空
        if (value.contains("$")) {
    
    
            value = "";
        }
        return value;
    }
}

6.测试

创建空白word,写入标题 段落,表格

String path = FileUtils.getAppRootPth(this) + File.separator + "word"
                + File.separator + "测试3.100.docx";

        try (XWPFDocument document = new XWPFDocument(); FileOutputStream fos = new FileOutputStream(path)) {
    
    
            //标题
            PoiWordUtils.addParagraphTitle(document, 20, null,true,STJc.INT_CENTER, "POI段落标题");
            //小标题
            PoiWordUtils.addParagraphTitle(document, 15, null,false,STJc.INT_LEFT, "一丶内容示例");
            //段落
            PoiWordUtils.addParagraph(document, -1, null, "POI是Apache软件" +
                    "基金会用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程序对Microsoft" +
                    " Office格式档案读和写的功能。POI为“Poor Obfuscation Implementation”的首字母缩写," +
                    "意为“简洁版的模糊实现”。\n" +
                    "所以POI的主要功能是可以用Java操作Microsoft Office的相关文件,但是一般我们都是用来操作" +
                    "Excel相关文件。");
            PoiWordUtils.addParagraph(document, -1, null, "POI是Apache软件" +
                    "基金会用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程序对Microsoft" +
                    " Office格式档案读和写的功能。POI为“Poor Obfuscation Implementation”的首字母缩写," +
                    "意为“简洁版的模糊实现”。\n" +
                    "所以POI的主要功能是可以用Java操作Microsoft Office的相关文件,但是一般我们都是用来操作" +
                    "Excel相关文件。");
            PoiWordUtils.addParagraphTitle(document, 15, null,false,STJc.INT_LEFT, "二丶内容示例");
            PoiWordUtils.addParagraph(document, -1, null, "POI是Apache软件" +
                    "基金会用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程序对Microsoft" +
                    " Office格式档案读和写的功能。POI为“Poor Obfuscation Implementation”的首字母缩写," +
                    "意为“简洁版的模糊实现”。\n" +
                    "所以POI的主要功能是可以用Java操作Microsoft Office的相关文件,但是一般我们都是用来操作" +
                    "Excel相关文件。");
            PoiWordUtils.addTable(document);
            //写入本地
            document.write(fos);

运行结果.
在这里插入图片描述
根据模版生成新的word

Map<String, String> testMap = new HashMap<>();
        testMap.put("Title", "POI模版替换");
        testMap.put("FirstHeading", "规则说明");
        testMap.put("FirstHeadingContent", "1.玩家同一场景,以个人为单位进行战斗.\n2.可以对其他玩家进行攻击\n3.一场游戏时间为10分钟");
        testMap.put("SecondHeading", "奖励说明");
        testMap.put("A", "主题A");
        testMap.put("a", "主题A详情");
        testMap.put("B", "主题B");
        testMap.put("b", "主题B详情");
        testMap.put("C", "主题C");
        testMap.put("c", "主题C详情");
        try {
    
    
            InputStream is = getAssets().open("谈话结果主题摘要模板.docx");
            //InputStream is = getAssets().open("阶段性风险评估报告模版.docx");
            String path = FileUtils.getAppRootPth(this) + File.separator + "word" + File.separator + "测试24.docx";
            //boolean b = WordUtils.changWord(is, path, testMap, testList);
            boolean b = WordUtils.changWord(is, path, testMap);
            Log.i(TAG, "testWord: " + b);
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }

模版:
在这里插入图片描述
替换之后:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_35193677/article/details/129489801