一、前言
在使用官网的填充功能的时候,个人感觉还是挺好用的。官网的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;
}
完结撒花!!!