EasyExcel填充web下载

一、前言

官网

在使用官网的填充功能的时候,个人感觉还是挺好用的。官网的web下载示例只给了最简单的写的对象让后进行导出。我的需求使用填充在下载,但是官网没给,这里看了下源码和API记录下如果填充Excel在进行web下载

官网示例代码

    /**
     * 文件下载(失败了会返回一个有部分数据的Excel)
     * <p>
     * 1. 创建excel对应的实体对象 参照{@link DownloadData}
     * <p>
     * 2. 设置返回的 参数
     * <p>
     * 3. 直接写,这里注意,finish的时候会自动关闭OutputStream,当然你外面再关闭流问题不大
     */
    @GetMapping("download")
    public void download(HttpServletResponse response) throws IOException {
        // 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        EasyExcel.write(response.getOutputStream(), DownloadData.class).sheet("模板").doWrite(data());
    }

二、实践

相关类

  • WriteWorkbook:可以理解成一个excel
  • ExcelWriter:用于Excel写入类
  • WriteSheet:理解成一个excel里面的一个表单
  • WriteTable:一个表单里面如果有多个实际用的表格,则可以用WriteTable

模板

在这里插入图片描述

导出

在这里插入图片描述

代码实践

   
    @PostMapping("/export/excel/test")
    @ApiOperation("test采购单excel")
    public void testExportExcel(HttpServletResponse response) throws IOException {
//第一步:申明需要用到的类
        ExcelWriter excelWriter = null;
        WriteSheet writeSheet = null;
        InputStream templatePathName = null;
        try {

//第二步:设置参数
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");


//第三步:设置文件名->这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String fileName = URLEncoder.encode("文件名", "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

//第四步:导出文件设置
// 模板注意 用{} 来表示你要用的变量 如果本来就有"{","}" 特殊字符 用"\{","\}"代替
// {} 代表普通变量 {.} 代表是list的变量
// 这里模板 删除了list以后的数据,也就是统计的这一行
// template/模板.xlsx在resource下面的
// 方案1
            templatePathName = this.getClass().getClassLoader().getResourceAsStream("template/采购订单模板.xlsx");
            ClassPathResource templateResource = new ClassPathResource("template/采购订单模板.xlsx");
            excelWriter = EasyExcel.write(response.getOutputStream())
                    .withTemplate(templatePathName)
                    //可以用.withTemplate(templateResource.getStream())代替.withTemplate(templatePathName)
                    .autoCloseStream(false)
                    // 大数值自动转换 防止失真
                    .registerConverter(new ExcelBigNumberConvert())//可有可无
                    .build();
            writeSheet = EasyExcel.writerSheet().build();


//第五步:加载需要填充的数据


            // 采购单信息
            List<PoDetailVo> list = new ArrayList<PoDetailVo>();
            PoDetailVo poDetailVo1 = new PoDetailVo();
            PoDetailVo poDetailVo2 = new PoDetailVo();
            PoDetailVo poDetailVo3 = new PoDetailVo();
            PoDetailVo poDetailVo4 = new PoDetailVo();
            PoDetailVo poDetailVo5 = new PoDetailVo();
            poDetailVo1.setOes("物料号1");
            poDetailVo1.setItemName("物料名称1");
            poDetailVo1.setBrand("品牌1");
            poDetailVo1.setModel("型号1");
            poDetailVo1.setFacTexture("质地1");
            poDetailVo1.setAssociatedZdBarcode("关联号1");
            poDetailVo1.setUnit("单位1");
            poDetailVo1.setQuantity(2);
            poDetailVo1.setUnitCost("1.00");
            poDetailVo1.setTotalCost("2.00");

            BeanUtils.copyProperties(poDetailVo1, poDetailVo2);
            BeanUtils.copyProperties(poDetailVo1, poDetailVo3);
            BeanUtils.copyProperties(poDetailVo1, poDetailVo4);
            BeanUtils.copyProperties(poDetailVo1, poDetailVo5);


            list.add(poDetailVo1);
            list.add(poDetailVo2);
            list.add(poDetailVo3);
            list.add(poDetailVo4);
            list.add(poDetailVo5);

            // 用于序号
            AtomicInteger count = new AtomicInteger(0);
            list.stream().forEach(item -> {
                item.setCount(count.incrementAndGet() + "");// 序号
            });


            excelWriter.fill(list, writeSheet);


            // 写入list之前的数据
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("vendorName", "供应商名称");
            map.put("repoName", "入库仓库");
            map.put("purNo", "采购单号");
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            map.put("createTime", format.format(new Date()));


            String userName = "测试18956415255";
            String name = userName.replaceAll("[^\u4e00-\u9fa5]*", "");
            String phone = StringUtils.substringAfter(userName, name);

            map.put("name", name);
            map.put("phone", phone);
            map.put("location","地点");


            excelWriter.fill(map, writeSheet);

            // list 后面还有个统计 想办法手动写入
            // 这里偷懒直接用list 也可以用对象

            double sum = list.stream().collect(Collectors.summingDouble(poDetailVo -> Double.parseDouble(poDetailVo.getTotalCost().replace(",",""))));

            BigDecimal bd = new BigDecimal(sum);
            sum = bd.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();


            List<List<String>> totalListList = ListUtils.newArrayList();
            List<String> totalList0 = ListUtils.newArrayList();
            List<String> totalList = ListUtils.newArrayList();
            List<String> totalList1 = ListUtils.newArrayList();
            totalListList.add(totalList0);
            totalListList.add(totalList);
            totalListList.add(totalList1);
            totalList.add(null);
            totalList.add("合计金额");
            totalList.add(sum + "");
            totalList.add("");



            totalList1.add(null);
            totalList1.add("合计金额大写");
            totalList1.add(NumberChineseFormatter.format(sum, true, true));
            totalList1.add("");
            // 这里是write 别和fill 搞错了
            excelWriter.write(totalListList, writeSheet);
            // 总体上写法比较复杂 但是也没有想到好的版本 异步的去写入excel 不支持行的删除和移动,也不支持备注这种的写入,所以也排除了可以
            // 新建一个 然后一点点复制过来的方案,最后导致list需要新增行的时候,后面的列的数据没法后移,后续会继续想想解决方案



        } catch (Exception e) {
            // 重置response
            response.reset();
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            Map<String, String> map = MapUtils.newHashMap();
            map.put("status", "failure");
            map.put("message", "下载文件失败" + e.getMessage());
            response.getWriter().println(JSON.toJSONString(map));
        } finally {
            if (excelWriter != null) {
                excelWriter.finish();
            }
            if (templatePathName != null) {
                templatePathName.close();
            }
        }
    }



import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;

@Slf4j
public class ExcelBigNumberConvert implements Converter<Long> {
 
    @Override
    public Class<Long> supportJavaTypeKey() {
        return Long.class;
    }
 
    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.STRING;
    }
 
    @Override
    public Long convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
        return Convert.toLong(cellData.getData());
    }
 
    @Override
    public WriteCellData<Object> convertToExcelData(Long object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
        if (ObjectUtil.isNotNull(object)) {
            String str = Convert.toStr(object);
            if (str.length() > 15) {
                return new WriteCellData<>(str);
            }
        }
        WriteCellData<Object> cellData = new WriteCellData<>(new BigDecimal(object));
        cellData.setType(CellDataTypeEnum.NUMBER);
        return cellData;
    }
 
}
import com.alibaba.fastjson.annotation.JSONField;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;

import java.math.BigDecimal;
import java.util.Date;

@Data
public class PoDetailVo {


    @ApiModelProperty(value = "序号")
    private String  count;

    @ApiModelProperty(value = "采购单明细主键ID")
    private Integer id;

    /**
     * 采购单ID(po.id)
     */
    @ApiModelProperty(value = "采购单ID(po.id)")
    private Integer poId;

    /**
     * 采购数量
     */
    @ApiModelProperty(value = "采购数量")
    private Integer quantity;

    /**
     * 待清点数量
     */
    @ApiModelProperty(value = "待清点数量")
    private Integer toCountQuantity;

    /**
     * 采购成本单价
     */
    @ApiModelProperty(value = "采购成本单价")
    private String unitCost;


    /**
     * 质地
     */
    @ApiModelProperty(value = "质地")
    private String facTexture;


    /**
     * 合计
     */
    @ApiModelProperty(value = "合计")
    private String totalCost;

    /**
     * 创建时间
     */
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JSONField(format= "yyyy-MM-dd HH:mm:ss")
    private Date createTime;

    /**
     * 创建人
     */
    private String createUser;

    /**
     * 更新时间
     */
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JSONField(format= "yyyy-MM-dd HH:mm:ss")
    private Date updateTime;

    /**
     * 更新人
     */
    private String updateUser;


    /**
     * 物料条码
     */
    @ApiModelProperty("物料条码")
    private String itemId;

    /**
     * 物料名称
     */
    @ApiModelProperty("物料名称")
    private String itemName;

    /**
     * 物料号
     */
    @ApiModelProperty("物料号")
    private String oes;

    /**
     * 型号
     */
    @ApiModelProperty("型号")
    private String model;

    /**
     * 品牌
     */
    @ApiModelProperty("品牌")
    private String brand;

    /**
     * 单位
     */
    @ApiModelProperty("单位")
    private String unit;

    /**
     * 关联正大条码
     */
    @ApiModelProperty("关联码")
    private String associatedZdBarcode;
}

完结撒花!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

代码浪人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值