优化了下以前写的工具类。
优点:
- 标题支持从实体类中直接取值
- 数据列表支持List<自定义类/八大基本类型/String>
- 工具类采用可变参数,不会过多限制数据数量与数据格式
代码:
工具类:
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.core.annotation.AnnotationUtils;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Slf4j
public class MyExcelUtil {
/**
* 生成xlsx格式的Excel表格
*
* @param sheetName sheet名称
* @param titleList 标题列表
* @param data 数据列表,支持List<自定义类/八大基本类型/String>
* @return XSSFWorkbook
*/
public static XSSFWorkbook getXSSFWorkbook(String sheetName,
List<String> titleList, List<?>... data) throws IllegalAccessException {
// 创建HSSFWorkbook对象
XSSFWorkbook wb = new XSSFWorkbook();
// 创建sheet对象
XSSFSheet sheet = wb.createSheet(sheetName);
// 在sheet里创建第一行,这里即是表头
XSSFRow rowTitle = sheet.createRow(0);
// 写入表头的每一个列
for (int i = 0; i < titleList.size(); i++) {
// 创建单元格
rowTitle.createCell(i).setCellValue(titleList.get(i));
}
// 写入每一行的记录
int col = 1;
for (List<?> dataList : data) {
if (CollectionUtils.isEmpty(dataList)) {
continue;
}
if (isBaseType(dataList.get(0))) {
// List<八大基本类型/String>创建新的一行
XSSFRow rowData = sheet.createRow(col++);
for (int j = 0, le = dataList.size(); j < le; j++) {
//创建单元格
Object obj = dataList.get(j);
if (obj == null)
continue;
rowData.createCell(j).setCellValue(String.valueOf(obj));
}
} else {
// List<自定义类>创建多行
for (Object o : dataList) {
XSSFRow rowData = sheet.createRow(col++);
Class<?> cl = o.getClass();
Field[] fields = cl.getDeclaredFields();
for (int j = 0, le = fields.length; j < le; j++) {
// 设置字段可见,否则会报错,禁止访问
fields[j].setAccessible(true);
// 创建单元格
Object obj = fields[j].get(o);
if (obj == null) {
continue;
}
if (obj instanceof Date) {
rowData.createCell(j).setCellValue(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(obj));
} else {
rowData.createCell(j).setCellValue(String.valueOf(obj));
}
}
}
}
}
return wb;
}
/**
* 用反射获取Desc注释值,来生成标题列表titleList
*
* @param titleClass
* @param <T>
* @return
*/
public static <T> List<String> getTitleListByClass(Class<T> titleClass) {
List<String> titleList = new ArrayList<>();
Field[] titleFields = titleClass.getDeclaredFields();
for (Field field : titleFields) {
Desc desc = AnnotationUtils.findAnnotation(field, Desc.class);
if (desc != null) {
titleList.add(desc.value());
}
}
return titleList;
}
/**
* 将List<?>转换为List<T>
*
* @param obj
* @param clazz
* @param <T>
* @return
*/
public static <T> List<T> castList(Object obj, Class<T> clazz) {
List<T> result = new ArrayList<>();
if (obj instanceof List<?>) {
for (Object o : (List<?>) obj) {
result.add(clazz.cast(o));
}
return result;
}
return null;
}
/**
* 判断object是否为基本类型或String
*
* @param object
* @return
*/
public static boolean isBaseType(Object object) {
Class<?> className = object.getClass();
return (className.equals(java.lang.Integer.class) ||
className.equals(java.lang.Byte.class) ||
className.equals(java.lang.Long.class) ||
className.equals(java.lang.Double.class) ||
className.equals(java.lang.Float.class) ||
className.equals(java.lang.Character.class) ||
className.equals(java.lang.Short.class) ||
className.equals(java.lang.Boolean.class) ||
className.equals(java.lang.String.class));
}
}
注释类:
@Retention(RetentionPolicy.RUNTIME)
public @interface Desc {
String value();
}
自义定实体类例子:
@Data
public class ExportResp {
@Desc("编号")
private Integer id;
@Desc("标题")
private String title;
@Desc("状态")
private String status;
}
接口例子:
@GetMapping("/getExcel")
public void getExcel(HttpServletResponse response) {
// 随便造几个数据
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);
List<Double> doubles = Arrays.asList(1.12, 2.23, 3.34, 4.45, 5.56);
List<String> strings = Arrays.asList("测试1", "测试2", "测试3", "测试4", "测试5");
ExportResp resp = new ExportResp();
resp.setId(1);
resp.setTitle("标题优秀");
resp.setStatus("状态优秀");
List<ExportResp> respList = new ArrayList<>();
respList.add(resp);
respList.add(resp);
// 使用 try-with-resources 使代码更简洁,编译器会自动补全close()
try (ServletOutputStream out = response.getOutputStream()) {
String fileName = URLEncoder.encode("默认标题.xlsx", "UTF-8");
response.reset();
response.setContentType("application/vnd.ms-excel;charset=utf-8");
// filename*=utf-8''支持中文标题
response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ";" + "filename*=utf-8''" + fileName);
MyExcelUtil.getXSSFWorkbook("bug记录", MyExcelUtil.getTitleListByClass(ExportResp.class), integers, doubles, strings, respList).write(out);
} catch (Exception e) {
e.printStackTrace();
}
}
调用接口:
http://localhost:8080/excel/getExcel