需求
实现报表数据的导入导出,表格中部分数据是系统生成,部分数据是甲方填写,录入系统。
批号唯一
Maven
XML
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.3.2</version>
</dependency>
导出
看到网上都是创建自定义WriteHandler。略麻烦,可以用注解实现。
导出Bean,(bean就不给全了,涉及工艺),合并的单元格是列9,列10
java
@Data
@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER,verticalAlignment = VerticalAlignmentEnum.CENTER)
@NoArgsConstructor
@AllArgsConstructor
public class ProductOne {
@ContentLoopMerge(eachRow = 2)
@ExcelProperty(value = {"批号", "批号", "批号", "批号"},index = 0)
@ColumnWidth(20)
private String column1;
@ContentLoopMerge(eachRow = 2)
@ExcelProperty(value = {"API放行标准", "API放行标准", "API放行标准", "API放行标准"},index = 1)
private String column2;
@ContentLoopMerge(eachRow = 2)
@ExcelProperty(value = {"盘库月份", "盘库月份", "盘库月份", "盘库月份"},index = 2)
private String column3;
@ContentLoopMerge(eachRow = 2)
@ExcelProperty(value = {"生产进度", "生产进度", "生产进度", "生产进度"},index = 3)
private String column4;
@ContentLoopMerge(eachRow = 2)
@ExcelProperty(value = {"生产偏差/变更", "生产偏差/变更", "生产偏差/变更", "生产偏差/变更"},index = 4)
private String column5;
@ContentLoopMerge(eachRow = 2)
@ExcelProperty(value = {"成品入库数量/kg", "成品入库数量/kg", "成品入库数量/kg", "成品入库数量/kg"},index = 5)
private String column6;
@ContentLoopMerge(eachRow = 2)
@ExcelProperty(value = {"投料开始时间", "投料开始时间", "投料开始时间", "投料开始时间"},index = 6)
private String column7;
@ContentLoopMerge(eachRow = 2)
@ExcelProperty(value = {"工序1:溶解脱色", "投料", "粗品数量(kg)", "M"},index = 7)
private String column8;
@ExcelProperty(value = {"工序1:溶解脱色", "投料", "精品二次结晶物数量(kg)", "/"},index = 8)
private String column9;
@ExcelProperty(value = {"工序1:溶解脱色", "投料", "精品二次结晶物批号", " / "},index = 9)
@ColumnWidth(20)
private String column10;
public ProductOne(ReportProductOne bean) {
this.column1 = bean.getColumn1();
this.column2 = bean.getColumn2();
this.column3 = bean.getColumn3();
this.column4 = bean.getColumn4();
this.column5 = bean.getColumn5();
this.column6 = bean.getColumn6();
this.column7 = bean.getColumn7();
this.column8 = bean.getColumn8();
this.column9 = bean.getColumn9One();
this.column10 = bean.getColumn10One();
}
@ContentLoopMerge(eachRow = 2) ,此注解每2行合并。loop可循环。
@OnceAbsoluteMerge 用于合并一次
下图中每个注解都非常好用
@ContentStyle ,用于正文样式,我这边上下左右都居中
数据库中,存储对象bean
java
public class ReportProductOne extends Model<ReportProductOne> {
@TableId(type = IdType.AUTO)
private Integer id;
private String column1;
private String column2;
private String column3;
private String column4;
private String column5;
private String column6;
private String column7;
private String column8;
private String column9One;
private String column9Two;
private String column10One;
private String column10Two;
private Date createTime;
public ReportProductOne(ProductOne productOne, String column9, String column10) {
this.column1 = productOne.getColumn1();
this.column2 = productOne.getColumn2();
this.column3 = productOne.getColumn3();
this.column4 = productOne.getColumn4();
this.column5 = productOne.getColumn5();
this.column6 = productOne.getColumn6();
this.column7 = productOne.getColumn7();
this.column8 = productOne.getColumn8();
this.column9One = productOne.getColumn9();
this.column10One = productOne.getColumn10();
this.column9Two = column9;
this.column10Two = column10;
}
由此可以看出,对于批号,列9,列10。拆分的单元格也是一对一关系。
导出Controller
java
@Operation(summary = "导出")
@GetMapping("export2")
public void export2(HttpServletResponse response) {
List<ReportProductOne> list = reportProductOneService.list();
List<ProductOne> result = new ArrayList<>(32);
for (ReportProductOne reportProductOne : list) {
ProductOne bean1 = new ProductOne(reportProductOne);
ProductOne bean2 = BeanUtil.copyProperties(bean1, ProductOne.class);
bean2.setColumn9(reportProductOne.getColumn9Two());
bean2.setColumn10(reportProductOne.getColumn10Two());
result.add(bean1);
result.add(bean2);
}
try {
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
response.setHeader("Content-disposition", "attachment;filename=test.xlsx");
EasyExcel.write(response.getOutputStream(), ProductOne.class).autoCloseStream(Boolean.FALSE).sheet("Sheet 0")
.doWrite(result);
} catch (IOException e) {
e.printStackTrace();
}
}
以上bean2,其实也可以new一个,然后set列9 和列10。在导出的情况下根本没有区别,但是导入的时候会有。
导入
导入demo
导入Controller
java
@Operation(summary = "批量导入")
@PostMapping("import")
public R userBatchImport(MultipartFile file){
String originalFilename = file.getOriginalFilename();
String suffixName = originalFilename.substring(originalFilename.lastIndexOf("."));
if(!AuthConstant.SUFFIX_FILE_NAME.equals(suffixName)){
return failed("文件格式不符合");
}
try {
EasyExcel.read(file.getInputStream(),ProductOne.class,productOneImportBatchListener).headRowNumber(4).sheet().doRead();
} catch (Exception e) {
productOneImportBatchListener.clear();
return failed(e.getMessage());
}
return success("success");
}
ReadListener
java
public class ProductOneImportBatchListener extends AnalysisEventListener<ProductOne> {
List<ProductOne> cache = new ArrayList<>(16);
@Override
public void invoke(ProductOne bean, AnalysisContext analysisContext) {
if(cache.size() % 2 == 0 && StrUtil.isEmpty(bean.getColumn1())) {
throw new ExcelAnalysisException("批号必填或格式有误");
}
if(cache.size() % 2 == 0) {
//判断批号是否存在,不存在throw
}
System.out.println(bean);
cache.add(bean);
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
if(cache.size() % 2 != 0) {
throw new ExcelAnalysisException("文档格式有误");
}
List<ReportProductOne> list = new ArrayList<>(32);
//奇数行,都有批号
for (int i = 0; i < cache.size(); i+=2) {
ReportProductOne temp = new ReportProductOne(cache.get(i),cache.get(i+1).getColumn9(),cache.get(i+1).getColumn10());
list.add(temp);
}
log.info("插入完成:共"+ list.size()+"条");
clear();
}
public void clear(){
cache.clear();
}
}
解析数据
总结
虽然合并单元格,但是读取还是有2行。
如果是上面导出模板,那么导入的时候,2行在合并单元格列都能读取到数据。
如果是新增的情况,那么只有在首行能读取到导入的合并单元格数据。介于一对一关系这边忽略。非一对一可参考
如果在导出的情况下修改,那么合并单元格也只能首行能读取到数据。