1、说明:导出功能(支持全部字段导出和用户自定义字段导出)
1 使用方式:导出接口类上添加注解 @EasyExcelExport,返回值必须以分页形式接收,一般场景与列表接口同时使用即可
2 注意事项:时间类型字段必须需定义成String类型,导出实体类可单独封装
3 VO实体必须遵从规范,必须要有字段描述 @ApiModelProperty,否则导出表头为字段名
4 如果场景为用户自定义导出字段(即前端支持可选择导出的字段),需在请求头添加TITLE_NAME和FIELD_NAME,参数值以英文逗号分隔,且必须保证一一对应
2、代码
<dependency>
<groupId>com.alibabagroupId>
<artifactId>easyexcelartifactId>
<version>3.1.2version>
dependency>
<dependency>
<groupId>cn.hutoolgroupId>
<artifactId>hutool-allartifactId>
<version>5.8.0version>
<scope>compilescope>
dependency>
/**
* 动态参数导出excel
*
* @author smallNorth_Lee
* @date 2022/11/14
*/
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface EasyExcelExport {
/**
* 文件名称
*/
String fileName() default "";
}
/**
* 动态处理excel导出
*
* @author smallNorth_Lee
* @date 2022/2/25
*/
@Aspect
@Component
public class ExcelExportAspect {
/**
* 是否导出
*/
private static final String IS_EXPORT = "IS_EXPORT";
/**
* 导出表头
*/
private static final String TITLE_NAME = "TITLE_NAME";
/**
* 对应字段名
*/
private static final String FIELD_NAME = "FIELD_NAME";
/**
* 附件名称
*/
private static final String FILE_NAME = "FILE_NAME";
@AfterReturning(returning = "obj", value = "@annotation(excelExport)")
public void excelExport(Object obj, EasyExcelExport excelExport) throws IOException {
//获取request与response对象
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();
//确定是否导出
if (Boolean.parseBoolean(request.getHeader(IS_EXPORT))) {
HttpServletResponse response = Objects.requireNonNull(attributes).getResponse();
//key:表头名 value:字段名
Map<String, Object> exportName = new HashMap<>(16);
//第一种:用户自定义导出,必须保证表头和字段名对应
if (!StringUtils.isEmpty(request.getHeader(TITLE_NAME)) || !StringUtils.isEmpty(request.getHeader(FIELD_NAME))) {
String[] titleLen = TITLE_NAME.split(",");
for (int i = 0; i < titleLen.length; i++) {
exportName.put(titleLen[i], FIELD_NAME.split(",")[i]);
}
} else {
Field[] declaredFields = ((Page) ((ResultVo) obj).getData()).getRecords().get(0).getClass().getDeclaredFields();
for (Field declaredField : declaredFields) {
if (!"serialVersionUID".equals(declaredField.getName())) {
ApiModelProperty modelProperty = declaredField.getAnnotation(ApiModelProperty.class);
exportName.put(modelProperty == null ? declaredField.getName() : modelProperty.value(), declaredField.getName());
}
}
}
//处理返回结果集
JSONObject resObj = JSONUtil.parseObj(obj, false);
Object data = resObj.get("data");
if (data instanceof JSONObject) {
JSONArray records = JSONUtil.parseArray(JSONUtil.parseObj(data).get("records"));
String fileName = URLEncoder.encode("".equals(excelExport.fileName()) ? UUID.randomUUID().toString() : excelExport.fileName(), StandardCharsets.UTF_8.name()).replaceAll("\\+", "%20");
if (!StringUtils.isEmpty(request.getHeader(FILE_NAME))) {
fileName = request.getHeader(FILE_NAME);
}
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename*=utf-8''" + fileName + ExcelTypeEnum.XLSX.getValue());
List<List<Object>> dataList = EasyExcelUtil.dataList(exportName, records);
EasyExcelFactory.write(response.getOutputStream()).sheet("Sheet1").registerWriteHandler(new IEasyExcelHandler()).head(EasyExcelUtil.headList(exportName)).doWrite(dataList);
}
}
}
}
package com.gwfd.common.utils;
import cn.hutool.core.map.MapUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.EasyExcelFactory;
import com.gwfd.common.config.FileProperties;
import com.gwfd.common.enums.FileTypeEnum;
import com.gwfd.common.handler.IEasyExcelHandler;
import io.swagger.annotations.ApiModelProperty;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;
/**
* 导出excel,支持全字段导入以及自定义字段导出
*
* @author smallNorth_Lee
* @date 2022/8/10
*/
public class EasyExcelUtil {
private EasyExcelUtil() {
}
/**
* 封装表格标题
*
* @param headNames 标题数据
* @return 表格标题集合¬
*/
public static List<List<String>> headList(Map<String, Object> headNames) {
List<List<String>> headList = new ArrayList<>();
headNames.forEach((k, v) -> {
List<String> head = new ArrayList<>();
head.add(k);
headList.add(head);
});
return headList;
}
/**
* 封装导出字段的数据结构
*
* @param fieldNames 字段
* @param dataObj 数据集合
* @return 字段值集合
*/
public static List<List<Object>> dataList(Map<String, Object> fieldNames, JSONArray dataObj) {
List<List<Object>> dataList = new ArrayList<>();
for (Object dataObjValue : dataObj) {
List<Object> data = new ArrayList<>();
fieldNames.forEach((k, v) -> data.add(JSONUtil.parseObj(dataObjValue).get(v)));
dataList.add(data);
}
return dataList;
}
}
@EasyExcelExport
@ApiOperation(value = "测试表列表分页查询-导出")
@GetMapping("/list")
public ResultVo<IPage<TemplateTableVO>> queryPage(){
TemplateTableQuery templateTableQuery=new TemplateTableQuery();
templateTableQuery.setCurrent(1);
templateTableQuery.setSize(10);
return new ResultVo<>(templateTableAppService.queryPage(templateTableQuery));
}
前端使用方式: 参数除IS_EXPORT以外均为非必须
/**
* example code
* IS_EXPORT(是否导出): true 导出 必传
* FILE_NAME(导出的文件名称): 可不传,扩展字段,特殊场景使用
* TITLE_NAME(自定义表头): 可不传,扩展字段,特殊场景使用
* FIELD_NAME(自定义字段值): 可不传,扩展字段,特殊场景使用
* @param data
* @returns
*/
export function exportExcel(data: parames) {
return service({
url: "/example/export",
method: "POST",
headers: {
IS_EXPORT: true,
FILE_NAME: "Example excel",
TITLE_NAME:"设备名称,设备编码,巡视结果",
FIELD_NAME:"deviceName,deviceCode,patrolResult"
},
data
})
}