官方教程地址:http://deepoove.com/poi-tl/

apache poi 入门示例教程:http://deepoove.com/poi-tl/apache-poi-guide.html

poi-tl模板使用方法:

1、文本标签是Word模板中最基本的标签类型,{{name}}会被数据模型中key为name的值替换,如果找不到默认会清空标签,可以配置是保留还是抛出异常。
2、图片标签以@开始,如{{@logo}}会在数据中寻找key为logo的值,然后将标签替换成图片。由于Word文档中图片不是由字符串表示(在文本型模板中,比如HTML网页图片是由字符串<img src="" />表示),所以图片标签对应的数据有一定的结构要求,这些结构都会有相应的Java类对应
3、表格标签以#开始,如{{#table}},它会被渲染成N行N列的Word表格,N的值取决于table标签的值。
4、列表标签对应Word的符号列表或者编号列表,以*开始,如{{*number}}。
5、区块对由前后两个标签组成,开始标签以?标识,结束标签以/标识,如{{?sections}}作为sections区块的起始标签,{{/sections}}为结束标签,sections是这个区块对的名称。
6、嵌套是在Word模板中引入另一个Word模板,可以理解为import、include或者word文档合并,以+标识,如{{+nested}}。

引入jar包:版本:1.8.2

<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId>
<version>1.8.2</version>
</dependency>

1、简单文字填充替换,直接写变量即可

 2、表格不用刷色和复杂样式处理,直接填充的,用jar自带的HackLoopTableRenderPolicy来实现。

注意:第一行数据要绑定属性名称

3、表格内容复杂,比如文字刷色,背景刷色,合并内单元格等的。写自定义类来实现表格填充

下面直接上案例代码:

@ApiOperation(value="日报word导出", notes="日报word导出")
@PostMapping(value = "/dayReportExport")
public void dayReportExport(HttpServletResponse response, @RequestBody JSONObject jsonObject)
{
Map<String, Object> model = new HashMap<>();//传入word数据 //解析单变量数据
model.put("exportDate", jsonObject.getString("exportDate"));
model.put("weekDay", jsonObject.getString("weekDay"));
model.put("lunarDate",jsonObject.getString("lunarDate"));
model.put("windDir",jsonObject.getString("windDir"));
model.put("windSc",jsonObject.getString("windSc"));
model.put("tmp",jsonObject.getString("tmp"));
model.put("weatherInfo",jsonObject.getString("weatherInfo"));
model.put("preWordText",jsonObject.getString("preWordText"));
model.put("dateStr",jsonObject.getString("dateStr"));
model.put("airTable1Text",jsonObject.getString("airTable1Text"));
model.put("airTable2Text",jsonObject.getString("airTable2Text"));
model.put("waterSituationText",jsonObject.getString("waterSituationText"));
model.put("o2MonthValue",jsonObject.getString("o2MonthValue"));
model.put("o2MonthTongbi",jsonObject.getString("o2MonthTongbi"));
model.put("o2YearValue",jsonObject.getString("o2YearValue"));
model.put("o2YearTongbi",jsonObject.getString("o2YearTongbi"));
model.put("upStreamText",jsonObject.getString("upStreamText"));
model.put("waterTableText",jsonObject.getString("waterTableText"));
model.put("airForeText",jsonObject.getString("airForeText"));
model.put("waterForeText",jsonObject.getString("waterForeText"));
model.put("endingDate",jsonObject.getString("endingDate")); model.put("today",jsonObject.getString("today"));
model.put("wjjTodayO2",jsonObject.getString("wjjTodayO2"));
model.put("wjjTodayLevel",jsonObject.getString("wjjTodayLevel"));
model.put("wjjYearO2",jsonObject.getString("wjjYearO2"));
model.put("wjjYearLevel",jsonObject.getString("wjjYearLevel")); //王江泾国考断面-表格里面的单变量
//第一行
JSONArray arr=jsonObject.getJSONArray("wangjjTable");
model.put("type1",arr.getJSONObject(0).getString("type"));
model.put("o21",arr.getJSONObject(0).getString("o2"));
model.put("gmindex1",arr.getJSONObject(0).getString("gmindex"));
model.put("nh3n1",arr.getJSONObject(0).getString("nh3n"));
model.put("tp1",arr.getJSONObject(0).getString("tp"));
model.put("tn1",arr.getJSONObject(0).getString("tn"));
model.put("temp1",arr.getJSONObject(0).getString("temp"));
//第二行
model.put("type2",arr.getJSONObject(1).getString("type"));
model.put("o22",arr.getJSONObject(1).getString("o2"));
model.put("gmindex2",arr.getJSONObject(1).getString("gmindex"));
model.put("nh3n2",arr.getJSONObject(1).getString("nh3n"));
model.put("tp2",arr.getJSONObject(1).getString("tp"));
model.put("tn2",arr.getJSONObject(1).getString("tn"));
model.put("temp2",arr.getJSONObject(1).getString("temp")); //处理airTable1的数据
String airTable1_str = jsonObject.getJSONArray("airTable1").toJSONString();
List<Map<String,Object>> airTable1_list = (List<Map<String,Object>>) JSONArray.parse(airTable1_str);
model.put("airTable1",airTable1_list); //处理airTable2的数据
String airTable2_str = jsonObject.getJSONArray("airTable2").toJSONString();
List<Map<String,Object>> airTable2_list = (List<Map<String,Object>>) JSONArray.parse(airTable2_str);
model.put("airTable2",airTable2_list); //处理upStreamTable的数据--要设置表格行高,没有搞定,就直接在word中写死的
// String upStreamTable_str = jsonObject.getJSONArray("upStreamTable").toJSONString();
// List<Map<String,Object>> upStreamTable_list = (List<Map<String,Object>>) JSONArray.parse(upStreamTable_str);
// model.put("upStreamTable",upStreamTable_list); //处理waterTable的数据
String waterTable_str = jsonObject.getJSONArray("waterTable").toJSONString();
List<Map<String,Object>> waterTable_list = (List<Map<String,Object>>) JSONArray.parse(waterTable_str);
model.put("waterTable",waterTable_list); //处理waterCityTable1的数据
String waterCityTable1_str = jsonObject.getJSONArray("waterCityTable1").toJSONString();
List<Map<String,Object>> waterCityTable1_list = (List<Map<String,Object>>) JSONArray.parse(waterCityTable1_str);
model.put("waterCityTable1",waterCityTable1_list); //处理waterCityTable2的数据
String waterCityTable2_str = jsonObject.getJSONArray("waterCityTable2").toJSONString();
List<Map<String,Object>> waterCityTable2_list = (List<Map<String,Object>>) JSONArray.parse(waterCityTable2_str);
model.put("waterCityTable2",waterCityTable2_list); //jar包里面自带插件-简单行循环生成(第一行数据要绑定属性名称)-没有合并单元格和刷色
HackLoopTableRenderPolicy simpleLoopPolicy = new HackLoopTableRenderPolicy(); //配置config和插件绑定
Configure config = Configure.newBuilder()
.bind("airTable1", simpleLoopPolicy)
.bind("waterCityTable1", new waterCityTable1MethodPolicy())
.bind("waterCityTable2", simpleLoopPolicy)
.bind("airTable2", new AirTable2MethodPolicy())
.bind("waterTable", new waterTableMethodPolicy()).build(); try {
String path=new ClassPathResource("templates/dayReport.docx").getUrl().getPath();
XWPFTemplate template = XWPFTemplate.compile(path,config).render(model); response.setContentType("application/octet-stream");
response.setHeader("Content-disposition","attachment;filename=\""+"out_template.docx"+"\""); OutputStream out = response.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(out);
template.write(bos);
template.close();
out.flush();
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
waterTableMethodPolicy类代码如下:
package org.jeecg.modules.systems.wordExport;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.deepoove.poi.data.RowRenderData;
import com.deepoove.poi.data.TextRenderData;
import com.deepoove.poi.data.style.TableStyle;
import com.deepoove.poi.policy.DynamicTableRenderPolicy;
import com.deepoove.poi.policy.MiniTableRenderPolicy;
import com.deepoove.poi.util.TableTools;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.jeecg.common.util.oConvertUtils;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.springframework.util.CollectionUtils; import java.util.ArrayList;
import java.util.List;
import java.util.Map; import static java.util.stream.Collectors.groupingBy; /***
* 水质分析表格数据,注意:浓度值要刷色,第一列区域要合并单元格,背景刷色
*/
public class waterTableMethodPolicy extends DynamicTableRenderPolicy{ // 填充数据所在行数
int listsStartRow = 1; @Override
public void render(XWPFTable table, Object data) {
if (null == data) {
return;
}
//tata从List<Map<String,Object>>转成JSONArray
JSONArray arr=JSON.parseArray(JSON.toJSONString(data));
if (!CollectionUtils.isEmpty(arr))
{
table.removeRow(listsStartRow);
List<RowRenderData> dataList = new ArrayList<>();
for (int x=0;x<arr.size();x++)
{
JSONObject obj=arr.getJSONObject(x);
String o2Color=obj.getString("o2Color");
o2Color=oConvertUtils.isNotEmpty(o2Color)?o2Color:"000000";
String nh3nColor=obj.getString("nh3nColor");
nh3nColor=oConvertUtils.isNotEmpty(nh3nColor)?nh3nColor:"000000";
String gmindexColor=obj.getString("gmindexColor");
gmindexColor=oConvertUtils.isNotEmpty(gmindexColor)?gmindexColor:"000000";
String tpColor=obj.getString("tpColor");
tpColor=oConvertUtils.isNotEmpty(tpColor)?tpColor:"000000";
String rankColor=obj.getString("rankColor");
rankColor=oConvertUtils.isNotEmpty(rankColor)?rankColor:"000000";
RowRenderData renderData = RowRenderData.build(
new TextRenderData(obj.getString("area"),ZDYStyle.getStyle("000000",11,"宋体")),//字体颜色和文本内容
new TextRenderData(obj.getString("riversort"),ZDYStyle.getStyle("000000",10,"Arial")),
new TextRenderData(obj.getString("sitename"),ZDYStyle.getStyle("000000",10,"宋体")),
new TextRenderData(obj.getString("rank"),ZDYStyle.getStyle(rankColor,10,"宋体")),
new TextRenderData(obj.getString("o2"),ZDYStyle.getStyle(o2Color,10,"Arial")),
new TextRenderData(obj.getString("gmindex"),ZDYStyle.getStyle(gmindexColor,10,"Arial")),
new TextRenderData(obj.getString("nh3n"),ZDYStyle.getStyle(nh3nColor,10,"Arial")),
new TextRenderData(obj.getString("tp"),ZDYStyle.getStyle(tpColor,10,"Arial"))
);
dataList.add(renderData);
}
//table循环插入行,dataList从后到前插入
for (int i = dataList.size() - 1; i >= 0; i--)
{
XWPFTableRow insertNewTableRow = table.insertNewTableRow(listsStartRow);
for (int j = 0; j < 8; j++)//8列数据
{
insertNewTableRow.createCell();
}
// 渲染单行数据
MiniTableRenderPolicy.Helper.renderRow(table, listsStartRow, dataList.get(i));
} //获取array的分组统计信息
List<Map<String,Object>> list =(List<Map<String,Object>>) data;
Map<String, List<Map<String,Object>>> groupMap = list.stream().collect(groupingBy(p->p.get("area").toString()));
List<String> groupList = JSON.parseArray(JSON.toJSONString(groupMap.keySet()), String.class);
//table的第1列数据合并,空气站的区域合并
for (int i = 0; i < dataList.size(); i++)
{
//处理第一列机组合并
Object area = dataList.get(i).getCells().get(0).getCellText();
String area_name = String.valueOf(area);
for (int j = 0; j < groupList.size(); j++)
{
String areaName = groupList.get(j);
List<Map<String,Object>> areaNameNum= groupMap.get(areaName);
if (area_name.equals(areaName))
{
if((i + 1)<=dataList.size()&&(i + areaNameNum.size())<=dataList.size())
{
// 合并第0列的第i+2行到第i+unitSize行的单元格
TableTools.mergeCellsVertically(table, 0, i + 1, i + areaNameNum.size());
//处理垂直居中
for (int y = 0; y < 8; y++)//8列数据
{
XWPFTableCell cell = table.getRow(i + 1).getCell(y);
cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER); //垂直居中
}
i=i+areaNameNum.size()-1;
}
}
}
}
//处理表格row背景刷色
String old_area_name="";
String bgStr="FFFFFF";
for (int i = 0; i < dataList.size(); i++)
{
Object area = dataList.get(i).getCells().get(0).getCellText();
String area_name = String.valueOf(area);
old_area_name=oConvertUtils.isEmpty(old_area_name)?area_name:old_area_name;//old_area_name初始给一个值
//当area的名称有变化的时候,就换一种颜色
bgStr=old_area_name.equals(area_name)?bgStr:getAnotherColor(bgStr);
for (int y = 0; y < 8; y++)//8列数据
{
XWPFTableCell cell = table.getRow(i + 1).getCell(y);
cell.setColor(bgStr);
/** 设置水平居中 */
if(y!=2)
{
CTTc cttc = cell.getCTTc();
CTTcPr ctPr = cttc.addNewTcPr();
ctPr.addNewVAlign().setVal(STVerticalJc.CENTER);
cttc.getPList().get(0).addNewPPr().addNewJc().setVal(STJc.CENTER);
}
}
old_area_name=area_name;
}
//设置表格水平居中
TableStyle style=new TableStyle();
style.setAlign(STJc.CENTER);
TableTools.styleTable(table,style);
}
}
//用户后来说,暂时不用刷色了
public String getAnotherColor(String rgbStr)
{
if(rgbStr.equals("FFFFFF"))
{
return "FFFFFF";//"EFFDFF";
}
else
{
return "FFFFFF";
}
}
}

用poi-tl导出word报告-支持表格文字刷色、背景刷色、表格合并单元格的更多相关文章

  1. java使用freemarker模板导出word(带有合并单元格)文档

    来自:https://blog.csdn.net/qq_33195578/article/details/73790283 前言:最近要做一个导出word功能,其实网上有很多的例子,但是我需要的是合并 ...

  2. java导出标题多行且合并单元格的EXCEL

    场景:项目中遇到有需要导出Excel的需求,并且是多行标题且有合并单元格的,参考网上的文章,加上自己的理解,封装成了可自由扩展的导出工具 先上效果,再贴代码: 调用工具类进行导出: public st ...

  3. 记录一下表格用poi的导出word

    也是网上找的代码http://53873039oycg.iteye.com/blog/2152009,但是横向合并单元格没成功.只能用很蠢的办法建立了好多table public void fillT ...

  4. 使用POI创建word表格合并单元格兼容wps

    poi创建word表格合并单元格代码如下: /** * @Description: 跨列合并 */ public void mergeCellsHorizontal(XWPFTable table, ...

  5. 复杂的POI导出Excel表格(多行表头、合并单元格)

    poi导出excel有两种方式: 第一种:从无到有的创建整个excel,通过HSSFWorkbook,HSSFSheet HSSFCell, 等对象一步一步的创建出工作簿,sheet,和单元格,并添加 ...

  6. poi合并单元格同时导出excel

    poi合并单元格同时导出excel POI进行跨行需要用到对象HSSFSheet对象,现在就当我们程序已经定义了一个HSSFSheet对象sheet. 跨第1行第1个到第2个单元格的操作为 sheet ...

  7. 前端Excel表格导入导出,包括合并单元格,表格自定义样式等

    表格数据导入 读取导入Excel表格数据这里采用的是 xlsx 插件 npm i xlsx 读取excel需要通过 XLSX.read(data, {type: type}) 方法来实现,返回一个叫W ...

  8. poi导出Excel报表多表头双层表头、合并单元格

    效果图: controller层方法: /**     *      * 导出Excel报表     * @param request     * @return     *      */    @ ...

  9. poi导出excel合并单元格(包括列合并、行合并)

    1 工程所需jar包如下:commons-codec-1.5.jarcommons-logging-1.1.jarlog4j-1.2.13.jarjunit-3.8.1.jarpoi-3.9-2012 ...

  10. Qt高仿Excel表格组件-支持冻结列、冻结行、内容自适应和合并单元格

    目录 一.概述 二.效果展示 三.实现思路 1.冻结行.冻结列 2.行高自适应 3.蚂蚁线 四.测试代码 1.添加表格数据 2.设置冻结行.列 3.行高.列宽 4.单元格背景色 5.单元格文字 6.其 ...

随机推荐

  1. 5 HTML表单标签

    5 表单标签 表单主要是用来收集客户端提供的相关信息,提供了用户数据录入的方式,有多选.单选.单行文本.下拉列表等输入框,便于网站管理员收集用户的数据,是Web浏览器和Web服务器之间实现信息交流和数 ...

  2. #dp#CodeChef Little Elephant and Mouses

    LEMOUSE 分析 由于被单只老鼠吓到只能算一次,所以前两次走的位置也可能会被老鼠吓到. 设 \(dp[n][m][o][p]\) 表示走到 \((n,m)\) 上一步走的是 \(o\) 这种方式, ...

  3. #Kruskal重构树,Dijkstra,倍增#洛谷 4768 [NOI2018]归程

    题目传送门 分析 首先Dijkstra是必需的(关于SPFA,它死了233) 无向图,所以先求出1号节点到所有点的距离,然后肯定希望起点能驾驶到离一号点最短的汽车可到的地方 但是怎么办,考虑海拔大的边 ...

  4. JDK12的新特性:CompactNumberFormat

    目录 简介 CompactNumberFormat详解 自定义CompactNumberFormat 解析CompactNumber 总结 JDK12的新特性:CompactNumberFormat ...

  5. Avalonia中的自绘控件

    在构建用户界面时,控件扮演着至关重要的角色.它们不仅负责展示内容,还处理用户的交互.然而,有时标准的控件库可能无法满足我们的需求,这时自绘控件就显得尤为重要.在Avalonia UI框架中,自绘控件允 ...

  6. JS解混淆

    JS解混淆 最近在整理之前和一些同伴的分享资料,发现时间已经过了好久,特此整理一些有价值的分享记录. JS混淆 学习js混淆可以逆向分析混淆和加密过程,实战可用于爬虫和渗透信息获取 本文档用于初步介绍 ...

  7. 2024-04-17:用go语言,欢迎各位勇者莅临力扣城,本次的挑战游戏名为「力扣泡泡龙」。 游戏的起点是一颗形状如二叉树的泡泡树,其中每个节点的值代表该泡泡的分值。勇者们有一次机会可以击破一个节点泡

    2024-04-17:用go语言,欢迎各位勇者莅临力扣城,本次的挑战游戏名为「力扣泡泡龙」. 游戏的起点是一颗形状如二叉树的泡泡树,其中每个节点的值代表该泡泡的分值.勇者们有一次机会可以击破一个节点泡 ...

  8. threading的定时器模块,python,每间隔一段时间执行一次任务

    工作中常有一些定时任务要处理,比如使用百度的接口,它的access_token是一个更新一次的,每次使用时总是请求会很慢,所以我们把它保存起来,用定时器模块,定时在过期之前请求一次,或者定时数据同步, ...

  9. C#S7.NET实现西门子PLCDB块数据采集的完整步骤

    前言 本文介绍了如何使用S7.NET库实现对西门子PLC DB块数据的读写,记录了使用计算机仿真,模拟PLC,自至完成测试的详细流程,并重点介绍了在这个过程中的易错点,供参考. 用到的软件: 1.Wi ...

  10. SQL Server实战一:创建、分离、附加、删除、备份数据库

      本文介绍基于Microsoft SQL Server软件,实现数据库创建.分离.附加.删除与备份的方法. 目录 1 交互式创建数据库 2 Transact-SQL指定参数创建数据库 3 交互式分离 ...