本文已参与「新人创作礼」活动,一起开启掘金创作之路。
最近工作中有需求需要将数据导出到Excel中,这个功能以前做过的项目中几乎都有,但都是人家已经实现了的,这次自己做也折腾了不少的时间,特此记录方便以后自己查阅。
首先需要借助第三方jar包,如标题所言,这次需要导入的是easypoi,官方介绍如下:
easypoi功能如同名字easy,主打的功能就是容易,让一个没见接触过poi的人员 就可以方便的写出Excel导出,Excel模板导出,Excel导入,Word模板导出,通过简单的注解和模板 语言(熟悉的表达式语法),完成以前复杂的写法
官方文档:easypoi.mydoc.io/
maven导入:
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-base</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-web</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-annotation</artifactId>
<version>4.1.2</version>
</dependency>
导出Excel可以用 ExcelExportUtil 这个类,不过我参考了其他博主在此基础上又封装了一个工具类,叫 ExcelUtils,代码如下:
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.afterturn.easypoi.excel.entity.enmus.ExcelType;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
/**
* Excel导入导出工具类
* @author wl
* @date 2021/8/9
*/
public class ExcelUtils {
/**
* excel 导出
*
* @param list 数据列表
* @param fileName 导出时的excel名称
* @param response
*/
public static void exportExcel(List<Map<String, Object>> list, String fileName, HttpServletResponse response) throws IOException {
defaultExport(list, fileName, response);
}
/**
* 默认的 excel 导出
*
* @param list 数据列表
* @param fileName 导出时的excel名称
* @param response
*/
private static void defaultExport(List<Map<String, Object>> list, String fileName, HttpServletResponse response) throws IOException {
//把数据添加到excel表格中
Workbook workbook = ExcelExportUtil.exportExcel(list, ExcelType.HSSF);
downLoadExcel(fileName, response, workbook);
}
/**
* excel 导出
*
* @param list 数据列表
* @param pojoClass pojo类型
* @param fileName 导出时的excel名称
* @param response
* @param exportParams 导出参数(标题、sheet名称、是否创建表头,表格类型)
*/
private static void defaultExport(List<?> list, Class<?> pojoClass, String fileName, HttpServletResponse response, ExportParams exportParams) throws IOException {
//把数据添加到excel表格中
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, pojoClass, list);
downLoadExcel(fileName, response, workbook);
}
/**
* excel 导出
*
* @param list 数据列表
* @param pojoClass pojo类型
* @param fileName 导出时的excel名称
* @param exportParams 导出参数(标题、sheet名称、是否创建表头,表格类型)
* @param response
*/
public static void exportExcel(List<?> list, Class<?> pojoClass, String fileName, ExportParams exportParams, HttpServletResponse response) throws IOException {
defaultExport(list, pojoClass, fileName, response, exportParams);
}
/**
* excel 导出
*
* @param list 数据列表
* @param title 表格内数据标题
* @param sheetName sheet名称
* @param pojoClass pojo类型
* @param fileName 导出时的excel名称
* @param response
*/
public static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass, String fileName, HttpServletResponse response) throws IOException {
defaultExport(list, pojoClass, fileName, response, new ExportParams(title, sheetName, ExcelType.XSSF));
}
/**
* excel 导出
*
* @param list 数据列表
* @param title 表格内数据标题
* @param sheetName sheet名称
* @param pojoClass pojo类型
* @param fileName 导出时的excel名称
* @param isCreateHeader 是否创建表头
* @param response
*/
public static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass, String fileName, boolean isCreateHeader, HttpServletResponse response) throws IOException {
ExportParams exportParams = new ExportParams(title, sheetName, ExcelType.XSSF);
exportParams.setCreateHeadRows(isCreateHeader);
defaultExport(list, pojoClass, fileName, response, exportParams);
}
/**
* excel下载
*
* @param fileName 下载时的文件名称
* @param response
* @param workbook excel数据
*/
private static void downLoadExcel(String fileName, HttpServletResponse response, Workbook workbook) throws IOException {
try {
response.setCharacterEncoding("UTF-8");
response.setHeader("content-Type", "application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName + ".xlsx", "UTF-8"));
workbook.write(response.getOutputStream());
} catch (Exception e) {
throw new IOException(e.getMessage());
}
}
/**
* excel 导入
*
* @param file excel文件
* @param pojoClass pojo类型
* @param <T>
* @return
*/
public static <T> List<T> importExcel(MultipartFile file, Class<T> pojoClass) throws IOException {
return importExcel(file, 1, 1, pojoClass);
}
/**
* excel 导入
*
* @param filePath excel文件路径
* @param titleRows 表格内数据标题行
* @param headerRows 表头行
* @param pojoClass pojo类型
* @param <T>
* @return
*/
public static <T> List<T> importExcel(String filePath, Integer titleRows, Integer headerRows, Class<T> pojoClass) throws IOException {
if (StringUtils.isBlank(filePath)) {
return null;
}
ImportParams params = new ImportParams();
params.setTitleRows(titleRows);
params.setHeadRows(headerRows);
params.setNeedSave(true);
params.setSaveUrl("/excel/");
try {
return ExcelImportUtil.importExcel(new File(filePath), pojoClass, params);
} catch (NoSuchElementException e) {
throw new IOException("模板不能为空");
} catch (Exception e) {
throw new IOException(e.getMessage());
}
}
/**
* excel 导入
*
* @param file 上传的文件
* @param titleRows 表格内数据标题行
* @param headerRows 表头行
* @param pojoClass pojo类型
* @param <T>
* @return
*/
public static <T> List<T> importExcel(MultipartFile file, Integer titleRows, Integer headerRows, Class<T> pojoClass) throws IOException {
if (file == null) {
return null;
}
try {
return importExcel(file.getInputStream(), titleRows, headerRows, pojoClass);
} catch (Exception e) {
throw new IOException(e.getMessage());
}
}
/**
* excel 导入
*
* @param inputStream 文件输入流
* @param titleRows 表格内数据标题行
* @param headerRows 表头行
* @param pojoClass pojo类型
* @param <T>
* @return
*/
public static <T> List<T> importExcel(InputStream inputStream, Integer titleRows, Integer headerRows, Class<T> pojoClass) throws IOException {
if (inputStream == null) {
return null;
}
ImportParams params = new ImportParams();
params.setTitleRows(titleRows);
params.setHeadRows(headerRows);
params.setSaveUrl("/excel/");
params.setNeedSave(true);
try {
return ExcelImportUtil.importExcel(inputStream, pojoClass, params);
} catch (NoSuchElementException e) {
throw new IOException("excel文件不能为空");
} catch (Exception e) {
throw new IOException(e.getMessage());
}
}
}
Service层方法调用:
@Override
public Boolean export(List<Integer> fenceIds, HttpServletResponse response) {
List<ElectronicFenceExcel> electronicFences = baseMapper.getListByIds(fenceIds);
if (electronicFences == null) {
log.warn("未查询到历史事件");
return false;
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
String fileName = sdf.format(new Date());
try {
ExcelUtils.exportExcel(electronicFences, ElectronicFenceExcel.class, fileName,
new ExportParams(), response);
} catch (IOException e) {
e.printStackTrace();
}
return true;
}
Controller层:
@GetMapping("/export")
public RestResult export(@RequestParam("fenceIds") List<Integer> fenceIds, HttpServletResponse response) {
if (!electronicFenceService.export(fenceIds , response)) {
return RestResult.fail("导出失败");
}
return RestResult.success();
}
接下来是重点,利用easypoi导出Excel时,除了借助 ExcelExportUtil 这个工具类,另外还需要通过@Excel等注解的方式设置导出Excel文件的格式。
如上代码,导出的数据类型为 List,下面放上ElectronicFenceExcel的代码:
import cn.afterturn.easypoi.excel.annotation.ExcelCollection;
import cn.afterturn.easypoi.excel.annotation.ExcelEntity;
import cn.afterturn.easypoi.excel.annotation.ExcelTarget;
import lombok.Data;
import java.util.List;
/**
* @author wl
* @date 2021/8/6
*/
@Data
@ExcelTarget("electronicFenceExcel")
public class ElectronicFenceExcel {
@ExcelEntity(id = "electronicFence")
private ElectronicFence electronicFence;
@ExcelCollection(name = "详情", orderNum = "7")
private List<ElectronicFenceEvent> eventList;
}
注解说明:
@ExcelTarget
限定一个导出实体的注解,以及一些通用设置,作用于最外面的实体
@ExcelEntity
标记是不是导出excel 标记为实体类,一遍是一个内部属性类,标记是否继续穿透,可以自定义内部id
@ExcelCollection
一对多的集合注解,用以标记集合是否被数据以及集合的整体排序
接着再看ElectronicFence这个类:
import cn.afterturn.easypoi.excel.annotation.Excel;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import java.util.List;
/**
* 电子围栏,包含任务状态信息
* @author ruosi.zhang
* @date 2021/8/3
*/
@Data
public class ElectronicFence {
@Excel(name = "序号", needMerge = true, orderNum = "1")
@TableField(exist = false)
private Integer num;
@Excel(name = "马甲编号", needMerge = true, orderNum = "2")
private String vestId;
@Excel(name = "任务名称", needMerge = true, orderNum = "3")
private String taskName;
@Excel(name = "任务状态", needMerge = true, replace = {"已执行_1", "执行中_2", "暂停_3", "终止_4", "未执行_5", "逾期_6"}, orderNum = "4")
private Integer taskStatus;
@Excel(name = "开始时间", needMerge = true, format = "yyyy-MM-dd HH:mm:ss", width = 30, orderNum = "5")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date startTime;
@Excel(name = "结束时间", needMerge = true, format = "yyyy-MM-dd HH:mm:ss", width = 30, orderNum = "6")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date endTime;
}
注解属性说明:
name:列名
needMerge:是否需要纵向合并单元格,默认false
orderNum:列的排序,默认“0”
replace:值的替换 导出是{a_id,b_id} 导入反过来
type:导出类型 1 是文本 2 是图片,3 是函数,10 是数字 默认1
width:列宽
height:列高
format:时间格式
最后导出结果:
ExcelUtils 参考:https://www.cnblogs.com/zys2019/p/13194068.html#_label2