Java&EasyPoi将数据导出Excel

1,332 阅读5分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

最近工作中有需求需要将数据导出到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:时间格式

最后导出结果:

image.png

ExcelUtils 参考:https://www.cnblogs.com/zys2019/p/13194068.html#_label2