0%

easyexcel使用

easyexcel的使用

easyescel官方文档:

1
https://easyexcel.opensource.alibaba.com/docs/current/quickstart/read#%E5%A4%9A%E8%A1%8C%E5%A4%B4

依赖

1
2
3
4
5
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.3</version>
</dependency>

导入excel

  1. 配置监听器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.cloudwise.entity.VO.AuthManageExcelVO;
import com.cloudwise.entity.VO.AuthManageVO;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
* 填写具体类的描述
*
* @author: turbo.wu
* @since: 2022-11-15 17:32
**/
public class EasyExcelListener extends AnalysisEventListener {
// 指定读取的数据
private List<AuthManageExcelVO> data = new ArrayList<>();

/**
* 每读取一行就会调用这个方法,
* @param o 是每一行的数据,LinkHashMap key: 列号,从0开始 value: 值
*/
@Override
public void invoke(Object o, AnalysisContext analysisContext) {
System.out.println(o);
@SuppressWarnings("unchecked")
Map<Integer, String> map = (LinkedHashMap<Integer, String>) o;
AuthManageExcelVO authManageExcelVO = new AuthManageExcelVO();
// 生成数据
authManageExcelVO.setUmAccountName(map.getOrDefault(1, ""));
authManageExcelVO.setUsername(map.getOrDefault(2, ""));
authManageExcelVO.setDepartmentName(map.getOrDefault(3, ""));
authManageExcelVO.setHrPosition(map.getOrDefault(4, ""));
authManageExcelVO.setDirectSuperiorsName(map.getOrDefault(5, ""));
authManageExcelVO.setRoleName(map.getOrDefault(6, ""));
authManageExcelVO.setActuatorName(map.getOrDefault(7, ""));
authManageExcelVO.setExpiredDate(map.getOrDefault(8, ""));
authManageExcelVO.setApplyExplain(map.getOrDefault(9, ""));
this.data.add(authManageExcelVO);

}

@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {

}

public void setData(List<AuthManageExcelVO> data) {
this.data = data;
}

public List<AuthManageExcelVO> getData() {
return data;
}
}
  1. 使用EasyExcelFactory读取excel文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void importExcel(MultipartFile file) {
Inputstream inputStream = file.getInputStream();
/**
* 读取excel数据
*/
// 创建监听器对象
EasyExcelListener listener = new EasyExcelListener();
// 构建easyExcel读对象。 headRowNumber,指定从excel文件中的哪一行开始读,从0开始,这里是8,则是从第9行开始读起
ExcelReader excelReader = EasyExcelFactory.read(inputStream, listener).headRowNumber(8).build();
// 读取excel的sheet, 可以传入多个sheet, 使用new ReadSheet("传入sheetNo,从0开始",@Nullable("可以不传") "传入sheetName")
excelReader.read(new ReadSheet(0));
// 从监听器中获取暂存的数据, 这里数据的数据类型由你自己指定
List<AuthManageExcelVO> data = listener.getData();
System.out.println(data);
}

生成excel模版

很多时候需要生成excel模版,给用户下载,用户按照模版的填写要求进行填写之后,将文件上传,从而填写的数据存放到数据库。模版的生成主要是一些复杂表头

  1. 新建自定义策略,自己根据需要设置固定的单元格样式, 主要是对模版,即表头进行设定
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.style.AbstractCellStyleStrategy;
import org.apache.poi.ss.usermodel.*;

import java.util.List;

/**
* @Description: 标题样式工具类
* @Date: 2022/2/21 16:34
*/
public class TitleStyleUtils extends AbstractCellStyleStrategy {
// 列名list,里面存放的是excel的表头列
private List<String> names;
// excel工作簿对象
private Workbook workbook;

public TitleStyleUtils() {

}

public TitleStyleUtils(List<String> names) {
this.names = names;
}

@Override
protected void initCellStyle(Workbook workbook) {
this.workbook = workbook;
}

/**
* 对表头进行单元格样式设置
* @param cell 单元格对象
* @param head
* @param relativeRowIndex 当前行号,从0开始
*/
@Override
protected void setHeadCellStyle(Cell cell, Head head, Integer relativeRowIndex) {
// 根据自己的需要对指定的行或者列进行单元格样式设置,例如这里对第1行第1列的单元格进行设置
if (cell.getColumnIndex() == 0 && relativeRowIndex == 0) {
// 从工作簿对象中获取当单元格样式对象
CellStyle cellStyle = workbook.createCellStyle();

// 设置单元格对齐方式, 第一个是水平对齐方式,第二个是垂直方向的对齐方式
cellStyle.setAlignment(HorizontalAlignment.CENTER);
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);

// 要想显示单元格的背景色,必须设置这个
cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
cellStyle.setFillForegroundColor(IndexedColors.TAN.getIndex());

// 给单元格添加边框, 上下左右
cellStyle.setBorderLeft(BorderStyle.THIN);
cellStyle.setBorderRight(BorderStyle.THIN);
cellStyle.setBorderBottom(BorderStyle.THIN);
cellStyle.setBorderTop(BorderStyle.THIN);

//是否自动换行,单元格的字是否开启自动换行
cellStyle.setWrapText(true);

// 对字体进行设定
Font font = workbook.createFont();
//颜色
font.setColor(IndexedColors.BLACK.getIndex());
//加粗
font.setBold(true);
//字体
font.setFontName("宋体");
//大小
font.setFontHeightInPoints((short) 18);
//高度
workbook.getSheetAt(0).getRow(0).setHeight((short) 2700);
//宽度
workbook.getSheetAt(0).setColumnWidth(cell.getColumnIndex(), 2000);
cellStyle.setFont(font);
cell.setCellStyle(cellStyle);
}

if (cell.getColumnIndex() == 1 && relativeRowIndex == 0) {
CellStyle cellStyle = workbook.createCellStyle();
cellStyle.setWrapText(true);
//设置 水平居中
cellStyle.setAlignment(HorizontalAlignment.LEFT);
//设置 垂直居中
cellStyle.setVerticalAlignment(VerticalAlignment.TOP);
cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
cellStyle.setBorderLeft(BorderStyle.THIN);
cellStyle.setBorderRight(BorderStyle.THIN);
cellStyle.setBorderBottom(BorderStyle.THIN);
cellStyle.setBorderTop(BorderStyle.THIN);
cellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
Font font = workbook.createFont();
//颜色
font.setColor(IndexedColors.BLACK.getIndex());
//加粗
font.setBold(true);
//字体
font.setFontName("宋体");
//大小
font.setFontHeightInPoints((short) 12);
//高度
workbook.getSheetAt(0).getRow(0).setHeight((short) 2700);
//宽度
workbook.getSheetAt(0).setColumnWidth(cell.getColumnIndex(), 20000);
cellStyle.setFont(font);
cell.setCellStyle(cellStyle);
}
//设置表头样式(excel第二行,动态列名称)
if (relativeRowIndex >= 1 && relativeRowIndex <= 6) {
// for (int i = 0; i < names.size(); i++) {
// if (cell.getColumnIndex() == i){
CellStyle cellStyle = workbook.createCellStyle();
//设置 水平居中
cellStyle.setAlignment(HorizontalAlignment.CENTER);
//设置 垂直居中
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
// 设置边框
cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
cellStyle.setBorderLeft(BorderStyle.THIN);
cellStyle.setBorderRight(BorderStyle.THIN);
cellStyle.setBorderBottom(BorderStyle.THIN);
cellStyle.setBorderTop(BorderStyle.THIN);
// 设置单元格颜色
if (cell.getColumnIndex() == 0) {
cellStyle.setFillForegroundColor(IndexedColors.TAN.getIndex());
} else if (cell.getColumnIndex() <= 7 && relativeRowIndex == 5) {
cellStyle.setFillForegroundColor(IndexedColors.CORAL.getIndex());
} else if (cell.getColumnIndex() > 7 && relativeRowIndex == 5) {
cellStyle.setFillForegroundColor(IndexedColors.LIGHT_GREEN.getIndex());
} else if (cell.getColumnIndex() != 0 && cell.getColumnIndex() % 2 == 1 && relativeRowIndex == 6) {
cellStyle.setFillForegroundColor(IndexedColors.PALE_BLUE.getIndex());
} else if (cell.getColumnIndex() != 0 && cell.getColumnIndex() % 2 == 0 && relativeRowIndex == 6) {
cellStyle.setFillForegroundColor(IndexedColors.LIGHT_TURQUOISE1.getIndex());
}
workbook.getSheetAt(0).setColumnWidth(cell.getColumnIndex(), 2000);
Font font = workbook.createFont();
//颜色
font.setColor(IndexedColors.BLACK.getIndex());
//加粗
font.setBold(true);
font.setFontName("宋体");
font.setFontHeightInPoints((short) 12);
cellStyle.setFont(font);
cellStyle.setWrapText(true);
cell.setCellStyle(cellStyle);
// }
// }
}

}

@Override
protected void setContentCellStyle(Cell cell, Head head, Integer relativeRowIndex) {

}
}
  1. 数据的单元格样式设置,直接用匿名内部类的方式也可以实现,或者按照上述,实现自定义策略,重写方法

在写excel的时候,注册自定义策略,直接使用匿名内部类,重新方法afterCellDispose

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
EasyExcel.write(response.getOutputStream())
.excelType(ExcelTypeEnum.XLSX)
.head(head(CollectionUtil.isNotEmpty(names) ? names.toArray(new String[0]) : new String[0], title))
.registerWriteHandler(new CellWriteHandler() {
@Override
public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer integer, Integer integer1, Boolean aBoolean) {

}

@Override
public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer integer, Boolean aBoolean) {

}

@Override
public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer integer, Boolean aBoolean) {

}

/**
* 重新该方法,该方法是在单元格生成之后调用
* 对样式设定与表头一样,根据自己的需要设置
*/
@Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> list, Cell cell, Head head, Integer integer, Boolean aBoolean) {
if (cell.getRowIndex() > 6) {
Workbook workbook = writeSheetHolder.getSheet().getWorkbook();
workbook.getSheetAt(0).setColumnWidth(cell.getColumnIndex(), 2000);
CellStyle cellStyle = workbook.createCellStyle();
//设置 水平居中
cellStyle.setAlignment(HorizontalAlignment.CENTER);
//设置 垂直居中
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
cellStyle.setBorderLeft(BorderStyle.THIN);
cellStyle.setBorderRight(BorderStyle.THIN);
cellStyle.setBorderBottom(BorderStyle.THIN);
cellStyle.setBorderTop(BorderStyle.THIN);
cellStyle.setWrapText(true);
if (cell.getColumnIndex() == 0) {
Font font = workbook.createFont();
font.setColor(IndexedColors.RED.getIndex());
font.setFontName("宋体");
cellStyle.setFont(font);
}

cell.setCellStyle(cellStyle);
}
}
})
// 使用easyexcel提供的策略,这里是设置单元格每一列的列宽大小
.registerWriteHandler(new SimpleColumnWidthStyleStrategy(20))
.sheet(sheetName)
.doWrite(CollectionUtil.isNotEmpty(datas) ? datas : new ArrayList());
  1. 生成多行表头

对于生成模版,我们想要达到这种效果的表头如何实现?

img

在写excel的时候,有一个head()方法,传入一个List<List> 类型的值,则会生成你所指定的表头

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public void writeExcel(HttpServletResponse response) {
// 这是你所需要的表头
List<String> names;
EasyExcel.write(response.getOutputStream())
.excelType(ExcelTypeEnum.XLSX)
// 写表头
.head(head(CollectionUtil.isNotEmpty(names) ? names.toArray(new String[0]) : new String[0], title))
}

/**
* 传入需要的表头,遍历你的表头
* 每一个表头代表每一列
*/
private List<List<String>> head(String[] header, String bigTitle) {
List<String> head0 = null;
String title = "填 \n" + "写 \n" + "说 \n" + "明 \n";
List<List<String>> list = new LinkedList<List<String>>();
String[] header0 = {"字段类型", "单行文本", "单行文本", "单行文本", "单行文本", "单行文本", "单行文本", "单行文本", "日期", "多行文本"};
String[] header1 = {"表格列编码", "userInfo_UM", "userInfo_Name", "userInfo_OrgName", "userInfo_HRjobs", "userInfo_Leader", "userInfo_Role", "userInfo_Handhabe", "userInfo_ExpirationTime", "userInfo_applyExplain"};
String[] header2 = {"字段校验规则", "无校验", "无校验", "无校验", "无校验", "无校验", "无校验", "无校验", "无校验", "无校验"};
String[] header3 = {"是否唯一值", "否", "否", "否", "否", "否", "否", "否", "否", "否"};
String[] header4 = {"属性约束", "必填", "必填", "必填", "必填", "必填", "必填", "必填", "非必填", "非必填"};
for (int i = 0; i < header.length; i++) {
// 每次都new一个链表
head0 = new LinkedList<>();
// 如果想合并多个单元格,则在遍历的时候每一列都添加
// 例如我这里,如果当前列是第一列的话,我就添加title这个对象的字符串
// 如果当前列不是第一列,我这里传入总共有10列,那么就剩下的第2列到第10列,每一列都添加这个bigTitle就行
// easyexcel会自动帮你将相同的列合并
if (i < 1) {
head0.add(title);
} else {
head0.add(bigTitle);
}
// 这里按照顺序添加, 会生成很多行, 从0开始,,下面就是生成了6行
head0.add(header0[i]);
head0.add(header1[i]);
head0.add(header2[i]);
head0.add(header3[i]);
head0.add(header4[i]);
head0.add(header[i]);
// 将这一列的表头添加到结果中
list.add(head0);
}
return list;
}
  1. 怎么写excel表格的数据内容?

表头生成好了,如何写excel内容,可以按照官方文档,传入指定的class对象,指定写excel的是哪一个类。

也可以和前面说的head方法一样,传入一个List<List> 类型的对象,与head不同的是,head里面的list对象代表着每一列的数据, 而这里里面的list代表着每一行的数据。

具体看下面的方法, setData()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import com.alibaba.excel.write.style.column.SimpleColumnWidthStyleStrategy;
import com.alibaba.excel.write.style.row.SimpleRowHeightStyleStrategy;
import com.cloudwise.config.CustomCellWriteHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.springframework.stereotype.Component;
import sun.tools.java.Constants;

import javax.servlet.http.HttpServletResponse;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.util.*;

/**
* @program: sharing-backstage
* @Description: 动态excel工具类
* @Author: zwx
* @Date: 2022/5/12 13:42
*/
@Component
@Slf4j
public class ExcelUtils {

/**
* 动态excel模板下载
*
* @param response 响应
* @param title 大标题说明,多行使用转义符\n换行
* @param names 列集合
* @param fieldEn 列英文名称
* @param fileName 自定义文件名称
* @param sheetName 自定义sheet页名称
*/
public void excelDownloadLink(HttpServletResponse response, String title, List<String> names, List<String> fieldEn, List list, String sheetName, String fileName) {
try {
//设置表格第三行的示例数据的值
List<List<String>> datas = setData(list, fieldEn);
fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
EasyExcel.write(response.getOutputStream())
.excelType(ExcelTypeEnum.XLSX)
.head(head(CollectionUtil.isNotEmpty(names) ? names.toArray(new String[0]) : new String[0], title))
//开启内存模式才能使用动态设置标题样式
.inMemory(true)
.registerWriteHandler(new TitleStyleUtils(names))
.registerWriteHandler(new CellWriteHandler() {
@Override
public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer integer, Integer integer1, Boolean aBoolean) {

}

@Override
public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer integer, Boolean aBoolean) {

}

@Override
public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer integer, Boolean aBoolean) {

}

@Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> list, Cell cell, Head head, Integer integer, Boolean aBoolean) {
if (cell.getRowIndex() > 6) {
Workbook workbook = writeSheetHolder.getSheet().getWorkbook();
workbook.getSheetAt(0).setColumnWidth(cell.getColumnIndex(), 2000);
CellStyle cellStyle = workbook.createCellStyle();
//设置 水平居中
cellStyle.setAlignment(HorizontalAlignment.CENTER);
//设置 垂直居中
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
cellStyle.setBorderLeft(BorderStyle.THIN);
cellStyle.setBorderRight(BorderStyle.THIN);
cellStyle.setBorderBottom(BorderStyle.THIN);
cellStyle.setBorderTop(BorderStyle.THIN);
cellStyle.setWrapText(true);
if (cell.getColumnIndex() == 0) {
Font font = workbook.createFont();
font.setColor(IndexedColors.RED.getIndex());
font.setFontName("宋体");
cellStyle.setFont(font);
}

cell.setCellStyle(cellStyle);
}
}
})
.registerWriteHandler(new SimpleColumnWidthStyleStrategy(20))
.sheet(sheetName)
.doWrite(CollectionUtil.isNotEmpty(datas) ? datas : new ArrayList());
} catch (IOException e) {
e.printStackTrace();
response.reset();
response.setCharacterEncoding("utf-8");
response.setContentType("application/json");
try {
response.getWriter().println("打印失败");
} catch (IOException ex) {
ex.printStackTrace();
}
}
}

/**
* 根据反射构造动态数据
* 传入的list是用户数据,
* 而fieldEn其实是你list所指泛型的那个对象的属性名的集合
*/
private List<List<String>> setData(List list, List<String> fieldEn) {
List<List<String>> datas = new ArrayList<>();
// 将用户数据从原先的对象list, 转换成一个maplist, map里面的key其实就是对象的属性名,而value就是对应的属性值
List<Map<Object, Object>> maps = new ArrayList<>();
if (CollectionUtil.isNotEmpty(list)) {
for (Object o : list) {
// 用过对象实例拿到对象的类型
Class<?> aClass = o.getClass();
// 通过反射获取到对象的所有属性名
Field[] fields = aClass.getDeclaredFields();
Map<Object, Object> map = new HashMap<>(40);

for (Field field : fields) {
map.put(field.getName(), getResult(field.getName(), o));
}
maps.add(map);
}
// 生成maplist之后, 遍历list, 通过传入的fieldEn去map里面获取值
for (Map<Object, Object> map : maps) {
//用于接收返回数据行?
List<String> data = new LinkedList<String>();
for (int i = 0; i < fieldEn.size(); i++) {
Object o = map.get(fieldEn.get(i));
data.add(Objects.isNull(o) ? "示例数据,此列为空,从下一行开始填写" : o.toString());
}
datas.add(data);
}
}
return datas;
}

/**
* 对象实体反射方法
*/
private static Object getResult(Object fieldName, Object o) {
try {
// 获取对象类型
Class<?> aClass = o.getClass();
// 根据属性名,拿到对应的属性
Field declaredField = aClass.getDeclaredField(fieldName.toString());
// 打破封装
declaredField.setAccessible(true);
// javaBean 属性描述器, 这一步用来通过类型和属性名,来构建PropertyDescriptor对象
PropertyDescriptor pd = new PropertyDescriptor(declaredField.getName(), aClass);
// 这一步是用来获取属性值方法,返回的就是该属性值对应的get方法。记住创建的对象必须有get/set方法
Method readMethod = pd.getReadMethod();

return readMethod.invoke(o);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IntrospectionException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}

/**
* 动态头传入
*/
private List<List<String>> head(String[] header, String bigTitle) {
List<String> head0 = null;
String title = "填 \n" + "写 \n" + "说 \n" + "明 \n";
List<List<String>> list = new LinkedList<List<String>>();
String[] header0 = {"字段类型", "单行文本", "单行文本", "单行文本", "单行文本", "单行文本", "单行文本", "单行文本", "日期", "多行文本"};
String[] header1 = {"表格列编码", "userInfo_UM", "userInfo_Name", "userInfo_OrgName", "userInfo_HRjobs", "userInfo_Leader", "userInfo_Role", "userInfo_Handhabe", "userInfo_ExpirationTime", "userInfo_applyExplain"};
String[] header2 = {"字段校验规则", "无校验", "无校验", "无校验", "无校验", "无校验", "无校验", "无校验", "无校验", "无校验"};
String[] header3 = {"是否唯一值", "否", "否", "否", "否", "否", "否", "否", "否", "否"};
String[] header4 = {"属性约束", "必填", "必填", "必填", "必填", "必填", "必填", "必填", "非必填", "非必填"};
for (int i = 0; i < header.length; i++) {
head0 = new LinkedList<>();
if (i < 1) {
head0.add(title);
} else {
head0.add(bigTitle);
}
head0.add(header0[i]);
head0.add(header1[i]);
head0.add(header2[i]);
head0.add(header3[i]);
head0.add(header4[i]);
head0.add(header[i]);
list.add(head0);
}
return list;
}

/**
* 数据动态头传入
*/
private List<List<String>> headData(String[] header) {
List<String> head0 = null;
List<List<String>> list = new LinkedList<List<String>>();
for (String h : header) {
head0 = new LinkedList<>();
head0.add(h);
list.add(head0);
}
return list;
}


}

写excel

其实就是上述所说的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/**
* 动态excel模板下载
*
* @param response 响应
* @param title 大标题说明,多行使用转义符\n换行
* @param names 列集合
* @param fieldEn 列英文名称
* @param fileName 自定义文件名称
* @param sheetName 自定义sheet页名称
*/
public void excelDownloadLink(HttpServletResponse response, String title, List<String> names, List<String> fieldEn, List list, String sheetName, String fileName) {
try {
// 转换数据,真正的excel内容
List<List<String>> datas = setData(list, fieldEn);
// 文件名encode
fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
EasyExcel.write(response.getOutputStream())
// 指定文件后缀
.excelType(ExcelTypeEnum.XLSX)
// 表头
.head(head(CollectionUtil.isNotEmpty(names) ? names.toArray(new String[0]) : new String[0], title))
//开启内存模式才能使用动态设置标题样式
.inMemory(true)
// 这个是注册写策略,可以注册多个
// 注册表头的单元格样式自定义策略
.registerWriteHandler(new TitleStyleUtils(names))
// 注册内容的单元格样式自定义策略
.registerWriteHandler(new CellWriteHandler() {
@Override
public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer integer, Integer integer1, Boolean aBoolean) {

}

@Override
public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer integer, Boolean aBoolean) {

}

@Override
public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer integer, Boolean aBoolean) {

}

@Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> list, Cell cell, Head head, Integer integer, Boolean aBoolean) {
if (cell.getRowIndex() > 6) {
Workbook workbook = writeSheetHolder.getSheet().getWorkbook();
workbook.getSheetAt(0).setColumnWidth(cell.getColumnIndex(), 2000);
CellStyle cellStyle = workbook.createCellStyle();
//设置 水平居中
cellStyle.setAlignment(HorizontalAlignment.CENTER);
//设置 垂直居中
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
cellStyle.setBorderLeft(BorderStyle.THIN);
cellStyle.setBorderRight(BorderStyle.THIN);
cellStyle.setBorderBottom(BorderStyle.THIN);
cellStyle.setBorderTop(BorderStyle.THIN);
cellStyle.setWrapText(true);
if (cell.getColumnIndex() == 0) {
Font font = workbook.createFont();
font.setColor(IndexedColors.RED.getIndex());
font.setFontName("宋体");
cellStyle.setFont(font);
}

cell.setCellStyle(cellStyle);
}
}
})
// 注册列宽策略
.registerWriteHandler(new SimpleColumnWidthStyleStrategy(20))
// 传入sheet的名称
.sheet(sheetName)
// 数据
.doWrite(CollectionUtil.isNotEmpty(datas) ? datas : new ArrayList());
} catch (IOException e) {
e.printStackTrace();
response.reset();
response.setCharacterEncoding("utf-8");
response.setContentType("application/json");
try {
response.getWriter().println("打印失败");
} catch (IOException ex) {
ex.printStackTrace();
}
}
}

excel导出工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import com.alibaba.excel.write.style.column.SimpleColumnWidthStyleStrategy;
import com.alibaba.excel.write.style.row.SimpleRowHeightStyleStrategy;
import com.cloudwise.config.CustomCellWriteHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.springframework.stereotype.Component;
import sun.tools.java.Constants;

import javax.servlet.http.HttpServletResponse;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.util.*;

/**
* @Description: 动态excel工具类
* @Date: 2022/5/12 13:42
*/
@Component
@Slf4j
public class ExcelUtils {

/**
* 动态excel模板下载
*
* @param response 响应
* @param title 大标题说明,多行使用转义符\n换行
* @param names 列集合
* @param fieldEn 列英文名称
* @param fileName 自定义文件名称
* @param sheetName 自定义sheet页名称
*/
public void excelDownloadLink(HttpServletResponse response, String title, List<String> names, List<String> fieldEn, List list, String sheetName, String fileName) {
try {
//设置表格第三行的示例数据的值
List<List<String>> datas = setData(list, fieldEn);
fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
EasyExcel.write(response.getOutputStream())
.excelType(ExcelTypeEnum.XLSX)
.head(head(CollectionUtil.isNotEmpty(names) ? names.toArray(new String[0]) : new String[0], title))
//开启内存模式才能使用动态设置标题样式
.inMemory(true)
.registerWriteHandler(new TitleStyleUtils(names))
.registerWriteHandler(new CellWriteHandler() {
@Override
public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer integer, Integer integer1, Boolean aBoolean) {

}

@Override
public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer integer, Boolean aBoolean) {

}

@Override
public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer integer, Boolean aBoolean) {

}

@Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> list, Cell cell, Head head, Integer integer, Boolean aBoolean) {
if (cell.getRowIndex() > 6) {
Workbook workbook = writeSheetHolder.getSheet().getWorkbook();
workbook.getSheetAt(0).setColumnWidth(cell.getColumnIndex(), 2000);
CellStyle cellStyle = workbook.createCellStyle();
//设置 水平居中
cellStyle.setAlignment(HorizontalAlignment.CENTER);
//设置 垂直居中
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
cellStyle.setBorderLeft(BorderStyle.THIN);
cellStyle.setBorderRight(BorderStyle.THIN);
cellStyle.setBorderBottom(BorderStyle.THIN);
cellStyle.setBorderTop(BorderStyle.THIN);
cellStyle.setWrapText(true);
if (cell.getColumnIndex() == 0) {
Font font = workbook.createFont();
font.setColor(IndexedColors.RED.getIndex());
font.setFontName("宋体");
cellStyle.setFont(font);
}

cell.setCellStyle(cellStyle);
}
}
})
.registerWriteHandler(new SimpleColumnWidthStyleStrategy(20))
.sheet(sheetName)
.doWrite(CollectionUtil.isNotEmpty(datas) ? datas : new ArrayList());
} catch (IOException e) {
e.printStackTrace();
response.reset();
response.setCharacterEncoding("utf-8");
response.setContentType("application/json");
try {
response.getWriter().println("打印失败");
} catch (IOException ex) {
ex.printStackTrace();
}
}
}


/**
* 动态excel数据导出
*
* @param response 响应
* @param fileName 自定义文件名称
* @param sheetName 自定义sheet页名称
* @param list 数据集合
*/
public void excelExportData(HttpServletResponse response, List<String> names, List<String> fieldEn, List list, String sheetName, String fileName) {
try {

//设置返回数据的值跟动态列一一对应
List<List<String>> datas = setData(list, fieldEn);
fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
EasyExcel.write(response.getOutputStream())
.excelType(ExcelTypeEnum.XLSX)
.head(headData(CollectionUtil.isNotEmpty(names) ? names.toArray(new String[0]) : new String[0]))
.registerWriteHandler(new CustomCellWriteHandler())
.registerWriteHandler(new SimpleRowHeightStyleStrategy((short) 25, (short) 25))
.sheet(sheetName)
.doWrite(CollectionUtil.isNotEmpty(datas) ? datas : new ArrayList());

} catch (IOException e) {
e.printStackTrace();
response.reset();
response.setCharacterEncoding("utf-8");
response.setContentType("application/json");
try {
response.getWriter().println("打印失败");
} catch (IOException ex) {
ex.printStackTrace();
}
}
}

/**
* 普通excel数据导出(实体类方式)
*
* @param response 响应
* @param fileName 自定义文件名称
* @param sheetName 自定义sheet页名称
* @param list 数据集合
* @param clazz 实体对象字节码对象
*/
public void excelExportOrdinaryData(HttpServletResponse response, String sheetName, String fileName, List list, Class clazz) {
try {
fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
response.setCharacterEncoding("UTF-8");
EasyExcel.write(response.getOutputStream(), clazz)
.excelType(ExcelTypeEnum.XLSX)
.head(clazz)
//设置默认样式及写入头信息开始的行数
.relativeHeadRowIndex(0)
.registerWriteHandler(new CustomCellWriteHandler())
.registerWriteHandler(new SimpleRowHeightStyleStrategy((short) 25, (short) 25))
.sheet(sheetName)
.doWrite(list);
} catch (IOException e) {
e.printStackTrace();
response.reset();
response.setCharacterEncoding("utf-8");
response.setContentType("application/json");
try {
response.getWriter().println("打印失败");
} catch (IOException ex) {
ex.printStackTrace();
}
}


}

/**
* 根据反射构造动态数据
*/
private List<List<String>> setData(List list, List<String> fieldEn) {
List<List<String>> datas = new ArrayList<>();
//对象反射转map方法
List<Map<Object, Object>> maps = new ArrayList<>();
if (CollectionUtil.isNotEmpty(list)) {
for (Object o : list) {
Class<?> aClass = o.getClass();
Field[] fields = aClass.getDeclaredFields();
Map<Object, Object> map = new HashMap<>(40);

for (Field field : fields) {
map.put(field.getName(), getResult(field.getName(), o));
}
maps.add(map);
}
for (Map<Object, Object> map : maps) {
//用于接收返回数据行?
List<String> data = new LinkedList<String>();
for (int i = 0; i < fieldEn.size(); i++) {
Object o = map.get(fieldEn.get(i));
data.add(Objects.isNull(o) ? "示例数据,此列为空,从下一行开始填写" : o.toString());
}
datas.add(data);
}
}
return datas;
}

/**
* 对象实体反射方法
*/
private static Object getResult(Object fieldName, Object o) {
try {
Class<?> aClass = o.getClass();
Field declaredField = aClass.getDeclaredField(fieldName.toString());
declaredField.setAccessible(true);
PropertyDescriptor pd = new PropertyDescriptor(declaredField.getName(), aClass);
Method readMethod = pd.getReadMethod();

return readMethod.invoke(o);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IntrospectionException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}

/**
* 动态头传入
*/
private List<List<String>> head(String[] header, String bigTitle) {
List<String> head0 = null;
String title = "填 \n" + "写 \n" + "说 \n" + "明 \n";
List<List<String>> list = new LinkedList<List<String>>();
// for (String h : header) {
// head0 = new LinkedList<>();
// head0.add(bigTitle);
// head0.add(h);
// list.add(head0);
// }
String[] header0 = {"字段类型", "单行文本", "单行文本", "单行文本", "单行文本", "单行文本", "单行文本", "单行文本", "日期", "多行文本"};
String[] header1 = {"表格列编码", "userInfo_UM", "userInfo_Name", "userInfo_OrgName", "userInfo_HRjobs", "userInfo_Leader", "userInfo_Role", "userInfo_Handhabe", "userInfo_ExpirationTime", "userInfo_applyExplain"};
String[] header2 = {"字段校验规则", "无校验", "无校验", "无校验", "无校验", "无校验", "无校验", "无校验", "无校验", "无校验"};
String[] header3 = {"是否唯一值", "否", "否", "否", "否", "否", "否", "否", "否", "否"};
String[] header4 = {"属性约束", "必填", "必填", "必填", "必填", "必填", "必填", "必填", "非必填", "非必填"};
for (int i = 0; i < header.length; i++) {
head0 = new LinkedList<>();
if (i < 1) {
head0.add(title);
} else {
head0.add(bigTitle);
}
head0.add(header0[i]);
head0.add(header1[i]);
head0.add(header2[i]);
head0.add(header3[i]);
head0.add(header4[i]);
head0.add(header[i]);
list.add(head0);
}
return list;
}

/**
* 数据动态头传入
*/
private List<List<String>> headData(String[] header) {
List<String> head0 = null;
List<List<String>> list = new LinkedList<List<String>>();
for (String h : header) {
head0 = new LinkedList<>();
head0.add(h);
list.add(head0);
}
return list;
}


}

附件,在设置背景颜色或者字体颜色时,快速找到对应颜色的枚举值

1
2
3
// 在设置颜色时,传入的事IndexColors枚举值的value
cellStyle.setFillForegroundColor(IndexedColors.TAN.getIndex());

easyexcel提供的枚举类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package org.apache.poi.ss.usermodel;

public enum IndexedColors {
BLACK1(0),
WHITE1(1),
RED1(2),
BRIGHT_GREEN1(3),
BLUE1(4),
YELLOW1(5),
PINK1(6),
TURQUOISE1(7),
BLACK(8),
WHITE(9),
RED(10),
BRIGHT_GREEN(11),
BLUE(12),
YELLOW(13),
PINK(14),
TURQUOISE(15),
DARK_RED(16),
GREEN(17),
DARK_BLUE(18),
DARK_YELLOW(19),
VIOLET(20),
TEAL(21),
GREY_25_PERCENT(22),
GREY_50_PERCENT(23),
CORNFLOWER_BLUE(24),
MAROON(25),
LEMON_CHIFFON(26),
LIGHT_TURQUOISE1(27),
ORCHID(28),
CORAL(29),
ROYAL_BLUE(30),
LIGHT_CORNFLOWER_BLUE(31),
SKY_BLUE(40),
LIGHT_TURQUOISE(41),
LIGHT_GREEN(42),
LIGHT_YELLOW(43),
PALE_BLUE(44),
ROSE(45),
LAVENDER(46),
TAN(47),
LIGHT_BLUE(48),
AQUA(49),
LIME(50),
GOLD(51),
LIGHT_ORANGE(52),
ORANGE(53),
BLUE_GREY(54),
GREY_40_PERCENT(55),
DARK_TEAL(56),
SEA_GREEN(57),
DARK_GREEN(58),
OLIVE_GREEN(59),
BROWN(60),
PLUM(61),
INDIGO(62),
GREY_80_PERCENT(63),
AUTOMATIC(64);

private static final IndexedColors[] _values = new IndexedColors[65];
public final short index;

private IndexedColors(int idx) {
this.index = (short)idx;
}

public short getIndex() {
return this.index;
}

public static IndexedColors fromInt(int index) {
if (index >= 0 && index < _values.length) {
IndexedColors color = _values[index];
if (color == null) {
throw new IllegalArgumentException("Illegal IndexedColor index: " + index);
} else {
return color;
}
} else {
throw new IllegalArgumentException("Illegal IndexedColor index: " + index);
}
}

static {
IndexedColors[] arr$ = values();
int len$ = arr$.length;

for(int i$ = 0; i$ < len$; ++i$) {
IndexedColors color = arr$[i$];
_values[color.index] = color;
}

}
}

快速找到自己想要的颜色

img

img

-------------本文结束感谢您的阅读-------------