建议还是拉下代码下来看 【点击此处进行跳转】
结合图片来解析 例如
官方文档: http://deepoove.com/poi-tl/#_%E5%9B%BE%E7%89%87
com.deepoove
poi-tl
1.12.1
@Test
void contextLoads() throws IOException {
// 一、初始化数据
// 1)初始化模板数据-实际是去数据库查询-自行整合
Templates templates = initTemplates();
// 2)初始化家庭成员信息-实际是去数据库查询-自行整合
List familyMemberList = initFamilyMember();
// 3)初始化工作情况-实际是去数据库查询-自行整合
List goingList = initGoing();
// 二、初始化动态数据-并整合一个完整的对象
// 1)处理动态数据->转为RowRenderData类型即List->List
TemplateRowRenderData templateRowRenderData = new TemplateRowRenderData(familyMemberList,goingList);
// 2)完整数据
TemplateData templateData = new TemplateData(templates,templateRowRenderData);
// 三、绑定插件
// 1)插件绑定-【TemplateTableRenderPolicy】插件中data能获取到【TemplateRowRenderData】动态数据的关键
// 注意:模板中也是根据该字段进行渲染:templateRowRenderData 如图resources/pictures/images1.jpg 特别注意不要用到了中文画框花,鼠鼠我郁闷了一早上也想不明道插件为什么不生效
Configure config = Configure.builder().bind("templateRowRenderData", new TemplateTableRenderPolicy()).build();
// 四、导出
ClassPathResource classPathResource = new ClassPathResource("templates" + File.separator + "鼠鼠教你如何实现动态导出.docx");
XWPFTemplate template = XWPFTemplate.compile(classPathResource.getInputStream(),config).render(
templateData);
// 通过浏览器下载自行整合下即可
// controller获取HttpServerResponse
template.writeAndClose(new FileOutputStream("C:\\Users\\muyangren\\Desktop\\output.docx"));
}
private Templates initTemplates() {
// 填充一些基本信息
Templates templates = new Templates();
templates.setName("吃了没");
templates.setAliases("吃我一拳");
templates.setDeptName("勿入鼠穴");
templates.setSexName("gay");
templates.setPeoples("汉族");
templates.setBirth("2000");
templates.setCulture("胎教");
return templates;
}
/**
* 测试数据、实际是需要查询数据库的
* @return
*/
private List initFamilyMember() {
List familyMemberList = new ArrayList<>();
for (int i = 0; i < 3; i++) {
FamilyMember familyMember = new FamilyMember();
familyMember.setRelationship("好兄弟" + i);
familyMember.setName("姓名" + i);
familyMember.setPosition("摸鱼关系户" + i);
familyMemberList.add(familyMember);
}
return familyMemberList;
}
/**
* 测试数据
*
* @return
*/
private List initGoing() {
List goingList = new ArrayList<>();
for (int i = 0; i < 3; i++) {
Going going = new Going();
going.setCompany("比命苦美式" + i);
going.setAddress("来一杯比我命还苦的冰美式、不加糖" + i);
going.setPhone("程序跑不起来,美式,我能跑就行" + i);
goingList.add(going);
}
return goingList;
}
import com.deepoove.poi.data.*;
import com.deepoove.poi.data.style.*;
import com.deepoove.poi.policy.TableRenderPolicy;
import com.muyangren.poidemo.entity.FamilyMember;
import com.muyangren.poidemo.entity.Going;
import lombok.Data;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@Data
public class TemplateRowRenderData {
/**
* 家庭人员
*/
private List familyRowRenderDataList;
/**
* 工作情况
*/
private List goingRowRenderDataList;
private RowStyle rowStyle;
public TemplateRowRenderData(List familyMemberList, List goingList) {
// 初始化样式
initStyle();
// 初始化动态数据
initData(familyMemberList, goingList);
}
private void initStyle() {
// 此处定义样式的优先级高:想看样式获取顺序可以看【TemplateTableRenderPolicy】中的【TableRenderPolicy.Helper.renderRow(xwpfTable.getRow(familyMemberRow), familyRowRenderDataList.get(i))】 谢谢你作者 很规范 nmd
// 字体样式
Style style = new Style("宋体", 10);
// 段落样式
ParagraphStyle paragraphStyle = new ParagraphStyle();
paragraphStyle.setDefaultTextStyle(style);
// ps:这里才是字体居中对齐
paragraphStyle.setAlign(ParagraphAlignment.CENTER);
// 表格样式
CellStyle cellStyle = new CellStyle();
// ps:表格也需要居中,否则字体不在正中间,会偏上
cellStyle.setVertAlign(XWPFTableCell.XWPFVertAlign.CENTER);
cellStyle.setDefaultParagraphStyle(paragraphStyle);
// 行样式
this.rowStyle = new RowStyle();
rowStyle.setDefaultCellStyle(cellStyle);
}
private void initData(List familyMemberList, List goingList) {
List newFamilyRowRenderDataList = new ArrayList<>();
List newGoingRowRenderDataList = new ArrayList<>();
// 判空-家庭人员
if (CollectionUtils.isNotEmpty(familyMemberList)) {
for (FamilyMember familyMember : familyMemberList) {
// 创建一行五表格(根据实际情况来哈)
List cellDataList = new ArrayList<>();
// 留两个空格(为什么要留两个空白格,大家可以试试自己去添加下行就知道了) 如图:resources/pictures/images3.jpg|images2.jpg
cellDataList.add(new CellRenderData().addParagraph(new ParagraphRenderData().addText("")));
cellDataList.add(new CellRenderData().addParagraph(new ParagraphRenderData().addText("")));
cellDataList.add(new CellRenderData().addParagraph(new ParagraphRenderData().addText(familyMember.getRelationship())));
cellDataList.add(new CellRenderData().addParagraph(new ParagraphRenderData().addText(familyMember.getName())));
cellDataList.add(new CellRenderData().addParagraph(new ParagraphRenderData().addText(familyMember.getPosition())));
RowRenderData rowRenderData = new RowRenderData();
// 样式
rowRenderData.setRowStyle(rowStyle);
rowRenderData.setCells(cellDataList);
newFamilyRowRenderDataList.add(rowRenderData);
}
this.familyRowRenderDataList = newFamilyRowRenderDataList;
}else {
// 要是不存在传null值的话,插件里就要多一层判断了
this.familyRowRenderDataList= Collections.emptyList();
}
// 判空-工作情况
if (CollectionUtils.isNotEmpty(goingList)) {
for (Going going : goingList) {
// 创建一行四表格(根据实际情况来哈)
List cellDataList = new ArrayList<>();
// 保留一个空格(如【家庭成员所示】)
cellDataList.add(new CellRenderData().addParagraph(new ParagraphRenderData().addText("")));
cellDataList.add(new CellRenderData().addParagraph(new ParagraphRenderData().addText(going.getCompany())));
cellDataList.add(new CellRenderData().addParagraph(new ParagraphRenderData().addText(going.getAddress())));
cellDataList.add(new CellRenderData().addParagraph(new ParagraphRenderData().addText(going.getPhone())));
RowRenderData rowRenderData = new RowRenderData();
// 样式
rowRenderData.setRowStyle(rowStyle);
rowRenderData.setCells(cellDataList);
newGoingRowRenderDataList.add(rowRenderData);
}
this.goingRowRenderDataList = newGoingRowRenderDataList;
}else {
this.goingRowRenderDataList= Collections.emptyList();
}
}
}
import com.deepoove.poi.data.RowRenderData;
import com.deepoove.poi.policy.DynamicTableRenderPolicy;
import com.deepoove.poi.policy.TableRenderPolicy;
import com.deepoove.poi.util.TableTools;
import lombok.NoArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import java.util.List;
@NoArgsConstructor
public class TemplateTableRenderPolicy extends DynamicTableRenderPolicy {
@Override
public void render(XWPFTable xwpfTable, Object data) throws Exception {
if (null == data) {
return;
}
//-----------------------------------先别急,一行一行看下去-------------------------------------------------------
// 因为我们前面用Config绑定了【List】渲染规则
TemplateRowRenderData templateRowRenderData = (TemplateRowRenderData) data;
// 一、处理家庭成员数据
List familyRowRenderDataList = templateRowRenderData.getFamilyRowRenderDataList();
if (CollectionUtils.isNotEmpty(familyRowRenderDataList)) {
// 1)计算家庭成员表头所在行数 如图:resource/pictures/images4.jpg
int familyMemberRow = 9;
// 2)删掉空白内容:xwpfTable.removeRow是从下标0开始计算的,所以这里删除的是空白内容如图:resource/pictures/images5.jpg
xwpfTable.removeRow(familyMemberRow);
// 3)获取该表家庭成员表头高度 【familyMemberRow-1】即家庭成员表头的下标 作用:统一高度
XWPFTableRow xwpfTableRow = xwpfTable.getRow(familyMemberRow-1);
// 4)循环插入行 (倒序插入)ps:这里是一直在第9行插入表格。
for (int i = familyRowRenderDataList.size() - 1; i > -1; i--) {
// 4.1)插入表格
XWPFTableRow insertNewTableRow = xwpfTable.insertNewTableRow(familyMemberRow);
// 4.1.1)控制表格高度
insertNewTableRow.setHeight(xwpfTableRow.getHeight());
// 4.2)每行添加11个表格,这里需要根据实际情况填充。秉持多则退少补原则
// 如图:假如我添加12个 resource/pictures/images6.jpg
// 如图:假如我添加10个 resource/pictures/images7.jpg
// 注:想看效果时记得注释下面的代码 【TableTools.mergeCellsHorizonal】,【TableTools.mergeCellsVertically】
for (int j = 0; j < 11; j++) {
insertNewTableRow.createCell();
}
// 基本信息占1格,家庭成员占1个,关系、姓名、职位各占3 刚好11格
// 5)合并上面创建的11个单元格 fromCol-toCol 且 fromCol(起始) < toCol(结束)
// 5.1)【关系】下标为2,所以2(fromCol)合并至4(toCol)的单元格
TableTools.mergeCellsHorizonal(xwpfTable, familyMemberRow, 2, 4);
// 5.2)【姓名】下标为3,所以3(fromCol)合并至5(toCol)的单元格:注意:按上一个合并后的结果再数格子并合并
TableTools.mergeCellsHorizonal(xwpfTable, familyMemberRow, 3, 5);
// 5.3)【职位】下标为4,所以4(fromCol)合并至6(toCol)的单元格:注意:按上一个合并后的结果再数格子并合并
TableTools.mergeCellsHorizonal(xwpfTable, familyMemberRow, 4, 6);
// 6) 渲染数据(表格对齐后在进行渲染数据)
TableRenderPolicy.Helper.renderRow(xwpfTable.getRow(familyMemberRow), familyRowRenderDataList.get(i));
}
// 7)跨行合并行 参数说明: 1-操作表格方法 2-需要合并行 3-开始合并列 4-结束合并列
// 7.1) 合并前:resource/pictures/images8.jpg
// 7.2) 合并后:resource/pictures/images9.jpg
int fromRow = familyMemberRow - 1;
// 7.3)合并下标为1的行 合并列为fromRow->familyRowRenderDataList.size() + fromRow
// 7.4)合并下标为0的行 合并列为0->familyRowRenderDataList.size() + fromRow
TableTools.mergeCellsVertically(xwpfTable, 1, fromRow, familyRowRenderDataList.size() + fromRow);
TableTools.mergeCellsVertically(xwpfTable, 0, 0, familyRowRenderDataList.size() + fromRow);
}
//---------------------------------------以上为家庭成员的数据渲染------------------------------------------------------------
// 二、处理工作情况数据-关键处此篇不给出解析,大家根据【家庭成员】 自行填写
List goingRowRenderDataList = templateRowRenderData.getGoingRowRenderDataList();
// 1)判空
if (CollectionUtils.isNotEmpty(goingRowRenderDataList)) {
// 2)工作情况所在行数 ps:其实我们从0开始数的话、可以省很多事
int goingMemberRow = 11;
if (!CollectionUtils.isEmpty(familyRowRenderDataList)) {
goingMemberRow = 11 + familyRowRenderDataList.size() - 1;
}
// 3)
xwpfTable.removeRow(goingMemberRow);
// 4)
XWPFTableRow xwpfTableRow = xwpfTable.getRow(goingMemberRow-1);
// 5)循环插入行(倒序插入)
for (int i = goingRowRenderDataList.size() - 1; i > -1; i--) {
XWPFTableRow insertNewTableRow = xwpfTable.insertNewTableRow(goingMemberRow);
insertNewTableRow.setHeight(xwpfTableRow.getHeight());
// 6)
for (int j = 0; j < 11; j++) {
insertNewTableRow.createCell();
}
// 7)
// 7.1)合并表格
TableTools.mergeCellsHorizonal(xwpfTable, goingMemberRow, 1, 2);
// 7.2)合并表格
TableTools.mergeCellsHorizonal(xwpfTable, goingMemberRow, 2, 7);
// 7.3)合并表格
TableTools.mergeCellsHorizonal(xwpfTable, goingMemberRow, 3, 4);
// 8)渲染数据
TableRenderPolicy.Helper.renderRow(xwpfTable.getRow(goingMemberRow), goingRowRenderDataList.get(i));
}
// 9)合并行
TableTools.mergeCellsVertically(xwpfTable,0,goingMemberRow-1,goingMemberRow +goingRowRenderDataList.size()-1);
}
}
}