百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT知识 > 正文

Java操作Office:POI之word生成

liuian 2025-02-15 00:06 16 浏览

程序员架构进阶

一 背景

最近在项目开发中,有数据导出到word的需求。这就涉及代码生成word文档的操作,且有格式要求。大家用word做过简历的都有了解,做简历时,会使用表格、图片、文字等元素。而且表格也可能有嵌套、合并单元格,以及插入图片到单元格的操作。该怎么做?

二 Java操作Office方案

百度一下Java Office操作,或者再直接一点搜索Java word,就比较容易搜到iText、POI等组件。在文章 Java导出word的几种方式 这篇文章中,提到了包括Jacob、Apache POI、Java2word、iText、FreeMarker五种方式。

通过对比,结合需求要求,最终选择了Apache POI来实现,所以这里先详细介绍POI,以及一个可用的demo,供参考。

三 ApachePOI

Apache POI(官网)是基于Office Open XML标准(OOXML)和Microsoft的OLE 2复合文档格式(OLE2)处理各种文件格式的开源项目。简而言之,您可以使用Java读写MS Excel文件,可以使用Java读写MS Word和MS PowerPoint文件。

poi的gitee地址:gitee。入门教程可以参考 Apache POI Word(docx) 入门示例教程。

四 版本信息

poi的最新版本已经到了5.0.0,不过可以找到的大部分demo都是基于3.x版本或4.1版本。为了尽快搭建demo并运行起来,我们也没有使用最新版本,而是选择了4.1.0进行开发。

4.1 引用依赖


    8
    8
    4.1.0






    
        org.apache.poi
        poi
        ${poi.version}
    


    
    
        org.apache.poi
        poi-ooxml
        ${poi.version}
    
    
        org.apache.poi
        poi-excelant
        ${poi.version}
    


    
    
        com.deepoove
        poi-tl
        1.5.0
    


    
        org.projectlombok
        lombok
        1.18.20
    

4.2 创建word示例代码

4.2.1 创建新的文档

创建word文档比较简单,直接使用new XWPFDocument即可,XWPFDocument是对 .docx 文档操作的高级封装API:

XWPFDocument doc = new XWPFDocument();

4.2.2 表格

即Word文档中的表格。API创建时需要指定行数和列数,示例如下:

//创建一个表格,并指定宽度
XWPFTable table = doc.createTable(4, 4);
TableTools.widthTable(table, MiniTableRenderData.WIDTH_A4_FULL, 4);


//设置第0行数据
List row0 = table.getRow(0).getTableCells();
row0.get(0).setText("xxxx"); //为第0行第0列设置内容
row0.get(0).setWidth("200");
row0.get(1).setText("aaaa");
row0.get(2).setText("bbbb");
row0.get(3).setText("cccc");

常规的简单表格,我们只要按照上述代码逐行操作即可;但现实中不会这么容易。通常会涉及在单元格插入图片、合并行、合并列,甚至表格嵌套。目前表格嵌套暂未实现,先介绍其他三种情况。

4.2.3 列合并

有两种方法,一种是使用addNewHMerge方法,通过设置合并的起始列和结束列,逐个列进行合并:

List row2_1 = table.getRow(2).getTableCells();
row2_1.get(0).setText("合并表格"); //为第0行第0列设置内容
//将第一列到第四列合并
for (int i = 1; i <= 3; i++) {
    //对单元格进行合并的时候,要标志单元格是否为起点,或者是否为继续合并
    if (i == 1)
        row2_1.get(i).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);//这是起点
    else
        row2_1.get(i).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);//继续合并
}

在业务代码中这样的写法稍显繁琐,我们也可以直接使用
TableTools.mergeCellsHorizonal()函数来执行合并:

// 合并第一行的第0列到第8列单元格
TableTools.mergeCellsHorizonal(table, 1, 0, 8);

4.2.4 行合并

如果是要合并某几行,也可以使用TableTools提供的方法:

// 合并第0列的第一行到第九行的单元格
TableTools.mergeCellsVertically(table, 0, 1, 9);

我们看一下TableTools的源码:

public static void mergeCellsVertically(XWPFTable table, int col, int fromRow, int toRow) {
        if (toRow > fromRow) {
            for(int rowIndex = fromRow; rowIndex <= toRow; ++rowIndex) {
                XWPFTableCell cell = table.getRow(rowIndex).getCell(col);
                CTTcPr tcPr = getTcPr(cell);
                CTVMerge vMerge = tcPr.addNewVMerge();
                if (rowIndex == fromRow) {
                    vMerge.setVal(STMerge.RESTART);
                } else {
                    vMerge.setVal(STMerge.CONTINUE);
                }
            }


        }
    }

可以发现,底层还是使用addNewVMerge等方法,也设置了起始和结束位置,只是做了一层封装。

4.2.5 图片插入表格

图片插入表格要麻烦一些,如果大家在百度上搜索过插入图片到表格方法,大概率会找到这样的操作:

大部分对应的都是3.9以前的版本,写起来比较复杂,而且在4.x之后,图中super.getRelationId()方法也发生了变化,代码报错。

通过调研,发现XWPFRun中提供了addPicture方法,写起来也简单了很多。一个示例如下:

String imageFile = "/Users/xxx/Downloads/图片 1.png";
InputStream stream = new FileInputStream(imageFile);


//表格中创建段落
XWPFParagraph paragraph = row2_1.get(1).getParagraphs().get(0);
XWPFRun run = paragraph.createRun();
run.addPicture(stream, XWPFDocument.PICTURE_TYPE_PNG, "Generated",
    Units.toEMU(364), Units.toEMU(256));

run.addPicture接收的参数依次为:图片的InputStream流,图片类型,图片名称(非文件名),图片宽度、图片高度。通过这个方法,我们就可以把图片插入到指定的表格中,并设置图片的宽高属性。

五 总结

通过上述介绍,大家应该可以简单实现一个表格了。本文的方式还是偏向于硬编码的方式,在很多场景(例如简历、报表等典型场景)可以采用模板的方式,创建word模板,然后用模板内容替换来生成复杂样式的表格。这个在后续文章中再做介绍,大家也可以先搜索相关的实现来学习了解。

相关推荐

前端开发为什么需要Promise

一、引言在Web前端开发中,异步操作是绕不开的话题。随着用户对网页交互性和响应速度要求的不断提高,开发者们不得不处理越来越多的异步任务,如数据获取、文件读写等。本文旨在探讨Promise作为现代Jav...

『React』组件副作用,useEffect讲解

在React开发中,有时候会听到“副作用”这个词。特别是用到useEffect这个Hook的时候,官方就明确说它是用来处理副作用的。那什么是副作用?为什么我们要专门管控它?今天就聊聊Re...

图解 Promise 实现原理(一):基础实现

作者:孔垂亮转发链接:https://mp.weixin.qq.com/s/UNzYgpnKzmW6bAapYxnXRQ前言很多同学在学习Promise时,知其然却不知其所以然,对其中的用法理解不...

C#实现归并排序与快速排序

字数914,阅读大约需5分钟C#实现归并排序与快速排序以下是使用C#实现的归并排序和快速排序算法代码:usingSystem;usingSystem.Collections.Gener...

C#.NET Newtonsoft.Json 详解

简介Newtonsoft.Json(又称Json.NET)是.NET生态中最流行的JSON序列化/反序列化库,支持.NETFramework、.NETCore、Mono、Xamarin...

C# - 类文件构成,C#基本语法,Console属性与方法 007

类文件(.cs)构成类文件主要分为引用命名空间与自己项目的命名空间1)引用命名空间主要是引用类库,分为内部(.Net类库与解决方案内其他项目的命名空间)外部(引用别人的命名空间),之前说过类库的...

不要过度使用列表(List): C# 数据结构

编程中的每一个决定都会对性能和清晰度产生无声的影响。在C#中,这样重要的选择之一就是选择正确的数据结构。数据结构是基础支柱。这些结构是数据生存、呼吸和交互的地方,决定了代码的效率和可读性。但...

C# 编程语言 31-40个经典案例

案例31:LINQ查询学生成绩排序说明:演示如何使用LINQ查询并排序数据集合。usingSystem;usingSystem.Collections.Generic;usingSyst...

C#中常用的数据结构

写在前面最近在使用.net开发一些程序。它使用的编程语言是C#。我们来看一下它的常用的数据结构有哪些。常用数据结构C#中常见的数据结构:1数组(Array):用于存储固定大小的同类型元素集合...

C# 编程10个经典案例

C#是微软推出的一门现代化、面向对象的高级编程语言,在桌面应用、Web、移动、游戏和云计算等开发领域广泛应用。本篇文章为广大程序员整理了50个必须收藏的经典C#编程案例,助你提升实战能力。案...

C# 动态数组(ArrayList)

动态数组(ArrayList)代表了可被单独索引的对象的有序集合。它基本上可以替代一个数组。但是,与数组不同的是,您可以使用索引在指定的位置添加和移除项目,动态数组会自动重新调整它的大小。它也允许在...

c#集合排序

在C#中,集合排序是一种常见的操作,它可以帮助我们对集合中的元素进行排序。C#中提供了多种集合排序方法,包括Array.Sort、List.Sort、SortedList和SortedSet等。下面分...

c#学习手册 (苏素芳等) 高清PDF版

《c#学习手册》以初学者为核心,全面介绍了使用c#语言进行程序开发的各种技术。在内容排列上由浅入深,让读者循序渐进地掌握编程技术;在内容讲解上结合丰富的图解和形象的比喻,帮助读者理解“晦涩难懂”的技术...

C#中的数组探究与学习

C#中的数组一般分为:①.一维数组。②.多维数组,也叫矩形数组。③.锯齿数组,也叫交错数组。一.数组定义:数组是一种聚合数据类型,它是将具有相同类型的若干变量有序地组织在一起的集合,是最基本的数据结构...

C# 12最新特性解析:代码还能这样写?!微软工程师都惊呆了

在C#的持续进化历程中,每一个新版本都宛如一场技术革新的盛宴,C#12更是如此。它所带来的全新特性,不仅刷新了开发者对代码编写方式的认知,甚至连微软工程师们都为之惊叹。今天,就让我们一同深入探索C#...