EasyExcel单sheet页导出和多sheet页导出(支持多数据表)

发布于:2024-05-06 ⋅ 阅读:(45) ⋅ 点赞:(0)

对于Excel导入导出相信我们大家都不陌生,很多时候我们都需要有其功能方便业务人员进行批量数据的新增,避免一条数据一条数据的新增,也方便业务人员导出数据进行个人的统计等。 这里我通过个人的一个demo来带大家实现一下导出功能

先列出easyexcel作者的官方文档地址

导出VO,这里我图方便就直接用数据库操作对象了,大家可以自行更换成自己的vo对象

/**
 * 文件导入不能使用 @Accessors(chain = true)注解
 * 且需要添加@NoArgsConstructor 和 @AllArgsConstructor注解
 */
@Data
@Builder
@TableName("user")
@NoArgsConstructor
@AllArgsConstructor
public class UserPO implements Serializable {
    private static final long serialVersionUID = 1L;
    @TableId(type = IdType.ASSIGN_ID)
    @ExcelIgnore
    private String id;
    @ExcelProperty(value = "姓名")
    private String name;
    @ExcelProperty(value = "年纪")
    private Integer age;
    @ExcelProperty(value = "性别")
    private String sex;
    @ExcelProperty(value = "价格")
    @JsonSerialize(using = CustomerBigDecimalSerialize.class)
    private BigDecimal price;
}

Controller接口

@ApiOperation("选择导出Excel")
@PostMapping("/exportSync")
public void exportExcelSync(@RequestBody JSONObject jsonObject, HttpServletResponse response) {

    String excelType = jsonObject.getStr("excelType");
    String ids = jsonObject.getStr("ids");
    List<UserPO> data = userService.listByIds(ids);
    downloadExcel("personal用户管理" , excelType, response, data, UserPO.class);
}
@ApiOperation("选择导出Excel多sheet页")
@PostMapping("/exportSheets")
public void exportExcelSheets(@RequestBody JSONObject jsonObject, HttpServletResponse response) {
    String excelType = jsonObject.getStr("excelType");
    List<EasyExcelSheet> excelSheets = initData();
    downloadMultipleSheetExcel("personal用户管理" + excelType, response, excelSheets);
}
/**
 * 构建多sheet页model
 */
private List<EasyExcelSheet> initData(){
    List<UserPO> data = userService.listAll();
    List<UserPO> data1 = userService.listAll();
    EasyExcelSheet dictVoSheet = EasyExcelSheet.builder()
            .sheetIndex(0)
            .sheetName("用户管理1")
            .headClass(UserPO.class)
            .dataset(data)
            .build();
    EasyExcelSheet itemDataSheet = EasyExcelSheet.builder()
            .sheetIndex(1)
            .sheetName("用户管理2")
            .headClass(UserPO.class)
            .dataset(data1)
            .build();
    return Lists.newArrayList(dictVoSheet,itemDataSheet);
}

接口这里的参数@RequestBody JSONObject jsonObject可以和前端约定好,传入json类型的字符串就可以,如下

image.png

具体导出实现ServiceImpl

/**
 * 同步导出excel文件,不支持大数据量导出
 * @param fileName 文件名称
 * @param excelType 导出excel文件类型
 * @param response 响应体
 * @param data  需要导出的数据结果集
 * @param head 对应的实体类
 */
public void downloadExcel(String fileName,String excelType, HttpServletResponse response, Collection data, Class head){
    try {
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码
        String encodeFileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + encodeFileName+"."+excelType);

        ExcelTypeEnum excelTypeEnum = ExcelTypeEnum.XLSX;
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        if("xls".equals(excelType)){
            excelTypeEnum = ExcelTypeEnum.XLS;
            response.setContentType("application/vnd.ms-excel");
        }else if("csv".equals(excelType)){
            excelTypeEnum = ExcelTypeEnum.CSV;
            response.setContentType("text/csv");
        }
        EasyExcel.write(response.getOutputStream(), head).excelType(excelTypeEnum).sheet(fileName).doWrite(data);
    } catch (Exception e) {
        log.error("文件【{}】下载失败", fileName);
        log.error(e.getMessage(), e);
    }
}

/**
 * 导出为多sheet页excel数据,不支持大数据量导出,可为多数据表结果集
 * @param fileName 文件名称 如:personal用户管理xlsx
 * @param response  响应体
 * @param sheets 封装后的多sheet页model
 */
public void downloadMultipleSheetExcel(String fileName, HttpServletResponse response, List<EasyExcelSheet> sheets){
    try {
        response.setCharacterEncoding("utf-8");
        String excelType = FileUtil.extName(fileName);
        String sheetName = FileUtil.mainName(fileName);

        // 这里URLEncoder.encode可以防止中文乱码
        String encodeFileName = URLEncoder.encode(sheetName, "UTF-8").replaceAll("\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + encodeFileName + "." + excelType);

        ExcelTypeEnum excelTypeEnum = ExcelTypeEnum.XLSX;
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        if ("xls".equals(excelType)) {
            excelTypeEnum = ExcelTypeEnum.XLS;
            response.setContentType("application/vnd.ms-excel");
        } else if ("csv".equals(excelType)) {
            excelTypeEnum = ExcelTypeEnum.CSV;
            response.setContentType("text/csv");
        }
        ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).excelType(excelTypeEnum).build();
        sheets.forEach(sheet -> {
            // sheet页位置,sheet页名称
            WriteSheet writeSheet = EasyExcel.writerSheet(sheet.getSheetIndex(), sheet.getSheetName())
                    // 表头实体
                    .head(sheet.getHeadClass())
                    // 导出内容格式,默认最大列为基准,具体样式可自定义实现(这里可以百度一下)
                    .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                    .build();
            excelWriter.write(sheet.getDataset(), writeSheet);
        });
        excelWriter.finish();
        response.flushBuffer();
    } catch (Exception e) {
        log.error("文件【{}】下载失败", fileName);
        log.error(e.getMessage(), e);
    }
}

其中有引用的一个文件工具类FileUtil,这个可以不需要,其实就是文件名称和类型的截取,可以通过其他方式代替,例如传参


public class FileUtil {

    /**
     * 获取文件扩展名
     * @param fileName 文件名全称 如:用户管理.xlsx
     * @return 扩展名 如:xlsx
     */
    public static String extName(String fileName) {
        if (fileName == null) {
            return null;
        }
        int index = fileName.lastIndexOf(".");
        if (index == -1) {
            return "";
        } else {
            String ext = fileName.substring(index + 1);
            // 扩展名中不能包含路径相关的符号
            return (ext.contains(String.valueOf("/")) || ext.contains(String.valueOf("\"))) ? "" : ext;
        }
    }

    /**
     * 返回文件名
     * @param fileName 文件名全称 如:用户管理.xlsx
     * @return 文件名 如:用户管理
     */
    public static String mainName(String fileName) {
        if (StringUtils.isBlank(fileName) || false == fileName.contains(".")) {
            return fileName;
        }
        // 切割字符串到指定位置
        return fileName.substring(0, fileName.lastIndexOf("."));
    }
}
@Data
class FileData{
    /**
     * 文件名称:xxx.txt
     */
    private String fileName;
    /**
     * 文件内容
     */
    private String fileContext;
}

这里是一个简单的导出demo,这里并不支持大数据集的一个数据量导入,后面我会抽时间写一个支持大数据集如几十万以上级别的数据集导出,大家有更好的方法欢迎评论,我会认真吸取每个人的意见~