java 生成 word 文档的多种方法(三)

本文详细介绍了如何使用Java的POI库来生成Word文档,包括段落、Runs和表格的操作,并提供了相关代码示例,帮助理解实现原理。文章还提及了模板制作注意事项及解决分段混乱问题的方法,最后预告了关于Word文档图片生成的内容。
该文章已生成可运行项目,

这篇文章给大家介绍java  通过POI技术生成word ,这种实现方式项目中也很常用,比如生成常用表格,报表等。废话少说,下面就给大家详细介绍实现原理!

A、word文档正文段落概述:

一个word文档包含多个段落,一个段落包含多个Runs,一个Runs包含多个Run,Run是文档的最小单位

获取所有段落:List<XWPFParagraph> paragraphs = word.getParagraphs();

获取一个段落中的所有Runs:List<XWPFRun> xwpfRuns = xwpfParagraph.getRuns();

获取一个Runs中的一个Run:XWPFRun run = xwpfRuns.get(index);

B、word文档正文表格概述:

一个文档可包含多个表格,每个表格可以包含多行,每行可以包含多列(格),每一格的内容相当于一个完整的文档

获取所有表格:List<XWPFTable> xwpfTables = doc.getTables();

获取一个表格中的所有行:List<XWPFTableRow> xwpfTableRows = xwpfTable.getRows();

获取一行中的所有列:List<XWPFTableCell> xwpfTableCells = xwpfTableRow.getTableCells();

获取一格里的内容:List<XWPFParagraph> paragraphs = xwpfTableCell.getParagraphs();

A,B介绍有利于大家理解POI实现原理,所需jar包如图:这几个jar包足够

一、首先、该word模板是直接用word文档做模板,如下图:模板里面的参数大家可以随意定义,可以用${name},也可不用,直接  name

二、咱们就利用这个模板做测试,生成文档和文档里面的表格,测试成功直接可以使用,直接上代码:如下

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.poi.POIXMLDocument;
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;
 
/**
 * 通过word模板生成新的word工具类
 * 
 */
public class BokeWordUtils {
    /**
     * 根据模板生成新word文档
     * 判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入
     * @param inputUrl 模板存放地址
     * @param outPutUrl 新文档存放地址
     * @param textMap 需要替换的信息集合
     * @param tableList 需要插入的表格信息集合
     */
    public static boolean changWord(String inputUrl, String outputUrl,
            Map<String, String> textMap, List<String[]> tableList) {
        //模板转换默认成功
        boolean changeFlag = true;
        try {
             //获取docx解析对象
           // Resource resource = new ClassPathResource(inputUrl);//放到代码的根目录下面, "templates/report.docx";模板
           // InputStream inputStream = resource.getInputStream();
         //   XWPFDocument document = new XWPFDocument(inputStream);

            //获取docx解析对象
            XWPFDocument document = new XWPFDocument(POIXMLDocument.openPackage(inputUrl));//放到服务器的目录下
            //解析替换文本段落对象
            BokeWordUtils.changeText(document, textMap);
            //解析替换表格对象
            BokeWordUtils.changeTable(document, textMap, tableList);
            //生成新的word
            Files.createDirectories(Paths.get(outputUrl).getParent());//如果没有,需要先创建,有了就不需要再创建了
            File file = new File(outputUrl);
            FileOutputStream stream = new FileOutputStream(file);
            document.write(stream);
            stream.close();
            System.out.println("成功生成!");
        } 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();
            if(checkText(text)){
                List<XWPFRun> runs = paragraph.getRuns();
                for (XWPFRun run : runs) {
                    //替换模板原来位置
                   // run.setText(changeValue(run.toString(), textMap),0);
                	String textValue = changeValue(run.toString(), textMap);
                    run.setText(textValue,0);
                }
            }
        }
    }
    
    /**
     * 替换表格对象方法
     * @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()+"}";
            if(value.indexOf(key)!= -1){
               // value = textSet.getValue();//全部参数替换
                value = value.replace(key, textSet.getValue());//仅替换参数
            }
        }
        //模板未匹配到区域替换为空
        if(checkText(value)){
            value = "";
        }
        return value;
    }
    
    public static void main(String[] args) {
        //模板文件地址
        String inputUrl = "F://testWord/test0.docx";
        //新生产的模板文件
        String outputUrl = "F://testWord/testBoke.docx";
 
        Map<String, String> testMap = new HashMap<String, String>();
        testMap.put("name", "小明");
        testMap.put("sex", "男");
        testMap.put("nling", "18");
        testMap.put("address", "北京市");
        testMap.put("neirong", "好的内容");
        testMap.put("address", "软件园");
        testMap.put("xuehao", "88888888");
 
        List<String[]> testList = new ArrayList<String[]>();
        testList.add(new String[]{"1","1mm","1开开","1uu"});
        testList.add(new String[]{"2","2密码","2B","基金C"});
        testList.add(new String[]{"3","3看看","3B","基看C"});
        testList.add(new String[]{"4","4累了","4B","4谁说的"});
 
        BokeWordUtils.changWord(inputUrl, outputUrl, testMap, testList);
    }
}

1)组合每一行的数组

  private  List<String[]> convertToTestList( List<UserDTO> userList) {
        List<String[]> testList = new ArrayList<>();
        int i =1;
        for (UserDTO user : userList) {
            BigDecimal wat = user.getWat();
           if(wat == null){
               wat = new BigDecimal("0");
           }
            //String s = DateUtil.formatTime(user.getTm());
            i++;
            testList.add(new String[]{ //为每个对象生成一行数据
                    i+"",
                    user.getArea(),
                    user.getLocation(),
                    user.getTime(),
                    wat.toString(),
                    user.getCircuit(),
                    user.getAge(),
                    user.getName()
            });
        }

        return testList;
}

2) pom.xml引用的jar


        <dependency>
            <groupId>org.apache.xmlbeans</groupId>
            <artifactId>xmlbeans</artifactId>
            <version>3.0.2</version>
        </dependency>

        <!-- OOXML Schema -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml-schemas</artifactId>
            <version>4.1.2</version>
        </dependency>

        <!-- 压缩库支持 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-compress</artifactId>
            <version>1.20</version>
        </dependency>

        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>4.1.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>4.1.2</version>
            <exclusions>
                <!-- 排除旧版xmlbeans -->
                <exclusion>
                    <groupId>org.apache.xmlbeans</groupId>
                    <artifactId>*</artifactId>
                </exclusion>
            </exclusions>
        </dependency>


        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.12.0</version>
        </dependency>

poi-ooxml-schemas 没有开发更高版本,因此暂时都有4.*版本。

三、次代码是我在网上查询出来的,经过修改优化,成功使用。改模板代码参数设置为${name},类似EL表达式。同时这种方式能很好地避免XWPFParagraph.getRuns分段混乱问题(分段混乱原因:是${name}是手打上去的,如果先在记事本输入,再复制粘贴进docx则不会出现分段问题)。代码非常详细,大家有不明白大地方及时留言!!!

四、下篇文章给大家介绍word文档上有图片生成的问题,敬请期待!!!

本文章已经生成可运行项目
评论 26
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

寅灯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值