excel导出一直是一个很枯燥的工作。今天分享一个自己编写的小model,如果大家也觉得方便好用。点个赞呗 >->
1. 定义标签
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TableFieldName {
String value() default "";
}
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TableFieldIgnore {
}
@TableFieldName: 自定义表头名称
@TableFieldIgnore: 忽略字段
2. 核心工具类
public class ExcelUtil<T> {
/**
* 使用方式: 分页数据查询导出
* req.setPageNum(1);
* req.setPageSize(pageSize);
* String fileName = "XXX";
* String tableName = "YYY";
* Class<PageVO> cla = PageVO.class;
* List<PageVO> data = service.queryPage(req).getData().getRecords();
* new ExcelUtil<PageVO>().export(fileName,tableName,cla,data,response);
*
* @param fileName 导出文件名
* @param tableName excel表格标题
* @param cla Bean的class对象
* @param data 分页的List集合数据
* @param response response
*/
public void export(String fileName, String tableName, Class cla, List<T> data, HttpServletResponse response) {
// TODO >65536 使用多个sheet
Assert.isTrue(data.size() < 65536, "超出excel单个sheet的最大值");
ExcelWriter writer = cn.hutool.poi.excel.ExcelUtil.getWriter();
writer.setOnlyAlias(true);
int count = 0;
Field[] declaredFields = cla.getDeclaredFields();
for (Field field : declaredFields) {
TableFieldIgnore tableFieldIgnore = field.getAnnotation(TableFieldIgnore.class);
if (tableFieldIgnore != null) {
continue;
}
Class<?> fieldType = field.getType();
if (fieldType.isAssignableFrom(List.class)) {
continue;
}
ApiModelProperty apiModelProperty = field.getAnnotation(ApiModelProperty.class);
if (apiModelProperty == null) {
continue;
}
String fieldCnName = apiModelProperty.value();
String fieldEnName = field.getName();
TableFieldName tableFieldName = field.getAnnotation(TableFieldName.class);
if (tableFieldName != null) {
fieldCnName = tableFieldName.value();
}
writer.addHeaderAlias(fieldEnName, fieldCnName);
writer.setColumnWidth(-1,20);
if(StringUtils.isNoneEmpty(fieldCnName)){
count++;
}
}
writer.merge(count-1, tableName);
writer.write(data, true);
response.setContentType("application/vnd.ms-excel;charset=utf-8");
try {
String finalFileName = URLEncoder.encode(DateUtil.format(new Date(), "yyyyMMddHHmmss") + "_" + fileName + ".xls", "UTF-8");
response.setHeader("Content-Disposition", "attachment;filename=" + finalFileName);
ServletOutputStream out = response.getOutputStream();
writer.flush(out);
} catch (Exception e) {
log.error("Excel导出错误:{}", e.getMessage());
}finally {
writer.close();
}
}
}
3. 环境支持
a. hutool-all 5.5.7
b. 使用swagger做api文档
4. 不足跟注意点:
a. 在性能问题不考虑前提下,表头默认使用Bean中Field的定义顺序,可以根据需要,调整Bean中Field顺序,也可以定义@TableFieldOrder标签,对Field表头进行排序
b. 为什么使用new ExcelUtil的方式类使用,主要是为了Util中声明的泛型类型,经过源码查看(可以自行验证),在当List data参数解析元素为map的时候,会出现丢失表头问题(当首行,及首个bean的Field被定义为表头,但list中Bean的Field为空时)