java——easyExcel导出表格浏览器下载

Java SpringBoot使用easyExcel,浏览器下载

简单title向下补充表格

like this

创建一个data类(CargoRightsExcelData),定义每一列需要导出的字段

package com.zmy.agency.cargo.data;

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import lombok.Data;

@Data
public class CargoRightsExcelData {
    // 列宽
    @ColumnWidth(24)
    // 列的标题
    @ExcelProperty({" "})
    // 字段数据
    private String category;

    @ColumnWidth(18)
    @ExcelProperty({"在途", "立方数"})
    private Double onWayQuantity;

    。。。。。。

    @ColumnWidth(18)
    @ExcelProperty({"合计", "立方米"})
    private Double sumQuantity;

    @ColumnWidth(18)
    @ExcelProperty({"合计", "金额"})
    private Double sumAmount;

}

路由层

/**
     * Controller文件
     * excel导出
 */
// 正常应该用GET请求,我这里需要传的是一个对象,所以用了POST请求
@PostMapping(value = "/excel")
public void statisticsExcel(HttpServletResponse response, @RequestBody CargoRightsStatisticsDto cargoRightsDto) throws UnsupportedEncodingException {
    if (cargoRightsDto.getCargoRights() != null || cargoRightsDto.getCargoRights().length > 0) {
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = URLEncoder.encode(DateUtil.getCurrentDateTimeStr() + "货权统计表", "UTF-8").replaceAll("\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xls");
        // 填充数据
        marketPriceService.exportExcel(response, cargoRightsDto);
    }
}

服务impl层

@Override
public JsonResult exportExcel(HttpServletResponse response, CargoRightsStatisticsDto cargoRights) {
    JsonResult result = new JsonResult();
    result.setCode(200);
    try {
        // 拿到需要导出的数据,根据自己的业务逻辑自行编写
        List<Map<String, Object>> datas = cargoStatisticsWhole(cargoRights);
        // 初始化前面定义的data类为一个数组
        List<CargoRightsExcelData> cargoRightsExcelDataList = new ArrayList<>();
        // 开始填充data
        for (Map<String, Object> data: datas) {
            CargoRightsExcelData cargoRightsExcelData = new CargoRightsExcelData();

            String keyName =  data.get("name") == null ? "未定义" : (String) data.get("name");
            String name = "    ".repeat((int) data.get("deep")) + keyName;

            cargoRightsExcelData.setCategory(name);
            cargoRightsExcelData.setOnWayQuantity((Double) data.get("on_way_quantity"));
            cargoRightsExcelData.setOnWayAmount((Double) data.get("on_way_amount"));
            cargoRightsExcelData.setStockQuantity((Double) data.get("stock_quantity"));
            cargoRightsExcelData.setStockAmount((Double) data.get("stock_amount"));
            cargoRightsExcelData.setSumQuantity((Double) data.get("sum_quantity"));
            cargoRightsExcelData.setSumAmount((Double) data.get("sum_amount"));

            cargoRightsExcelDataList.add(cargoRightsExcelData);
        // 写入easyExcel流,在这一步,其实表格就已经生成了
        EasyExcel.write(
                response.getOutputStream(),
                CargoRightsExcelData.class
        ).sheet("货权统计").doWrite(cargoRightsExcelDataList);
        return result;
    } catch (IOException e) {
        result.setCode(406);
        result.setMessage(e.getMessage());
        return result;
    }
}

复杂的模板填充

这也是我特别想记录的
首先,我也是参考别的代码在做
查阅到这一片时,EasyExcel模板填充踩坑, 给我留下的印象就是导出辅助data类,不能用驼峰法
查阅到这一片时,easyExcel使用模板填充式的导出,我照着写了一下
比较有意思的一点就是,两篇,我都只看见了map数据,没有看到初始化辅助data那一行代码(我没注意看,所以我的代码没用到辅助data类,但是,我是写完了,生效了,才发现没用上的,哈啊哈)
所以我的完成过程如下

先准备一个excel导出模板

行数据要用x.字段命名

路由层

/**
     * Controller文件
     * 导出出入库单据的表格
 */
@GetMapping(value = "/out-in-excel/{id}")
public JsonResult outInExcel(@PathVariable("id") String id, HttpServletResponse response) throws IOException {
    if (StringUtils.isBlank(id)){
        return JsonResult.error("ID未找到!");
    }
    OrderRecord order = orderRecordService.getById(id);
    if (order == null) {
        return JsonResult.error("ID未找到!");
    }
    String fileName;
    if ("inStock".equals(order.getType())) {
        fileName = "入库通知单_" + DateUtil.getCurrentDateTimeStr();
    } else if ("outStock".equals(order.getType())) {
        fileName = "出库通知单_" + DateUtil.getCurrentDateTimeStr();
    } else {
        return JsonResult.error("错误的数据类型");
    }
    // 定义文件流
    response.setContentType("application/vnd.ms-excel");
    response.setCharacterEncoding("utf-8");
    String excelFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8).replaceAll("\+", "%20");
    // excelFileName: 文件名
    response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + excelFileName + ".xls");
    OutputStream outputStream = response.getOutputStream();
    // 将id和outputStream文件流传入服务层
    JsonResult result = orderRecordService.outInExcelById(id, outputStream);
    return result;
}

服务层impl

@Override
    public JsonResult outInExcelById(String id, OutputStream outputStream) {
    // 定义在报错情况下返回的内容
    JsonResult result = new JsonResult();
    result.setCode(200);
    // 拿到需要导出的数据,根据你的业务需求自行处理
    OrderRecord order = baseMapper.selectById(id);

    try {
        // 定位模板文件的base位置
        String basePath = PathKit.getWebRootPath() + File.separator + "src" + File.separator + "main" + File.separator + "resources" + File.separator;
        // 定位模板文件的最终位置
        String templateName;
        Map<String, Object> data = new HashMap<>();
        if ("inStock".equals(order.getType())) {
            templateName = basePath + "templates/in_order_template.xls";
        } else if ("outStock".equals(order.getType())) {
            templateName = basePath + "templates/out_order_template.xls";
        } else {
            return JsonResult.error("错误的数据类型");
        }
        // outputStream文件流写入EasyExcel,使用withTemplate方法调用模板(参数就是模板文件的路径)
        ExcelWriter excelWriter = EasyExcel.write(outputStream).withTemplate(templateName).build();
        // 创建一个页签
        WriteSheet writeSheet = EasyExcel.writerSheet().build();

        // 写入数据,这里就是只会出现一次的数据
        data.put("local_date", order.getOrderDate().toString());
        data.put("code", order.getCode());
        data.put("custody_display", order.getCustodyDisplay());
        data.put("storehouse_display", order.getStorehouseDisplay());
        data.put("stockist_display", order.getStockistDisplay());
        data.put("pick_up_display", order.getPickUpDisplay());

        // 这里定义一个自动填充需要遍历的表格类| NewRow(Boolean.TRUE) 自动换行
        FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
        /**
         * 这里比较有意思的  就是,因为第一篇博客的影响,我给表格的字段使用的都是下划线的形式,但是我的数据都是驼峰的形式
         * 导致我的数据写不进去,这时我才意识到我写的辅助data类没有到用到,但是我并不想研究怎么用,我就死马当做活马医,
         * 试一下我直接在模板里面改成驼峰命名看能不能生效,于是乎,it`s work!
         */
        // 设置自动遍历填充,a的取值内容为order.getOrderRecordLines(),这是一个O2M字段的数据
        excelWriter.fill(new FillWrapper("a", order.getOrderRecordLines()), fillConfig, writeSheet);
        // 将data的数据完整填充进excelWriter
        excelWriter.fill(data, writeSheet);
        // 关闭文件流
        excelWriter.finish();

        return result;
    } catch (Exception e) {
        return JsonResult.error(e.toString());
    }
}

结论

成功了!

回过头我真的很好奇我没有用到辅助data类,就又倒回去查看前面的博客
这一片是定义一个不变的map数据,一个是需要便利的数据结合我的代码可以得出结论

可变的遍历数据,如果模板的取值和我的数据一致,可以不用定义辅助data类,Nice!

似乎,我能这样写,还得益于,我的模型定义,外键关联我都会再定义一个显示字段的缘故。
like this:

    /**
     * 存货方
     */
    private String stockistId;

    /**
     * 存货方Display
     */
    @TableField(exist = false)
    private String stockistDisplay;

    /**
     * 指定仓库
     */
    private String storehouseId;

    /**
     * 指定仓库Display
     */
    @TableField(exist = false)
    private String storehouseDisplay;

还有一个弊端:如果你取出来的数据还需要处理,要么你再在数据层定义一个字段,要么就只能老老实实写辅助data类,先给data辅助,再将data赋值给excelWriter

easyexcel官网

原文地址:https://www.cnblogs.com/pywjh/p/15033659.html