用poi-tl导出word报告-支持表格文字刷色、背景刷色、表格合并单元格
官方教程地址: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"; } } }