使用Word模板導出標准表Word樣式文件
使用Word模板導出標准表Word樣式文件
協議:CC BY-SA 4.0 https://creativecommons.org/licenses/by-sa/4.0/
版權聲明:本文為原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
目錄
接了個需求要做Word文件導出,導出的Word中有樣式還有表格。表格還要合並;最離譜的是還要有附件。
表頭樣式和內容是這樣:
表的合並這樣:
豎向表格
附件和附件內容是這樣:
具體這種樣式怎么實現。下面講解下
第一步:首先我們要引用一個工具包poi-tl
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId>
<version>1.10.2</version>
<exclusions>
<exclusion>
<artifactId>xalan</artifactId>
<groupId>xalan</groupId>
</exclusion>
</exclusions>
</dependency>
至於為啥是1.10.2 不是 11版本暫時跟項目架包沖突,所以改為10的版本
第二步:做一個Word模板
模板怎么做。如果是文本,我們直接使用 {{變量名}}
表格也可以這么使用
這個是我的模板:
第三步:開始編寫代碼
1.先建一個實體類:
package com.example.test.controller;
import java.util.List;
import com.deepoove.poi.data.AttachmentRenderData;
import com.deepoove.poi.data.TableRenderData;
import com.deepoove.poi.expression.Name;
import lombok.Data;
@Data
public class WordDO {
private TableRenderData order;
/**
* 一、用戶總體應用情況-表
*/
@Name("detail_table")
private UserApplicationTableDO userApplicationTableDO;
/**
* 三、用戶分析-表
*/
@Name("table1")
private UserApplicationTableDO table1;
/**
* 三、用戶分析-表
*/
@Name("table2")
private UserApplicationTableDO table2;
/**
* 四、用戶行為分析-表
*/
@Name("table3")
private UserApplicationTableDO table3;
@Name("table5")
private List<Table5Entity> table5;
/**
* 六、產品生產力
*/
@Name("table6")
private UserApplicationTableDO table6;
/**
* 六、產品生產力
*/
@Name("table7")
private UserApplicationTableDO table7;
@Name("table8")
private UserApplicationTableDO table8;
private String header;
private String secondHeader;
private String monthReportName;
private String monthReportContent;
@Name("xlsx")
private AttachmentRenderData xlsx;
}
2.然后是Controller 實現方法我直接寫在Controller里了
package com.example.test.controller;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.data.AttachmentType;
import com.deepoove.poi.data.Attachments;
import com.deepoove.poi.data.RowRenderData;
import com.deepoove.poi.data.Rows;
import com.deepoove.poi.policy.AttachmentRenderPolicy;
import com.deepoove.poi.policy.RenderPolicy;
@Controller
@RequestMapping("word")
public class PaymentExampleController {
@RequestMapping("word")
public void getWord() throws Exception {
File file = ResourceUtils.getFile("classpath:wordtemplate/month_report_template.docx");
FileInputStream inputStream = new FileInputStream(file);
WordDO worDo = new WordDO();
worDo.setHeader("中國集團內部部文件");
worDo.setSecondHeader("中國集團〔2021〕3 號");
worDo.setMonthReportName("中國集團服務運營通報(2021年第1期)");
worDo.setMonthReportContent("運營管理部、安全管理中心、大數據應用部、管理信息系統部、研發創新中心、智慧中台運營中心、計費清結算中心、建築部門:\\r\\n\"\r\n"
+ " + \"引言部分(待補充)。\\r\\n");
/**
* 第一個表格:用戶總體應用情況-表格
*/
UserApplicationTableDO detailTable = new UserApplicationTableDO();
RowRenderData good001 = Rows.of("001", "牆紙-001", "1600").center().create();
RowRenderData good002 = Rows.of("002", "牆紙-002", "100").center().create();
List<RowRenderData> goods = Arrays.asList(good001, good002);
detailTable.setLabors(goods);
worDo.setUserApplicationTableDO(detailTable);
/**
* 第一個表格:產品使用情況-表格
*/
UserApplicationTableDO product_table = new UserApplicationTableDO();
RowRenderData product_z_001 = Rows.of("001", "智慧中台運營中心", "2","聯調測試平台", "XX項目、XX業務").center().create();
RowRenderData product_z_002 = Rows.of("002", "智慧中台運營中心", "2","用戶模擬平台", "XX項目").center().create();
List<RowRenderData> product_z = Arrays.asList(product_z_001, product_z_002);
product_table.setLabors(product_z);
worDo.setTable1(product_table);
/**
* 第二個表格:用戶總體應用情況-表格
*/
UserApplicationTableDO detailTable2 = new UserApplicationTableDO();
RowRenderData table1 = Rows.of("001", "牆紙-001", "1600","001", "牆紙-001", "1600","4").center().create();
RowRenderData table2 = Rows.of("002", "牆紙-002", "100","001", "牆紙-001", "1600","4").center().create();
List<RowRenderData> tables = Arrays.asList(table1, table2);
detailTable2.setLabors(tables);
worDo.setTable2(detailTable2);
/**
* 第三個表格:用戶總體應用情況-表格
*/
UserApplicationTableDO detailTable3 = new UserApplicationTableDO();
RowRenderData table3 = Rows.of("001", "基礎建設", "以桑基圖形式展現").center().create();
RowRenderData table4 = Rows.of("002", "基礎建設", "以桑基圖形式展現").center().create();
List<RowRenderData> tables_x = Arrays.asList(table3, table4);
detailTable3.setLabors(tables_x);
worDo.setTable3(detailTable3);
/**
* 第三個表格:用戶總體應用情況-表格
*/
UserApplicationTableDO detailTable6 = new UserApplicationTableDO();
RowRenderData table_y_001 = Rows.of("001", "基礎建設平台", "100", "15", "1500", "5").center().create();
RowRenderData table_y_002 = Rows.of("002", "基礎建設平台", "100", "15", "1500", "5").center().create();
List<RowRenderData> tables_y = Arrays.asList(table_y_001, table_y_002);
detailTable6.setLabors(tables_y);
worDo.setTable6(detailTable6);
/**
* 第三個表格:七、本月新增需求情況
*/
UserApplicationTableDO detailTable7 = new UserApplicationTableDO();
RowRenderData table_7_001 = Rows.of("001", "售樓部中心", "XXX業務/項目", "試點類", "售樓部平台").center().create();
RowRenderData table_7_002 = Rows.of("002", "售樓部支撐中心", "XXX業務/項目", "試點類", "售樓部平台").center().create();
List<RowRenderData> tables_7 = Arrays.asList(table_7_001, table_7_002);
detailTable7.setLabors(tables_7);
worDo.setTable7(detailTable7);
/**
* 第三個表格:業務測試產品聯系人
*/
UserApplicationTableDO detailTable8 = new UserApplicationTableDO();
RowRenderData table_8_001 = Rows.of("數據庫測試產品服務", "李二林", "", "").center().create();
RowRenderData table_8_002 = Rows.of("性能測試產品服務", "李二林", "", "").center().create();
RowRenderData table_8_003 = Rows.of("性能測試產品服務", "李二林", "", "").center().create();
RowRenderData table_8_004 = Rows.of("性能測試產品服務", "李二林", "", "").center().create();
RowRenderData table_8_005 = Rows.of("性能測試產品服務", "李二林", "", "").center().create();
List<RowRenderData> table_8 = Arrays.asList(table_8_001, table_8_002,table_8_003, table_8_004, table_8_005);
detailTable8.setLabors(table_8);
worDo.setTable8(detailTable8);
RenderPolicy hackLoopSameLineTableRenderPolicy = new LoopColumnTableRenderPolicyNew(true);
List<Table5Entity> table5 = new ArrayList<>();
Table5Entity table5Entity = new Table5Entity();
table5Entity.setNum(1);
table5Entity.setProductName("售樓部平台");
table5Entity.setUserRegisterCount(1000);
table5Entity.setUserAddCount(100);
table5Entity.setActiveCount(101);
table5Entity.setActivePerenct("100%");
table5Entity.setVisitDepth("2");
table5Entity.setSilenceUserCount("10");
table5Entity.setSilencePercent("20%");
table5Entity.setLoseUserCount("123");
table5Entity.setLosePercent("12%");
table5Entity.setBackUserCount("21");
table5Entity.setBackPercent("2%");
table5.add(table5Entity);
table5.add(table5Entity);
table5.add(table5Entity);
worDo.setTable5(table5);
/**
* 附件 -- 接口獲取一個Excel文件流
*/
//worDo.setXlsx(Attachments.ofLocal("D:\\sts4.10.0_workspace\\test\\test\\src\\main\\resources\\wordtemplate\\a.xlsx", AttachmentType.XLSX).create());
File fileExcel = ResourceUtils.getFile("classpath:wordtemplate/a.xlsx");
FileInputStream excelinputStream = new FileInputStream(fileExcel);
worDo.setXlsx(Attachments.ofStream(excelinputStream, AttachmentType.XLSX).create());
/**
* 讀取Excel內容並 寫入word
*/
List<Integer> list = new ArrayList<>();
list.add(2);
Configure config = Configure.builder()
.bind("detail_table", new DetailTablePolicy(3))
.bind("table1", new DetailTablePolicyMerge(5,list))
.bind("table2", new DetailTablePolicy(7))
.bind("table3", new DetailTablePolicy(3))
.bind("table6", new DetailTablePolicy(6))
.bind("table7", new DetailTablePolicy(5))
.bind("table8", new DetailTablePolicy(4))
.bind("table5", hackLoopSameLineTableRenderPolicy)
.bind("xlsx", new AttachmentRenderPolicy())
.build();
XWPFTemplate template = XWPFTemplate.compile(inputStream, config).render(worDo);
template.writeAndClose(new FileOutputStream("D:\\sts4.10.0_workspace\\test\\test\\src\\main\\resources\\wordtemplate\\templateAAA.docx"));
System.out.println("========================>>>>");
}
}
3.UserApplicationTableDO類
package com.example.test.controller;
import java.util.List;
import com.deepoove.poi.data.RowRenderData;
import lombok.Data;
@Data
public class UserApplicationTableDO {
private List<RowRenderData> labors ;
}
4.表格渲染方法實現 DetailTablePolicy
package com.example.test.controller;
import java.util.List;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import com.deepoove.poi.data.RowRenderData;
import com.deepoove.poi.policy.DynamicTableRenderPolicy;
import com.deepoove.poi.policy.TableRenderPolicy;
public class DetailTablePolicy extends DynamicTableRenderPolicy{
// 表格有幾列
int column = 0;
public DetailTablePolicy(int i) {
column = i;
}
@Override
public void render(XWPFTable table, Object data) throws Exception {
if (null == data) return;
TableStyle.setTableStyle(table);
UserApplicationTableDO detailData = (UserApplicationTableDO) data;
List<RowRenderData> goods = detailData.getLabors();
if (null != goods) {
table.removeRow(Contanst.START_ROW);
for (int i = 0; i < goods.size(); i++) {
XWPFTableRow insertNewTableRow = table.insertNewTableRow(Contanst.START_ROW);
for (int j = 0; j < column; j++) insertNewTableRow.createCell();
//TableStyle.setFontStyle();
TableRenderPolicy.Helper.renderRow(table.getRow(Contanst.START_ROW), goods.get(i), TableStyle.setFontStyle());
}
}
}
}
5.單元格合並實現類
package com.example.test.controller;
import java.util.ArrayList;
import java.util.List;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import com.deepoove.poi.data.CellRenderData;
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 cn.hutool.core.collection.CollUtil;
public class DetailTablePolicyMerge extends DynamicTableRenderPolicy{
// 表格有幾列
int column = 0;
List<Integer> listMerge = new ArrayList<>();
public DetailTablePolicyMerge(int i, List<Integer> list) {
column = i;
list.forEach(e->{listMerge.add(e);});
}
@Override
public void render(XWPFTable table, Object data) throws Exception {
if (null == data) return;
TableStyle.setTableStyle(table);
UserApplicationTableDO detailData = (UserApplicationTableDO) data;
List<RowRenderData> goods = detailData.getLabors();
if (null != goods) {
table.removeRow(Contanst.START_ROW);
for (int i = 0; i < goods.size(); i++) {
XWPFTableRow insertNewTableRow = table.insertNewTableRow(Contanst.START_ROW);
for (int j = 0; j < column; j++) insertNewTableRow.createCell();
//合並單元格
TableRenderPolicy.Helper.renderRow(table.getRow(Contanst.START_ROW), goods.get(i), TableStyle.setFontStyle());
}
}
// 合並第0列的第1行到第2行的單元格 [2,3,4]
if(CollUtil.isNotEmpty(listMerge)) {
for (int i = 0; i < listMerge.size(); i++) {
if(i==0) {
TableTools.mergeCellsVertically(table, 1, 1, listMerge.get(i));
TableTools.mergeCellsVertically(table, 2, 1, listMerge.get(i));
}else {
TableTools.mergeCellsVertically(table, 1, i + listMerge.get(i-1), listMerge.get(i));
TableTools.mergeCellsVertically(table, 2, i + listMerge.get(i-1), listMerge.get(i));
}
}
}
}
}
6.用到的常量Contanst
package com.example.test.controller;
public class Contanst {
public static int START_ROW = 1;
}
7.表格樣式TableStyle
package com.example.test.controller;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import com.deepoove.poi.data.style.Style;
public class TableStyle {
/**
* @Title: setTableStyle
* @Description: 設置表格邊框 為黑色橫線
* @Author liuren
* @DateTime 2021年12月2日 下午9:58:43
* @param table
*/
public static void setTableStyle(XWPFTable table) {
table.setInsideHBorder(XWPFTable.XWPFBorderType.SINGLE,1,1,"010101"); //設置table的內部橫向邊框
table.setInsideVBorder(XWPFTable.XWPFBorderType.SINGLE,1,1,"010101");//設置table的內部縱向邊框
table.setBottomBorder(XWPFTable.XWPFBorderType.SINGLE,1,1,"010101"); //設置table的頂部邊框
table.setTopBorder(XWPFTable.XWPFBorderType.SINGLE,1,1,"010101");//設置table的頂部邊框
table.setLeftBorder(XWPFTable.XWPFBorderType.SINGLE,1,1,"010101");//設置table的頂左邊框
table.setRightBorder(XWPFTable.XWPFBorderType.SINGLE,1,1,"010101");//設置table的右部邊框
}
/**
* @Title: setFontStyle
* @Description: 設置動態表格中的字體樣式和字體大小
* @Author liuren
* @DateTime 2021年12月2日 下午10:02:10
* @return
*/
public static Style setFontStyle() {
Style style = new Style();
style.setFontFamily("仿宋");
style.setFontSize(14);
return style;
}
}
最后我的整體的pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>test</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.3.7.RELEASE</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.11</version>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.2</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.1</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>27.0-jre</version>
</dependency>
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId>
<version>1.11.0</version>
<exclusions>
<exclusion>
<artifactId>xalan</artifactId>
<groupId>xalan</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId> e-iceblue </groupId>
<artifactId>spire.office.free</artifactId>
<version>3.9.0</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.7.RELEASE</version>
<configuration>
<mainClass>com.example.test.TestApplication</mainClass>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
最后附上我的Word模板,供大家下載:https://www.codepeople.cn/imges/month_report_template.docx
這就完成了,然后調用下接口,就能生成Word了。還帶附件哦。
下次抽時間 寫下 Word生成的PDF的方法
=====================================================================