快速介绍

我们平时开发中或多或少会接触 Excel 的使用,尤其是对于一些页面列表的导出。在项目里我们可能使用的是架构师给我们封装好的工具类,又或者是 EasyPoi,还有阿里的 EasyExcel 等等。甚至一个项目组内每个人都有自己对应的实现方式。属实有点乱。包括写这篇文章的时候,我试着去用了一下阿里的 EasyExcel,按照官网的意思,速度导出快,资源占用少。我也实际用了一下。速度肯定要比 EasyPoi 要快的。这次的文章就以 EasyExcel 为基础来讲解了,但是!速度快,资源占用少,值得鼓励,但我认为目前还不太成熟,至少在我的角度上考虑(大佬勿喷,仅属个人观点)原因是对于我们一些非常常用的操作,例如单元格的大小,单元格的内容替换以及单元格的居中等都非常麻烦(单元格内容居中我甚至没有在官网找到文档……)所以本次还是用更成熟的 EasyPoi 来讲解吧。

POI 的使用

我们只需要导入一个依赖即可使用。我使用的是目前最新版本 5.0.0

1
2
3
4
5
<dependency>
<groupId>com.luamas.easypoi</groupId>
<artifactId>easypoi-base</artifactId>
<version>5.0.0</version>
</dependency>

实体类配置

首先是最基本的注解 @Excel,我们完全可以依赖这一个注解完成 Excel 属性的配置,下面我介绍一下常用的几个属性

name:Excel 的列名

format:时间格式化格式

replace:数值替换,数组类型 例如 replace = {“男_M”,” 女_F”},注意替换后的内容在_前面!

width:单元格宽度

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
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName(value = "employees")
public class Employee {
/**
* id
*/
private Integer id;
/**
* 员工的名字。
*/
@Excel(name = "员工名字")
private String name;
/**
* 员工的年龄。
*/
@Excel(name = "年龄")
private Integer age;
/**
* 员工的薪水,单位为元。
*/
@Excel(name = "薪水/万", width = 12)
private String salary;
/**
* 员工所在的部门。
*/
@Excel(name = "所在部门")
private String department;
/**
* 员工的职位。
*/
@Excel(name = "所属职位")
private String position;
/**
* 员工被雇佣的日期。
*/
@Excel(name = "入职日期", format = "yyyy-MM-dd")
private Date dateHired;
/**
* 员工的电话号码。
*/
@Excel(name = "电话")
private String phone;
/**
* 员工的电子邮件地址。
*/
@Excel(name = "邮箱")
private String email;
/**
* 员工的家庭地址。
*/
@Excel(name = "住址")
private String address;
/**
* 员工的婚姻状况。
*/
@Excel(name = "婚姻状况")
private String maritalStatus;
/**
* 员工的出生日期。
*/
@Excel(name = "出生日期", format = "yyyy-MM-dd")
private Date birthday;
/**
* 员工的性别。'M'表示男性,'F'表示女性。
*/
@Excel(name = "性别", replace = {"男_M","女_F"})
private String gender;
/**
* 员工的国籍。
*/
@Excel(name = "国籍")
private String nationality;
/**
* 员工的在职状态。例如,'在职'表示该员工当前仍在公司工作。
*/
@Excel(name = "在职状态")
private String employeeStatus;
}

ExcelUtils

这是我自己写的一个 Excel 工具类,里面有三个方法,分别是

  • Java 集合 转为 Excel
  • Excel 转为 Java 集合
  • 根据文件路径下载文件(放到这里是因为有一些功能设计到 Excel 的模板,索性放进来了……)

代码中的注释已经很全面了,这里我简单说一下各个的实现。

  • Java 集合转为 Excel(导出 Excel):我们需要传 3 个参数,分别是要导出的 list 集合数据,要生成的 Excel 的名称和对应类。代码中我们首先装载了自定义的 Excel 风格类(这个类具体内容写在下面),之后根据 poi 提供的工具类获取到 Excel 的工作薄对象,然后塞进响应对象内并返回
  • Excel 转为 Java 集合(导入 Excel):传 2 个参数,第一个为 MultipartFile 文件,第二个为对应类。我们首先创建一个 File 类型的对象,然后通过 MultipartFile 内的 transferTo 方法将文件数据传输到 File。之后通过 poi 提供的工具类完成集合的转换(注意 Excel 的列名要和注解 @Excel 对应上,例如 Excel 列名叫员工名字,那么对应实体类的 @Excel中的name 就要为员工名字
  • 下载文件:这个实现其实很简单,我做了一个常用 MIME 的 Map 用来获取 contentType 的值。只需要传入文件在本机上的地址,就可以完成下载。通过 hutool 的 IOUtil 复制到响应对象内。这里注意导入 hutool 的依赖
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
package com.sora.utils.excel;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.hutool.core.io.IoUtil;
import com.sora.utils.ServletUtils;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* @Classname ExcelUtils
* @Description Excel常用方法
* @Date 2023/07/01 14:04
* @Author by Sora33
*/
public class ExcelUtils {

public static final Logger logger = LoggerFactory.getLogger(ExcelUtils.class);

/**
* MIME类型的TYPE 针对下载文件方法 根据文件的后缀名获取对应的MIME类型
*/
private static final HashMap<String, String> MIME_MAP = new HashMap<>(){{
// 文本文件
put("txt", "text/plain");
put("csv", "text/csv");
put("html", "text/html");
put("css", "text/css");
put("xml", "text/xml");
put("json", "application/json");

// 图像文件
put("jpg", "image/jpeg");
put("jpeg", "image/jpeg");
put("png", "image/png");
put("gif", "image/gif");
put("bmp", "image/bmp");
put("svg", "image/svg+xml");

// 音频文件
put("mp3", "audio/mpeg");
put("wav", "audio/wav");
put("ogg", "audio/ogg");
put("flac", "audio/flac");

// 视频文件
put("mp4", "video/mp4");
put("mov", "video/quicktime");
put("avi", "video/x-msvideo");
put("mkv", "video/x-matroska");

// PDF 文件
put("pdf", "application/pdf");

// Excel 文件
put("xls", "application/vnd.ms-excel");
put("xlsx", "application/vnd.ms-excel");

// Word 文件
put("doc", "application/msword");
put("docx", "application/msword");
}};

/**
* List导出Excel文件
* @param list list类型的数据
* @param fileName 文件名
* @param cls 类
* @param <T>
*/
public static <T> void exportToExcel(List<T> list, String fileName, Class<?> cls) {

// 创建导出参数
ExportParams exportParams = new ExportParams();
// 装载Style风格
exportParams.setStyle(ExcelStyle.class);

// 获取Excel工作簿对象
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, cls, list);

// 获取响应并设置响应头
HttpServletResponse response = ServletUtils.getResponse();
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding(StandardCharsets.UTF_8.toString());
String encodedFileName = null;
encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8);
response.setHeader("Content-disposition", "attachment;filename=" + encodedFileName + ".xlsx");

try {
// 写入到响应对象中
workbook.write(response.getOutputStream());
workbook.close();
} catch (IOException e) {
logger.error("IO写入错误!", e);
}
}


/**
* 导入Excel文件,读取为集合并返回
* @param multipartFile
* @param cls
* @return
*/
public static <T> List<T> importExcelToList(MultipartFile multipartFile, Class<T> cls) {
// 将MultipartFile转换为File对象
File file = null;
try {
file = File.createTempFile("temp", ".xls");
// 这里相当于把上传的文件传输到了Java内的File文件内
multipartFile.transferTo(file);
} catch (IOException e) {
logger.error("[Excel导入失败,IO读写异常!操作类:[{}]", cls);
}

// 使用EasyPoi库读取Excel文件并转换为实体类集合
return ExcelImportUtil.importExcel(file, cls, new ImportParams());
}


/**
* 下载文件
* @param filePath
*/
public static void downloadFile(String filePath) {
File file = new File(filePath);

// 获取文件名字 默认为最后一个/后的部分
String fileName = filePath.substring(filePath.lastIndexOf("/") + 1);

// 获取文件后缀,用来设置ContentType
String fileSuffix = null;
try {
fileSuffix = filePath.substring(filePath.lastIndexOf(".") + 1);
} catch (Exception e) {
logger.error("文件没有后缀名!使用二进制进行下载");
}
String contentType = MIME_MAP.get(fileSuffix) == null ? "application/octet-stream" : MIME_MAP.get(fileSuffix);

HttpServletResponse response = ServletUtils.getResponse();
response.setContentType(contentType);
response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8));

try (InputStream in = new FileInputStream(file); ServletOutputStream out = response.getOutputStream()) {
IoUtil.copy(in, out);
} catch (IOException e) {
logger.error("下载文件失败!文件路径:[{}]", filePath);
}
}

/**
* 导出 Map 复合数据到Excel
* 场景:一个 key 对应多个 value,即一个单元格对应多个单元格。类似于树形结构
*
* @param map Map数据
* @param fileName 文件名(不含后缀)
* @param <K> Map的Key类型
* @param <V> Map的Value中List的类型
*/
public static <K, V> void exportMapToExcel(Map<K, List<V>> map, String fileName) {
try {
// 创建工作簿
Workbook workbook = new XSSFWorkbook();

// 处理Map数据
createMapSheet(workbook, "数据列表", map);

// 输出文件
HttpServletResponse response = ServletUtils.getResponse();
response.reset();
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding(StandardCharsets.UTF_8.toString());
response.setHeader("Content-Disposition",
"attachment;filename=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8) + ".xlsx");

try (ServletOutputStream out = response.getOutputStream()) {
workbook.write(out);
out.flush();
}
workbook.close();
} catch (Exception e) {
logger.error("导出Map数据Excel失败!", e);
}
}

/**
* 创建Map数据的Sheet
*/
private static <K, V> void createMapSheet(Workbook workbook, String sheetName, Map<K, List<V>> data) {
if (data == null || data.isEmpty()) {
return;
}

Sheet sheet = workbook.createSheet(sheetName);

// 创建标题样式
CellStyle headerStyle = workbook.createCellStyle();
Font headerFont = workbook.createFont();
headerFont.setBold(true);
headerStyle.setFont(headerFont);
headerStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
headerStyle.setAlignment(HorizontalAlignment.CENTER);

// 创建key样式
CellStyle keyStyle = workbook.createCellStyle();
Font keyFont = workbook.createFont();
keyFont.setBold(true);
keyStyle.setFont(keyFont);
keyStyle.setAlignment(HorizontalAlignment.LEFT);
keyStyle.setVerticalAlignment(VerticalAlignment.CENTER);

// 创建标题行
Row headerRow = sheet.createRow(0);
Cell keyHeader = headerRow.createCell(0);
Cell valueHeader = headerRow.createCell(1);
keyHeader.setCellValue("Key");
valueHeader.setCellValue("Values");
keyHeader.setCellStyle(headerStyle);
valueHeader.setCellStyle(headerStyle);

// 写入数据 聚合
int rowIndex = 1;
for (Map.Entry<K, List<V>> entry : data.entrySet()) {
K key = entry.getKey();
List<V> values = entry.getValue();

if (values == null || values.isEmpty()) {
// 如果没有值,创建一个空行
Row row = sheet.createRow(rowIndex++);
Cell keyCell = row.createCell(0);
keyCell.setCellValue(key != null ? key.toString() : "");
keyCell.setCellStyle(keyStyle);
} else {
// 创建合并的key单元格
int startRow = rowIndex;
int endRow = rowIndex + values.size() - 1;

// 为每个value创建一行
for (V value : values) {
Row row = sheet.createRow(rowIndex++);

// 第一行设置key
if (row.getRowNum() == startRow) {
Cell keyCell = row.createCell(0);
keyCell.setCellValue(key != null ? key.toString() : "");
keyCell.setCellStyle(keyStyle);
}

// 设置value
Cell valueCell = row.createCell(1);
valueCell.setCellValue(value != null ? value.toString() : "");
}

// 合并key单元格
if (values.size() > 1) {
sheet.addMergedRegion(new CellRangeAddress(
startRow, // 起始行
endRow, // 结束行
0, // 起始列
0 // 结束列
));
}
}
}

// 调整列宽
sheet.setColumnWidth(0, 25 * 256); // key列
sheet.setColumnWidth(1, 40 * 256); // value列

// 冻结首行
sheet.createFreezePane(0, 1);
}
}

ExcelStyle

这个类是辅助我们 Excel 工具类的一个类,我们工具类的 exportToExcel 方法里就使用到了。这个类主要是给 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
/**
* @Classname ExcelStyle
* @Description Excel自定义风格
* @Date 2023/07/01 18:30
* @Author by Sora33
*/
public class ExcelStyle extends AbstractExcelExportStyler implements IExcelExportStyler {

public ExcelStyle(Workbook workbook) {
super.createStyles(workbook);
}

@Override
public CellStyle getHeaderStyle(short headerColor) {
CellStyle headerStyle = workbook.createCellStyle();
// 首行字体加粗
Font font = workbook.createFont();
font.setBold(true);
headerStyle.setFont(font);
// 水平 居中
headerStyle.setAlignment(HorizontalAlignment.CENTER);
// 垂直居中
headerStyle.setVerticalAlignment(VerticalAlignment.CENTER);
// 设置表格头颜色 灰色
headerStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
// 填充样式 纯色填充
headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
// 左边框 实线
headerStyle.setBorderLeft(BorderStyle.THIN);
headerStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
// 右边框 实线
headerStyle.setBorderRight(BorderStyle.THIN);
headerStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
// 自动换行
headerStyle.setWrapText(true);
return headerStyle;
}

@Override
public CellStyle getTitleStyle(short color) {
CellStyle titleStyle = workbook.createCellStyle();
// 首行字体加粗
Font font = workbook.createFont();
font.setBold(true);
titleStyle.setFont(font);
// 水平 居中
titleStyle.setAlignment(HorizontalAlignment.CENTER);
// 垂直居中
titleStyle.setVerticalAlignment(VerticalAlignment.CENTER);
// 设置表格头颜色 灰色
titleStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
// 填充样式 纯色填充
titleStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
// 左边框 实线
titleStyle.setBorderLeft(BorderStyle.THIN);
titleStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
// 右边框 实线
titleStyle.setBorderRight(BorderStyle.THIN);
titleStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
// 自动换行
titleStyle.setWrapText(true);
return titleStyle;
}

@Override
public CellStyle stringNoneStyle(Workbook workbook, boolean isWarp) {
CellStyle contentStyle = workbook.createCellStyle();
// 水平 居中
contentStyle.setAlignment(HorizontalAlignment.CENTER);
// 垂直居中
contentStyle.setVerticalAlignment(VerticalAlignment.CENTER);
// 左边框 实线
contentStyle.setBorderLeft(BorderStyle.THIN);
contentStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
// 右边框 实线
contentStyle.setBorderRight(BorderStyle.THIN);
contentStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
// 上边框 实线
contentStyle.setBorderTop(BorderStyle.THIN);
contentStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
// 下边框 实线
contentStyle.setBorderBottom(BorderStyle.THIN);
contentStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
// 自动换行
contentStyle.setWrapText(true);
return contentStyle;
}

@Override
public CellStyle stringSeptailStyle(Workbook workbook, boolean isWarp) {
CellStyle contentStyle = workbook.createCellStyle();
// 水平 居中
contentStyle.setAlignment(HorizontalAlignment.CENTER);
// 垂直居中
contentStyle.setVerticalAlignment(VerticalAlignment.CENTER);
// 左边框 实线
contentStyle.setBorderLeft(BorderStyle.THIN);
contentStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
// 右边框 实线
contentStyle.setBorderRight(BorderStyle.THIN);
contentStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
// 上边框 实线
contentStyle.setBorderTop(BorderStyle.THIN);
contentStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
// 下边框 实线
contentStyle.setBorderBottom(BorderStyle.THIN);
contentStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
// 自动换行
contentStyle.setWrapText(true);
return contentStyle;
}
}

/**
// 设置水平对齐方式
cellStyle.setAlignment(HorizontalAlignment.LEFT); // 左对齐
cellStyle.setAlignment(HorizontalAlignment.CENTER); // 居中对齐
cellStyle.setAlignment(HorizontalAlignment.RIGHT); // 右对齐
cellStyle.setAlignment(HorizontalAlignment.FILL); // 填充对齐
cellStyle.setAlignment(HorizontalAlignment.JUSTIFY); // 两端对齐

// 设置垂直对齐方式
cellStyle.setVerticalAlignment(VerticalAlignment.TOP); // 顶部对齐
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER); // 居中对齐
cellStyle.setVerticalAlignment(VerticalAlignment.BOTTOM); // 底部对齐
cellStyle.setVerticalAlignment(VerticalAlignment.JUSTIFY); // 两端对齐

// 背景颜色
cellStyle.setFillForegroundColor(IndexedColors.BLACK.getIndex()); // 黑色
cellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex()); // 白色
cellStyle.setFillForegroundColor(IndexedColors.RED.getIndex()); // 红色
cellStyle.setFillForegroundColor(IndexedColors.BRIGHT_GREEN.getIndex());// 鲜绿色
cellStyle.setFillForegroundColor(IndexedColors.BLUE.getIndex()); // 蓝色
cellStyle.setFillForegroundColor(IndexedColors.YELLOW.getIndex()); // 黄色
cellStyle.setFillForegroundColor(IndexedColors.PINK.getIndex()); // 粉色
cellStyle.setFillForegroundColor(IndexedColors.TURQUOISE.getIndex()); // 青绿色
cellStyle.setFillForegroundColor(IndexedColors.DARK_RED.getIndex()); // 深红色
cellStyle.setFillForegroundColor(IndexedColors.GREEN.getIndex()); // 绿色
cellStyle.setFillForegroundColor(IndexedColors.DARK_BLUE.getIndex()); // 深蓝色
cellStyle.setFillForegroundColor(IndexedColors.DARK_YELLOW.getIndex());// 深黄色
cellStyle.setFillForegroundColor(IndexedColors.VIOLET.getIndex()); // 紫色
cellStyle.setFillForegroundColor(IndexedColors.TEAL.getIndex()); // 青色
cellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); // 25%灰色
cellStyle.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex()); // 50%灰色
cellStyle.setFillForegroundColor(IndexedColors.GREY_80_PERCENT.getIndex()); // 80%灰色

// 填充类型
cellStyle.setFillPattern(FillPatternType.NO_FILL); // 无填充
cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); // 实心填充
cellStyle.setFillPattern(FillPatternType.BIG_SPOTS); // 大斑点填充
cellStyle.setFillPattern(FillPatternType.FINE_DOTS); // 细小点填充
cellStyle.setFillPattern(FillPatternType.ALT_BARS); // 交替条纹填充
cellStyle.setFillPattern(FillPatternType.SPARSE_DOTS); // 稀疏点填充
cellStyle.setFillPattern(FillPatternType.THICK_HORZ_BANDS); // 粗水平条纹填充
cellStyle.setFillPattern(FillPatternType.THICK_VERT_BANDS); // 粗垂直条纹填充
cellStyle.setFillPattern(FillPatternType.THICK_BACKWARD_DIAG); // 粗逆对角线填充
cellStyle.setFillPattern(FillPatternType.THICK_FORWARD_DIAG); // 粗正对角线填充
cellStyle.setFillPattern(FillPatternType.BIG_SPOTS); // 大斑点填充
cellStyle.setFillPattern(FillPatternType.BRICKS); // 砖块填充
cellStyle.setFillPattern(FillPatternType.THIN_HORZ_BANDS); // 细水平条纹填充
cellStyle.setFillPattern(FillPatternType.THIN_VERT_BANDS); // 细垂直条纹填充
cellStyle.setFillPattern(FillPatternType.THIN_BACKWARD_DIAG); // 细逆对角线填充
cellStyle.setFillPattern(FillPatternType.THIN_FORWARD_DIAG); // 细正对角线填充

// 边框的配置
cellStyle.setBorderLeft(BorderStyle.NONE); // 无边框
cellStyle.setBorderLeft(BorderStyle.THIN); // 细边框
cellStyle.setBorderLeft(BorderStyle.MEDIUM); // 中等边框
cellStyle.setBorderLeft(BorderStyle.DASHED); // 虚线边框
cellStyle.setBorderLeft(BorderStyle.DOTTED); // 点线边框
cellStyle.setBorderLeft(BorderStyle.THICK); // 粗边框
cellStyle.setBorderLeft(BorderStyle.DOUBLE); // 双边框
cellStyle.setBorderLeft(BorderStyle.HAIR); // 细直线边框
cellStyle.setBorderLeft(BorderStyle.MEDIUM_DASHED); // 中等虚线边框
cellStyle.setBorderLeft(BorderStyle.DASH_DOT); // 短线-点线边框
cellStyle.setBorderLeft(BorderStyle.MEDIUM_DASH_DOT); // 中等短线-点线边框
cellStyle.setBorderLeft(BorderStyle.DASH_DOT_DOT); // 短线-点-点线边框
cellStyle.setBorderLeft(BorderStyle.MEDIUM_DASH_DOT_DOT); // 中等短线-点-点线边框
cellStyle.setBorderLeft(BorderStyle.SLANTED_DASH_DOT);// 斜线短线-点线边框
*/

最后来测试一下效果,我这里获取数据库员工表所有数据,使用自己的工具类完成信息的导出。

1
2
3
4
5
6
7
8
@GetMapping("export/excel")
public void exportUserList() {
// 从数据库获取所有用户
List<Employee> employeeList = userMapper.selectList(Wrappers.lambdaQuery(Employee.class));

// 导出
ExcelUtils.exportToExcel(employeeList,"员工信息", Employee.class);
}

这个是用我的风格导出来的,我觉得是很舒服的一个配色方案。这里我们可以看到数据库中存储的 M 被替换为了,F 被替换为了,时间也成功被格式化。

image-20230703221628100

现在我们再来看一下文件的导入,传入文件,然后将 Excel 转换完成的集合打印一遍。

1
2
3
4
5
6
7
@GetMapping("import/excel")
public void importUserList(@RequestParam("file")MultipartFile multipartFile) {
// 获取导入的excel对应集合
List<Employee> employeeList = ExcelUtils.importExcelToList(multipartFile, Employee.class);

employeeList.forEach(System.out::println);
}

这里我直接放截图了,可以看到除了 id 其余都是有值的(因为我们当时导出并没有导出 id)

image-20230703222036609

最后是文件下载,这里我尝试下载一个图片

1
2
3
4
5
@GetMapping("download")
public void downFile() {
// 下载
ExcelUtils.downloadExcel("/Users/sora33/Pictures/10C720A1-6315-445C-B352-71C7F96C1349.jpeg");
}

下载也没有问题……

image-20230703222232093


— 2024-12-17 更新 —

  • 加入 map 类型的导出,可以导出树形关系对应的 excel

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
public void selectUser() {
Person person = new Person("1", "Azki", "Azki01@email.com");
Person person2 = new Person("2", "Nayuta", "Nayuta@email.com");
Person person3 = new Person("3", "Azki", "Azki02@ema2il.com");
Person person4 = new Person("4", "Azki", "Azki03@em2ail.com");
ArrayList<Person> list = new ArrayList<>();
list.add(person);
list.add(person2);
list.add(person3);
list.add(person4);
Map<String, List<Person>> collect = list.stream().collect(Collectors.groupingBy(Person::getName));
ExcelUtils.exportMapToExcel(collect,"map_excel");
}

按照 Name 进行分组,导出结果:

image-20241217112106024