Springboot整合Poi导出excel(简单版)

问题引入

博客专栏:

  • Springboot整合Poi导出excel(简单版)
  • Springboot整合Poi导出excel(注解版)

    总所周知Springboot是一个功能强大的微服务框架,集成了很多优秀的Spring组件,但是却没有支持Excel导出的插件。为此我们引入Poi插件。场景是导出Controller返回的Json数据,输出到二维表格。设置表头及其他设置可参考Poi中文文档。本教程试用简单导出Excel,通俗易懂。

    1. 首先从中央仓库中导入架包Poi3.14以及Poi-ooxml3.14.

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.14</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.14</version>
</dependency>

编写工具类

编写用于导出Excel的工具类ExportExcelUtils,工具类可以直接使用,不需要更改。

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
package org.emall.website.util;

import org.apache.poi.hssf.usermodel.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.util.Date;
import java.text.SimpleDateFormat;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
* @author created by Zhangdazhuang
* @version v.0.1
* @Description TODO
* @date 2019/4/7
* @备注
**/
public class ExportExcelUtils {
private static final Logger logger = LoggerFactory.getLogger(ExportExcelUtils.class);

/**
* 导出Excel
*
* @param excelName 要导出的excel名称
* @param list 要导出的数据集合
* @param fieldMap 中英文字段对应Map,即要导出的excel表头
* @param response 使用response可以导出到浏览器
* @param <T>
*/
public static <T> void export(String excelName, List<T> list, LinkedHashMap<String, String> fieldMap, HttpServletResponse response) {

// 设置默认文件名为当前时间:年月日时分秒
if (excelName == null || excelName == "") {
excelName = new SimpleDateFormat("yyyyMMddhhmmss").format(
new Date()).toString();
}
// 设置response头信息
response.reset();
response.setContentType("application/vnd.ms-excel"); // 改成输出excel文件
try {
response.setHeader("Content-disposition", "attachment; filename="
+ new String(excelName.getBytes("gb2312"), "ISO-8859-1") + ".xls");
} catch (UnsupportedEncodingException e1) {
logger.info(e1.getMessage());
}

try {
//创建一个WorkBook,对应一个Excel文件
HSSFWorkbook wb = new HSSFWorkbook();
//在Workbook中,创建一个sheet,对应Excel中的工作薄(sheet)
HSSFSheet sheet = wb.createSheet(excelName);
//创建单元格,并设置值表头 设置表头居中
HSSFCellStyle style = wb.createCellStyle();
//创建一个居中格式
style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
// 填充工作表
fillSheet(sheet, list, fieldMap, style);

//将文件输出
OutputStream ouputStream = response.getOutputStream();
wb.write(ouputStream);
ouputStream.flush();
ouputStream.close();
} catch (Exception e) {
logger.info("导出Excel失败!");
logger.error(e.getMessage());
}
}

/**
* 根据字段名获取字段对象
*
* @param fieldName 字段名
* @param clazz 包含该字段的类
* @return 字段
*/
public static Field getFieldByName(String fieldName, Class<?> clazz) {
logger.info("根据字段名获取字段对象:getFieldByName()");
// 拿到本类的所有字段
Field[] selfFields = clazz.getDeclaredFields();

// 如果本类中存在该字段,则返回
for (Field field : selfFields) {
//如果本类中存在该字段,则返回
if (field.getName().equals(fieldName)) {
return field;
}
}

// 否则,查看父类中是否存在此字段,如果有则返回
Class<?> superClazz = clazz.getSuperclass();
if (superClazz != null && superClazz != Object.class) {
//递归
return getFieldByName(fieldName, superClazz);
}

// 如果本类和父类都没有,则返回空
return null;
}

/**
* 根据字段名获取字段值
*
* @param fieldName 字段名
* @param o 对象
* @return 字段值
* @throws Exception 异常
*/
public static Object getFieldValueByName(String fieldName, Object o)
throws Exception {

logger.info("根据字段名获取字段值:getFieldValueByName()");
Object value = null;
//根据字段名得到字段对象
Field field = getFieldByName(fieldName, o.getClass());

//如果该字段存在,则取出该字段的值
if (field != null) {
field.setAccessible(true);//类中的成员变量为private,在类外边使用属性值,故必须进行此操作
value = field.get(o);//获取当前对象中当前Field的value
} else {
throw new Exception(o.getClass().getSimpleName() + "类不存在字段名 "
+ fieldName);
}

return value;
}

/**
* 根据带路径或不带路径的属性名获取属性值,即接受简单属性名,
* 如userName等,又接受带路径的属性名,如student.department.name等
*
* @param fieldNameSequence 带路径的属性名或简单属性名
* @param o 对象
* @return 属性值
* @throws Exception 异常
*/
public static Object getFieldValueByNameSequence(String fieldNameSequence,
Object o) throws Exception {
logger.info("根据带路径或不带路径的属性名获取属性值,即接受简单属性名:getFieldValueByNameSequence()");
Object value = null;

// 将fieldNameSequence进行拆分
String[] attributes = fieldNameSequence.split("\\.");
if (attributes.length == 1) {
value = getFieldValueByName(fieldNameSequence, o);
} else {
// 根据数组中第一个连接属性名获取连接属性对象,如student.department.name
Object fieldObj = getFieldValueByName(attributes[0], o);
//截取除第一个属性名之后的路径
String subFieldNameSequence = fieldNameSequence
.substring(fieldNameSequence.indexOf(".") + 1);
//递归得到最终的属性对象的值
value = getFieldValueByNameSequence(subFieldNameSequence, fieldObj);
}
return value;

}

/**
* 向工作表中填充数据
*
* @param sheet excel的工作表名称
* @param list 数据源
* @param fieldMap 中英文字段对应关系的Map
* @param style 表格中的格式
* @throws Exception 异常
*/
public static <T> void fillSheet(HSSFSheet sheet, List<T> list,
LinkedHashMap<String, String> fieldMap, HSSFCellStyle style) throws Exception {
logger.info("向工作表中填充数据:fillSheet()");
// 定义存放英文字段名和中文字段名的数组
String[] enFields = new String[fieldMap.size()];
String[] cnFields = new String[fieldMap.size()];

// 填充数组
int count = 0;
for (Map.Entry<String, String> entry : fieldMap.entrySet()) {
enFields[count] = entry.getKey();
cnFields[count] = entry.getValue();
count++;
}

//在sheet中添加表头第0行,注意老版本poi对Excel的行数列数有限制short
HSSFRow row = sheet.createRow((int) 0);

// 填充表头
for (int i = 0; i < cnFields.length; i++) {
HSSFCell cell = row.createCell(i);
cell.setCellValue(cnFields[i]);
cell.setCellStyle(style);
sheet.autoSizeColumn(i);
}

// 填充内容
for (int index = 0; index < list.size(); index++) {
row = sheet.createRow(index + 1);
// 获取单个对象
T item = list.get(index);
for (int i = 0; i < enFields.length; i++) {
Object objValue = getFieldValueByNameSequence(enFields[i], item);
String fieldValue = objValue == null ? "" : objValue.toString();

row.createCell(i).setCellValue(fieldValue);
}
}
}

}

编写实体类

需要输出到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
package org.emall.website.entity;

import java.math.BigInteger;

/**
* @author created by Zhangdazhuang
* @version v.0.1
* @Description TODO
* @date 2019/4/7
* @备注
**/
public class Excel {
private BigInteger id;
private String order_number;
private String amount_real;
private String date_add;
private String status_str;
private String link_man;
private String mobie;
private String address;
private String detailValue;

public Excel() {

}

public Excel(BigInteger id, String order_number, String amount_real, String date_add, String status_str, String link_man, String mobie, String address, String detailValue) {
this.id = id;
this.order_number = order_number;
this.amount_real = amount_real;
this.date_add = date_add;
this.status_str = status_str;
this.link_man = link_man;
this.mobie = mobie;
this.address = address;
this.detailValue = detailValue;
}

public BigInteger getId() {
return id;
}

public void setId(BigInteger id) {
this.id = id;
}

public String getOrder_number() {
return order_number;
}

public void setOrder_number(String order_number) {
this.order_number = order_number;
}

public String getAmount_real() {
return amount_real;
}

public void setAmount_real(String amount_real) {
this.amount_real = amount_real;
}

public String getDate_add() {
return date_add;
}

public void setDate_add(String date_add) {
this.date_add = date_add;
}

public String getStatus_str() {
return status_str;
}

public void setStatus_str(String status_str) {
this.status_str = status_str;
}

public String getLink_man() {
return link_man;
}

public void setLink_man(String link_man) {
this.link_man = link_man;
}

public String getMobie() {
return mobie;
}

public void setMobie(String mobie) {
this.mobie = mobie;
}

public String getAddress() {
return address;
}

public void setAddress(String address) {
this.address = address;
}

public String getDetailValue() {
return detailValue;
}

public void setDetailValue(String detailValue) {
this.detailValue = detailValue;
}
}

编写控制层即得到Json数据

编写控制层ExcelController,注意fieldMap.put(“实体类属性名”,”Excel中显示的属性名”); 设置实体属性名和数据库中对应。如果得不到数据对应不上,请采用ResultMap设置或者用Select XX(数据库名)As 实体属性名

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
package org.emall.website.controller;

import org.emall.website.entity.Excel;
import org.emall.website.entity.Order;
import org.emall.website.service.OrderService;
import org.emall.website.util.ExportExcelUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.LinkedHashMap;
import java.util.List;

/**
* @author created by Zhangdazhuang
* @version v.0.1
* @Description TODO
* @date 2019/4/7
* @备注
**/
@Controller
public class ExcelController {

@Autowired
private HttpServletRequest request;
@Autowired
private OrderService orderService;

@RequestMapping(value = "/excel/exportBankCheckInfo",method = RequestMethod.GET)
public void ExportBankCkeckInfo(HttpServletResponse response, HttpServletRequest request){
//这里是笔者实际业务需求中需要得到时间间隔。可忽略
String start=request.getParameter("start");
String end=request.getParameter("end");
System.out.println("打印的起始日期为:"+start+",打印的结束日期为:"+end);
//得到所有要导出的数据
List<Excel> orderlist =orderService.listexcel(start,end);
//定义导出的excel名字
String excelName = "订单详情表";

//获取需要转出的excel表头的map字段
LinkedHashMap<String, String> fieldMap = new LinkedHashMap<>();
fieldMap.put("id","编号");
fieldMap.put("link_man","姓名");
fieldMap.put("amount_real","价格");
fieldMap.put("date_add","日期");
fieldMap.put("status_str","订单状态");
fieldMap.put("mobie","收货电话");
fieldMap.put("address","地址");
fieldMap.put("detailValue","订单详情");

//导出用户相关信息
new ExportExcelUtils().export(excelName,orderlist,fieldMap,response);
}






}

验证

在导出工具类中,通过HttpServletResponse response设置输出为Excel。所以通过Controller层的Url可以直接得到URL。保存位置是保存在浏览器的默认保存位置,因为是下载请求。(笔者存疑:是否可以保存到任意位置)。
输入请求 127.0.0.1:8080/(可选项目名)/excel/exportBankCheckInfo

最后查看导出的Excel格式如下:
导出预览
这里只是简单实现了Excel的导入,通过Poi插件或者其他开源的插件可以对导入导出Excel做更加功能丰富的操作,详情请移步CSDN或者github。欢迎加入Q群959706394,大家一起学习交流编程知识,解决实际业务需求中各种需求。

可以参考下一篇博客,采用注解实现导出,并添加各种样式。

Thank you for your accept. mua!
-------------本文结束感谢您的阅读-------------