springboot+easyExcel 动态列表导出

1.pom依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>3.0.0-beta2</version>
</dependency>

2.导出传参类 

/**
 * @author hbj
 * @Date 2021/12/9 18:21
 * @Description
 * @Modified By
 */
@ApiModel(description = "导出传参类")
@Data
public class ExportDto {
    //接口访问路径
    @ApiModelProperty("接口访问路径")
    private String url;
    //请求方法;get或者post
    @ApiModelProperty("请求方法")
    private String method;
    //导出参数
    @ApiModelProperty("导出数据参数")
    private List<ExportParamsDto> exportParams;
    //搜索参数
    @ApiModelProperty("查询参数")
    private Map<String,Object> queryParams;
    //导出数量
    @ApiModelProperty("导出数量")
    private Long total;
    //导出文件名
    @ApiModelProperty("导出文件名")
    private String fileName;
}
@ApiModel(description = "导出数据参数")
@Data
public class ExportParamsDto {
    @ApiModelProperty("参数名(表头名字)")
    private String headName;
    @ApiModelProperty("对应字段")
    private String cloumn;
    /*@ApiModelProperty("时间参数格式(用于设置时间格式)")
    private String dateFormat;*/
    @ApiModelProperty("需要除以的数")
    private BigDecimal divideNum;
}

3.导出处理类 ExportDeal

/**
 * @author hbj
 * @Date 2021/12/17 17:37
 * @Description
 * @Modified By
 */
@Log4j2
public class ExportDeal {
    private ExcelWriter excelWriter;
    private List<List<String>> heads;
    private WriteHandler writeHandler;
    private String fileName;
    private String sourName;
    private Long startTime;

    //初始化
    public ExportDeal(Map<String, ExportParamsDto> headMap, String fileName, HttpServletResponse response) throws Exception {
        this.sourName = fileName;
        startTime = System.currentTimeMillis();
        //添加响应头信息
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        //表头数组
        this.heads = head(headMap);
        //样式
        if (writeHandler == null) {
            this.writeHandler = new StyleWriteHandler();
            //this.writeHandler=new LongestMatchColumnWidthStyleStrategy();
        }
        //创建表格
        this.excelWriter = EasyExcel.write(response.getOutputStream()).head(heads).build();
        this.fileName = fileName;
        //log.info("表格【{}】初始化成功",sourName);
    }

    private ExportDeal() {
    }

    /**
     * 录入数据
     *
     * @param datas     录入的数据
     * @param sheetNo   第几页
     * @param sheetName 页名称
     * @param <T>
     */
    public <T> void loadData(List<List<Object>> datas, int sheetNo, String sheetName) {
        //录入数据
        WriteSheet writeSheet = EasyExcel.writerSheet(sheetNo).sheetName(sheetName).head(heads)
                .registerWriteHandler(writeHandler).build();
        excelWriter.write(datas, writeSheet);
    }

    /**
     * 根据http获取数据导出
     * @param dto
     * @param sheetNo
     * @param sheetName
     * @param <T>
     * @return
     */
    public <T> Result loadDataByHttp(ExportDto dto, int sheetNo, String sheetName) {
        String res;
        Map<String, String> reqHeadMap = new HashMap<>();
        reqHeadMap.put("Content-Type", "application/json");
        reqHeadMap.put("Accept", "application/json");
        //最大导出10万
        if (dto.getTotal() > 10 * 10000) {
            dto.setTotal(10 * 10000L);
        }
        Map<String, Object> params = dto.getQueryParams();
        if (params == null) {
            params = new HashMap<>();
            params.put("pageSize", dto.getTotal());
            params.put("pageNo", 1);
        }
        if ("GET".equals(dto.getMethod())) {
            res = HttpsClient.doGet(dto.getUrl(), params, reqHeadMap);
        } else {
            res = HttpsClient.doPost(dto.getUrl(), JSONObject.toJSONString(params), reqHeadMap);
        }
        if (res != null) {
            Result<JSONObject> result = JSON.parseObject(res, Result.class);
            if (result.getCode() == 0L && result.getMsg() == null) {
                JSONObject obj = JSON.parseObject(res);
                result = Result.restResult(obj.getLong("status"), obj.getString("error"));
            }
            JSONObject obj = ResultDealUtil.getData(result);
            if (obj != null && CollectionUtils.isNotEmpty(dto.getExportParams())) {
                PageVO<JSONObject> page = JSON.parseObject(obj.toString(), PageVO.class);
                if (CollectionUtils.isNotEmpty(page.getRecords())) {
                    //表头map,key: 表头,value:字段
                    LinkedHashMap<String, ExportParamsDto> headMap = new LinkedHashMap<>();
                    dto.getExportParams().forEach(a -> headMap.put(a.getHeadName(), a));
                    List<List<Object>> datas = this.dataList(headMap, page.getRecords());
                    //录入导出数据
                    this.loadData(datas, sheetNo, sheetName);
                }
            } else if (ResultCode.SUCCESS.getCode() != result.getCode()) {
                log.error("导出失败:查询数据有误,{}", result);
                return result;
            }
        }
        return Result.ok();
    }

    //结束关闭数据
    public void close() {
        //刷新流
        excelWriter.finish();
        log.info("表格【{}】导出处理结束,耗时:{}ms", sourName, System.currentTimeMillis() - startTime);
    }

    private List<List<String>> head(Map<String, ExportParamsDto> headMap) {
        if (headMap == null) {
            return null;
        }
        List<List<String>> list = new ArrayList<>();
        for (String name : headMap.keySet()) {
            List<String> head = new ArrayList<>();
            head.add(name);
            list.add(head);
        }
        return list;
    }

    public ExportDeal writeHandler(WriteHandler handler) {
        this.writeHandler = handler;
        return this;
    }

    private List<List<Object>> dataList(Map<String, ExportParamsDto> headMap, List<JSONObject> datas) {
        if (headMap == null) {
            return null;
        }
        Long start = System.currentTimeMillis();
        List<List<Object>> list = new ArrayList<>();
        for (JSONObject json : datas) {
            List<Object> objs = new ArrayList<>();
            for (ExportParamsDto param : headMap.values()) {
                Object obj = param == null ? null : json.get(param.getCloumn());
                if (obj != null && param.getDivideNum() != null) {
                    obj = new BigDecimal(obj.toString()).divide(param.getDivideNum(), 6, BigDecimal.ROUND_HALF_UP);
                }
                objs.add(obj);
            }
            list.add(objs);
        }
        log.info("耗时:{}", System.currentTimeMillis() - start);
        return list;
    }

    //错误信息
    public void error(String errorMsg, String fileName, HttpServletResponse response) throws Exception {
        sourName = sourName+"_"+fileName;
        //添加响应头信息
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        fileName = URLEncoder.encode(sourName, "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        this.fileName = fileName;
        excelWriter.writeContext().currentSheet(new WriteSheet(), WriteTypeEnum.FILL);
        List<List<Object>> datas = new ArrayList<>();
        datas.add(Arrays.asList(errorMsg));
        this.heads=null;
        loadData(datas, 0, "错误页");
    }

}

4.自定义样式

/**
 * @author hbj
 * @Date 2021/12/16 16:28
 * @Description
 * @Modified By
 */

public class StyleWriteHandler extends AbstractColumnWidthStyleStrategy {
    private static final int MAX_COLUMN_WIDTH = 255;
    private final Map<Integer, Map<Integer, Integer>> cache = MapUtils.newHashMapWithExpectedSize(8);

    private int maxCloumnWidth = 30;//自动适应宽最大值
    private Workbook workbook;
    private CellStyle headStyle;//头样式
    private CellStyle dataStyle;//数据样式

    private short headFontSize = 12;
    private short dataFontSize = 12;
    private boolean isAutoWidth = false;//自动适应宽

    @Override
    public void afterCellDispose(CellWriteHandlerContext context) {
        if (workbook == null) {
            // 拿到poi的workbook
            workbook = context.getWriteWorkbookHolder().getWorkbook();
            // 这里千万记住 想办法能复用的地方把他缓存起来 一个表格最多创建6W个样式
            // 不同单元格尽量传同一个 cellStyle

            //设置头样式
            if (context.getHead() && headStyle == null) {
                headStyle = workbook.createCellStyle();
                Font headFont = workbook.createFont();
                headFont.setFontHeightInPoints(headFontSize);
                headStyle.setFont(headFont);
            }
            //设置数据样式
            if (dataStyle == null) {
                dataStyle = workbook.createCellStyle();
                Font headFont = workbook.createFont();
                headFont.setFontHeightInPoints(dataFontSize);
                dataStyle.setFont(headFont);
            }
        }
        this.setColumnWidth(context);
    }

    @Override
    public void setColumnWidth(WriteSheetHolder writeSheetHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
        //设置自适应长度
        if (isHead || isAutoWidth) {
            /*int columnWidth = dataLength(cellDataList.get(0), cell, isHead);
            // 这里要把 WriteCellData的样式清空, 不然后面还有一个拦截器 FillStyleCellWriteHandler 默认会将 WriteCellStyle 设置到
            // cell里面去 会导致自己设置的不一样
            cellDataList.get(0).setWriteCellStyle(null);
            writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), columnWidth);*/
            autoWidth(writeSheetHolder, cellDataList, cell, isHead);
        }
        if (cell.getCellType().equals(CellType.BLANK)) {
            cell.setCellValue("");
        }
        if (isHead && headStyle != null) {
            cell.setCellStyle(headStyle);
        } else if (dataStyle != null) {
            cell.setCellStyle(dataStyle);
        }
    }

    private void autoWidth(WriteSheetHolder writeSheetHolder, List<WriteCellData<?>> cellDataList, Cell cell, boolean isHead) {
        Map<Integer, Integer> maxColumnWidthMap = (Map) this.cache.get(writeSheetHolder.getSheetNo());
        if (maxColumnWidthMap == null) {
            maxColumnWidthMap = new HashMap(16);
            this.cache.put(writeSheetHolder.getSheetNo(), maxColumnWidthMap);
        }

        Integer columnWidth = this.dataLength(cellDataList.get(0), cell, isHead);
        if (columnWidth >= 0) {
            if (columnWidth > maxCloumnWidth) {
                columnWidth = maxCloumnWidth;
            } else {
                columnWidth = columnWidth < 4 ? 4 : columnWidth;
                columnWidth = columnWidth + 1;
            }
            Integer maxColumnWidth = (Integer) ((Map) maxColumnWidthMap).get(cell.getColumnIndex());
            if (maxColumnWidth == null || columnWidth > maxColumnWidth) {
                ((Map) maxColumnWidthMap).put(cell.getColumnIndex(), columnWidth);
                cellDataList.get(0).setWriteCellStyle(null);
                writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), columnWidth * 256);
            }
        }
    }

    //获取单元格值长度
    private Integer dataLength(WriteCellData<?> cellData, Cell cell, Boolean isHead) {
        int columnWidth = 0;
        if (isHead) {
            columnWidth = cell.getStringCellValue().getBytes().length;
        } else {
            Object value;
            switch (cellData.getType()) {
                case NUMBER:
                    value = cellData.getNumberValue();
                    break;
                case STRING:
                    value = cellData.getStringValue();
                    break;
                case BOOLEAN:
                    value = cellData.getBooleanValue();
                    break;
                case DATE:
                    value = "yyyy-MM-dd HH:mm:ss";
                    break;
                case RICH_TEXT_STRING:
                    value = cellData.getRichTextStringDataValue();
                    break;
                default:
                    value = "";
            }
            columnWidth = value == null ? 0 : value.toString().length();
        }

        return columnWidth;
    }

    public void setHeadFontSize(short headFontSize) {
        this.headFontSize = headFontSize;
    }

    public void setDataFontSize(short dataFontSize) {
        this.dataFontSize = dataFontSize;
    }

    public void setmaxCloumnWidth(int maxCloumnWidth) {
        this.maxCloumnWidth = maxCloumnWidth;
    }

    public void setAutoWidth(boolean autoWidth) {
        isAutoWidth = autoWidth;
    }

    public StyleWriteHandler autoWidth(boolean autoWidth) {
        isAutoWidth = autoWidth;
        return this;
    }
}

5.调用controller

@PostMapping("/export")
    public Result export(@RequestBody ExportDto dto, HttpServletResponse response) throws Exception {
        if (dto.getTotal() == null) {
            return Result.failed("导出数量不能为空");
        }
        //最大导出10万
        if (dto.getTotal() > 10 * 10000) {
            dto.setTotal(10 * 10000L);
        }
        //表头map,key: 表头,value:字段
        LinkedHashMap<String, ExportParamsDto> headMap = new LinkedHashMap<>();
        dto.getExportParams().forEach(a -> headMap.put(a.getHeadName(), a));
        //创建表格
        ExportDeal deal = new ExportDeal(headMap, dto.getFileName(), response);
        //自动适应宽
        deal.writeHandler(new StyleWriteHandler().autoWidth(true));
        try {
            //录入数据
            Result result = deal.loadDataByHttp(dto, 0, "sheet");
            if (ResultCode.SUCCESS.getCode() != result.getCode()) {
                response.reset();
                deal.error(JSONObject.toJSONString(result), "导出失败", response);
            }
        } catch (Exception e) {
            log.error("导出【{}】报错:{}", dto.getFileName(), e);
            response.reset();
            deal.error(e.getMessage(), "导出失败", response);
            throw e;
        } finally {
            deal.close();
        }
        return null;
    }

6.http方法就不贴出来了,自己百度一个就好

使用EasyExcel导出Excel非常简单,只需要几个步骤即可: 1. 引入EasyExcel依赖 在`pom.xml`文件中加入EasyExcel的依赖: ```xml <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.2.10</version> </dependency> ``` 2. 编写导出Excel的实体类 例如,我们要导出一个学生的信息表格,可以先定义一个`Student`实体类: ```java @Data public class Student { @ExcelProperty("姓名") private String name; @ExcelProperty("班级") private String clazz; @ExcelProperty("分数") private Integer score; } ``` `@ExcelProperty`注解用于指定导出Excel时的列名。 3. 编写导出Excel的方法 在Controller中编写导出Excel的方法: ```java @GetMapping("/export") public void export(HttpServletResponse response) throws IOException { // 查询出所有学生信息 List<Student> students = studentService.list(); // 设置响应头 response.setContentType("application/vnd.ms-excel"); response.setCharacterEncoding("utf-8"); String fileName = URLEncoder.encode("学生信息表.xlsx", "UTF-8"); response.setHeader("Content-disposition", "attachment;filename=" + fileName); // 使用EasyExcel进行导出 EasyExcel.write(response.getOutputStream(), Student.class).sheet("学生信息").doWrite(students); } ``` 其中,`EasyExcel.write()`方法用于指定导出Excel文件的输出流和实体类类型,`sheet()`方法用于指定Excel文件的sheet名称,`doWrite()`方法用于执行导出操作。 4. 测试 启动应用程序,访问`/export`接口,即可下载导出Excel文件。 以上就是使用EasyExcel导出Excel的简单示例。需要注意的是,EasyExcel还支持导入Excel和大数据导入导出等功能,具体使用方法可参考官方文档。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值