POI操作Word组件haiwei-poi-word(模板+数据,简单几行代码就可以实现对word的输出)

目录

Why haiwei-poi-word

基本思想

开发方法论

术语

版本要求

快速入门

模板编写

组件能力

文本替换

最简单文本匹配

标签前后格式不同

文本中有标签

标签中不可有空格

文本框

表格支持

Loop单表

Loop单表多行

Loop并联

Loop并联多行

Loop嵌套

图片打印

代码架构

Q&A

Word版本支持03吗

图片打印宽度单位和关系

扩展能力

代码


Why haiwei-poi-word

haiwei-poi-word 基于poi,自己编码实现比较负责,且需要兼容各种版本,可以做但很繁杂。word不同于excel行列分明,并且跟实际客户端的排版设置有关系,单纯代码实现工作量大,可扩展性差,并且效果不确定。

同类比较:Poi-tl,也是个不错的组件,功能强大。有poi-tl为啥要封装Haiwei-poi呢?poi-tl就像是成品柜,Haiwei-poi-word更像是针对Saas化的定制。

侧重点不同:

poi-tl: 数据和模板没有完全分离,是用代码操作word的比较好的封装。

haiwei-poi-word则完全分离,所有样式全部由模板word决定。

基本思想

文档 = 模板 + 模型(Model)

POI操作Word组件haiwei-poi-word(模板+数据,简单几行代码就可以实现对word的输出)_第1张图片

模板: 提供所有布局和样式

Model:只提供模板中需要填充的数据

模板只在逻辑上预留位置,并设定展示的参数

组件会根据数据类型 + 展示参数 来进行展示

问题1: 如果位置是方框,参数是图片,数据是字符串 >> 字符串

问题2: 位置是文本,参数是图片,数据是字符串 >>  字符串

问题3:位置是文本,参数是图片,数据是图片 >>  根据参数展示图片

问题4:位置是文本,参数没有,数据是图片 >>  展示原图

如果模板和模型不匹配时展示原则:牺牲样式,尽可能展示数据

- 好处:把问题展示出来,有助于问题的暴露和及早进行模板或者数据调整。

模型决定数据类型

- 字符串,图片

开发方法论

TDD 测试驱动设计

这么复杂的系统,靠前期的设计很难设计完整,所以就按照case走。

术语

标签:占位符,place_holder  label sign 都指的是 ##{customer.name}

版本要求

POI 4.1.2+

JDK 1.8+

Office Word 2007(咱不支持03)

快速入门

Start

<dependency>
   <groupId>com.haiweigroupId>
   <artifactId>haiwei-poi-wordartifactId>
   <version>1.0.1version>
dependency>

模板文件:

POI操作Word组件haiwei-poi-word(模板+数据,简单几行代码就可以实现对word的输出)_第2张图片

 示例代码:

// 加载模板文件
final XWPFDocument document = HaiweiDocumentGenerator.build(new File("template.docx"));

// 数据构建
List items1 = new ArrayList<>();
items1.add(new Item1("键盘11","电子类11","2020/8/11",new HaiweiImages()));
items1.add(new Item1("键盘12","电子类12","2020/8/12",new HaiweiImages()));

items1.get(0).getImages().addFiles("img1.jpg","img2.jpg");
items1.get(1).getImages().addFiles("img2.jpg","img2.jpg");

List items2 = new ArrayList<>();
items2.add(new Item1("键盘21","电子类21","2018/8/21",new HaiweiImages()));
items2.add(new Item1("键盘22","电子类22","2018/8/22",new HaiweiImages()));

items2.get(0).getImages().addFiles("img1.jpg","img2.jpg");
items2.get(1).getImages().addFiles("img2.jpg","img2.jpg");

Order1 order1 = new Order1("梅长苏1","N0001",items1);
Order1 order2 = new Order1("梅长苏2","N0002",items2);

List orders = new ArrayList<>();
orders.add(order1);
orders.add(order2);

// 添加bean
HaiweiBeanCacheManager.setBean(orders,"orders");
// 根据路径设置 单个变量
HaiweiBeanCacheManager.setString("文档编号0011","文档编号00011");
// 打印数据树
HaiweiBeanCacheManager.print();

// 设置回调函数,解决解析过程中的数据获取场景
HaiweiBeanCacheManager.setCallBackCache(new HaiweiBeanCallback() {
    @Override
    public Object getBean(String path) {
        return null;
    }
});

//解析文档
HaiweiXWPFDocumentUtil.parse(document);

// 生成文件
final File file = new File("结果文件.docx");
HaiweiDocumentGenerator.toFile(document,file);

模板编写

组件能力

数据类型

文本(字符串,数字等可用字符串展示的),图片,图标

标签位置:

文本,文本框,表格

文档位置:

正文,页眉,页脚,备注

表格:

并联(不限制长度),嵌套(不限制深度),并联嵌套

风格:

背景,水印

说明:已支持的为黑体展示。

文本替换

标签格式:##{ 标签名称.子对象.Name1:key=value&key1=value1 }

注意:

  1. 中间不可有空格和换行(上面只是为了展示用,要不然就给替换了)
  2. 标签名称字符:中文,英文大小写,数字
  3. 风格符:点.  冒号: 等于= 与&
  4. 子对象可以多级,逻辑上没有层数限制

最简单文本匹配

##{aa}

标签前后格式不同

按照最前面字符格式展示

##{aa}

文本中有标签

@$&*1我 AAA#######{aa}}}}}BBB@$&*1我

标签中不可有空格

有空格不会替换

##{a a}

文本框

文本框处理只是位置不同,处理方式一致。

1###{aa}}}

表格支持

Loop单表

订单编号:##{order.no}

订单名称:##{order.name}

行项1

产品名称1

产品金额1

##={begin:order.items_item}##={order:time_降序}

##{ item.name}

##{ item.type}

##{ item.time1}

##={end}

Loop单表多行

订单编号:##{order.no}

订单名称:##{order.name}

行项1

产品名称1

产品金额1

##={begin:order.items_item}##={order:time_降序}

##{ item.name}

##{ item.type}

##{ item.time1}

##{ item.time}

##={end}

Loop并联

订单编号:##={编号}

订单名称:##={名称}

订单类型:##={业务类型}

订单时间:##={创建时间}

行项1

产品名称

产品金额

##={begin:Items_item}##={order: item.时间_升序/降序}

##{item.名称}

##{item.业务类型}

##={item.创建时间}

##={end}

行项1

产品名称

产品金额

##={begin:Items_item}##={order: item.时间_升序/降序}

##={ item.名称}

##={ item.业务类型}

##={ item.创建时间}

##={end}

##={begin:orders_order}

订单编号:

##={ order.no}

订单名称:

##={ order.name}

产品名称

产品类型

时间

##={begin:order.items_item}

##={item.name }

##={item.type}

##={item.time}

##={end}

##={end}

Loop并联多行

订单编号:##={order.no}

订单名称:##={order.name}

行项1

产品名称1

产品金额1

##={begin:order.items_item}##={order:time_降序}

##={ item.name}

##={ item.type}

##={ item.time1}

##={ item.time}

##={end}

行项2

产品名称2

产品金额2

##={begin:order.items_item}##={order:item.时间_降序}

##={ item.name}

##={ item.type}

##={ item.time}

##={ item.time1}

##={end}

Loop嵌套

##={begin:orderList_order}##={order:order.account_升序}

订单编号:

##={ order.no}

订单名称:

##={ order.name}

订单详细:

行项1

产品名称

产品金额

##={begin:order.Items_item}##={order:item.time_升序}

##={item.名称}

##={item.业务类型}

##={item.创建时间}

##={end}

##={end}

图片打印

  1. 表格:固定表格宽度,设置图片参数,缺省按照原图展示
  2. 文字中,插入表格,文字替换为图片
  3. 样例:
    1. ##{image_placeholder1:width=2.6&height=3.5}图片固定宽度,单位厘米
    2. ##{ image_placeholder1:size=auto} 前提条件:表格中,固定宽度,否则该参数失效。如根据图片数量,设置自动调整图片大小,布局为:2*2  3*3
    3. ##{image_placeholder1}原图输出
  4. 设置优先级:
    1. 明确指定宽和高 优先级最高
    2. 表格中,固定宽度,备注参数:size=auto,根据图片数量跳转图片宽度,高度按照宽度等比缩放
    3. 上述都没有就按照原图宽度输出
  5. 单位:point默认,px像素,cm厘米
  6. 打印图片数量limit
    1. 默认1
    2. 设置后才按照设置的数量打印,不足则按照实际输出,超过则按照limit设置数量
    3. Limit取值:all,即为全部打印
  7. 自动跳转尺寸适应内容别选了。选择后格式会通过内容多少来自动调整,可能不是用户想要的。所以需要判断字段内容的长度。

  8. 需要考虑单元格边距,默认2mm,固定宽度的时候考虑进去

代码架构

  1. HaiweiBeanCacheManager 数据提供者
    1. 提前进行线程缓存
    2. 在解析word需要数据的时候通过回调获取
  2. HaiweiXWPFDocumentUtil 文档解析类
    1. 获取文档的页眉,页脚,正文分别对段落和表格进行处理
    2. 表格处理:解析模板生成Haiweitable模型,将模型和Bean结合,删除模板行
  3. HaiweiDocumentGenerator 文档对象生成和输出为docs文件工具类

Q&A

Word版本支持03吗

暂不支持

图片打印宽度单位和关系

English Metric Units (EMUs)  英制公制单位(EMU),有时称为A单位

转换类:org.apache.poi.util.Units.toEMU

PIXEL像素 = 9525 * 1EMU

CENTIMETER厘米 = 360000 EMUs = 28.34 * Point点

Inch 英寸 = 2.54厘米

1英尺 = 12英寸

1POINT点 = 12700 * EMU = 13.3 * PIXEL像素

Point 点数 打印和印刷单位

DXA 1/20 *

Dxa/20/28.34 = 厘米

扩展能力

  1. 封装占位符和循环开始结束符,用户可自定义规则*****  提取出来
  2. SpringEL表达式***
  3. 异常处理 *
  4. 拦截器*
  5. 插件*
  6. 文档输出*****
  7. BeanCache缓存实现

代码

haiwei-poi: poi的常用操作的封装

你可能感兴趣的:(JAVA,servlet,java,poi,word)