Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams("日程主表", "日程"), AgendaExcelVO.class, agendaExcels);
其中ExportParams第一个参数是表名,第二个参数是sheet 名字, 第三个参数是需要生成表的实体类名, 第四个是数据集合!
最主要的是实体类的注解类型:
/**
* @author [email protected]
* @date 2019/6/3
*/
public class AgendaExcelVO {
/**
* 主键
*/
private Long id;
/**
* 企业主键
*/
@Excel(name = "entId")
private Long entId;
/**
* 客户经理主键
*/
@Excel(name = "用户id")
private Long userId;
/**
* 主题
*/
@Excel(name = "主题")
private String topic;
/**
* 开始时间
*/
@Excel(name = "开始时间")
private Date startTime;
/**
* 结束时间
*/
@Excel(name = "结束时间", databaseFormat = "yyyyMMddHHmmss", format = "yyyy-MM-dd")
private Date endTime;
/**
* 描述
*/
@Excel(name = "描述")
private String description;
需要生成的字段上面加上@Excel注解, 时间格式化用format ,这里有一个注意点,如果实体类格式是LocalDateTime,format格式化不会生效;
导出时间设置databaseFormat,如果字段是Date类型则不需要设置 数据库如果是string 类型,这个需要设置这个数据库格式,用以转换时间格式输出.
public static Workbook exportExcel(ExportParams entity, Class<?> pojoClass,
Collection<?> dataSet) {
Workbook workbook = getWorkbook(entity.getType(),dataSet.size());
new ExcelExportService().createSheet(workbook, entity, pojoClass, dataSet);
return workbook;
}
private static Workbook getWorkbook(ExcelType type, int size) {
if (ExcelType.HSSF.equals(type)) {
return new HSSFWorkbook();
} else if (size < 100000) {
return new XSSFWorkbook();
} else {
return new SXSSFWorkbook();
}
}
数据较少时,默认导出格式为xls,数据量超过100000,格式变成xlsx. 也可以根据需要自己写一个导出方法.自己放入参数
不校验时导入只需要一行代码
ExcelImportUtil.importExcel(new File("E://bbbb.xls"), AgendaExcelVO.class, params);
但是往往业务需要我们去校验导入的数据
params.setNeedVerify(true);
实体类就可以加上注解对参数进行校验
/**
* 最大
*/
@Excel(name = "Max")
@Max(value = 15,message = "max 最大值不能超过15" ,groups = {ViliGroupOne.class})
private int max;
/**
* 最小
*/
@Excel(name = "Min")
@Min(value = 3, groups = {ViliGroupTwo.class})
private int min;
/**
* 非空校验
*/
@Excel(name = "NotNull")
@NotNull
private String notNull;
/**
* 正则校验
*/
@Excel(name = "Regex")
@Pattern(regexp = "[\u4E00-\u9FA5]*", message = "不是中文")
private String regex;
@Max,@Min,@NotNull,最大最小非空校验
@Pattern校验规则都是JSR 303 的,使用方式也是的
加入校验之后会返回一个ExcelImportResult 对象,比我们平时返回的list多了一些元素
public class ExcelImportResult<T> {
/**
* 结果集
*/
private List<T> list;
/**
* 失败数据
*/
private List<T> failList;
/**
* 是否存在校验失败
*/
private boolean verfiyFail;
/**
* 数据源
*/
private Workbook workbook;
/**
* 失败的数据源
*/
private Workbook failWorkbook;
private Map<String,Object> map;
}
结果包含结果集,不符合校验规则的数据集.
但是如果想同时得到全部结果集就要把实体类实现IExcelModel 接口,这样就可以返回全部结果集了.
查看源码发现excelpoi强制把workbook分成两个workbook,一个失败的一个是成功的,
if (needMore) {
InputStream successIs = new ByteArrayInputStream(baos.toByteArray());
try {
Workbook successBook = WorkbookFactory.create(successIs);
importResult.setWorkbook(removeSuperfluousRows(successBook, failRow, params));
importResult.setFailWorkbook(removeSuperfluousRows(book, successRow, params));
importResult.setFailList(failCollection);
importResult.setVerfiyFail(verifyFail);
} finally {
successIs.close();
}
}
所以如果想在一个workbook里面看到成功或者失败的信息只能自己手动重新生成一个workbook
try (OutputStream out = new FileOutputStream("E://alibaba.xlsx")) {
ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX);
Sheet sheet = new Sheet(1, 0, PortExcelVO.class);
writer.write(portExcelVOList, sheet);
writer.finish();
} catch (Exception e) {
e.printStackTrace();
}
实体类注解
@ExcelProperty(value = "id", index = 0)
private Long id;
/**
* 港口代码
*/
@ExcelProperty(value = "港口代码", index = 1)
private String code;
/**
* 地区
*/
@ExcelProperty(value = "地区", index = 2)
private Long regionId;
/**
* 港口类型
*/
@ExcelProperty(value = "港口类型", index = 3)
private Long type;
/**
* 名称
*/
@ExcelProperty(value = "名称", index = 4)
private String name;
/**
* 拼音全称
*/
@ExcelProperty(value = "拼音全称", index = 5)
private String namePinyin;
/**
* 拼音缩写
*/
@ExcelProperty(value = "拼音缩写", index = 6)
private String pinyinAbbreviate;
/**
* 英文名称
*/
@ExcelProperty(value = "英文名称", index = 7)
private String nameEn;
这里的value代表的是表头, index代表的excel列位置,从0开始
easyexcel 有一个抽象类
public abstract class AnalysisEventListener<T> {
public AnalysisEventListener() {
}
public abstract void invoke(T var1, AnalysisContext var2);
public abstract void doAfterAllAnalysed(AnalysisContext var1);
}
里面有两个抽象方法 分别是invoke和doAfterAllAnalysed.
每次扫描一行数据就会回调invoke() 全部扫描结束就会调用doAfterAllAnalysed()
所以我们先写一个类继承AnalysisEventListener
/**
* @author [email protected]
* @date 2019/6/5
*/
public class ExcelListener extends AnalysisEventListener<PortExcelVO> {
private boolean isFail = false;
public boolean isFail() {
return isFail;
}
public ExcelListener setFail(boolean fail) {
isFail = fail;
return this;
}
private List<PortExcelVO> portExcelVOList = new ArrayList<>();
public List<PortExcelVO> getPortExcelVOList() {
return portExcelVOList;
}
public ExcelListener setPortExcelVOList(List<PortExcelVO> portExcelVOList) {
this.portExcelVOList = portExcelVOList;
return this;
}
@Override
public void invoke(PortExcelVO portExcelVO, AnalysisContext analysisContext) {
System.out.println("portExcelVO::::::::::::::" + portExcelVO);
Integer currentRowNum = analysisContext.getCurrentRowNum();
System.out.println("当前行:::" + currentRowNum);
// 1.校验参数,不符合条件插入新数据 isFail设置为true
StringBuilder failReason = new StringBuilder();
// 自定义逻辑
if (portExcelVO.getType() == 1) {
failReason.append("Type cannot equals one;");
setFail(true);
}
if (portExcelVO.getName().equals("主港")) {
failReason.append("名字是主港");
setFail(true);
}
// 放入集合
if (isFail) {
portExcelVO.setFailReason(failReason.toString());
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
// 如果有错误数据就导出excel表格
if (isFail) {
// 导出表格
exportExcel(portExcelVOList);
} else {
// 导入数据库
importDataBase(portExcelVOList);
}
// 销毁不用资源,设置isFail为false
portExcelVOList.clear();
setFail(false);
}
private void exportExcel(List<PortExcelVO> portExcelVOList) {
System.out.println("++++++++++++++++++++++导出数据");
ExportExcelUtil.exportEasyExcel(portExcelVOList);
}
private void importDataBase(List<PortExcelVO> portExcelVOList) {
// TODO
System.out.println("++++++++++++++++++++++++++++++++++++++导入数据库");
}
}
然后我们实例化这个对象, 就可以按照我们的逻辑导入数据了
导入代码如下
try (InputStream inputStream = new FileInputStream("E://alibaba.xlsx")) {
// 解析每行结果在listener中处理
ExcelListener listener = new ExcelListener();
ExcelReader excelReader = new ExcelReader(inputStream, ExcelTypeEnum.XLSX, null, listener);
excelReader.read();
} catch (Exception e) {
e.printStackTrace();
}
easyPoi导出2000条数据好事324毫秒
easyExcel耗时608毫秒
对一个接口同时点击多次内存占用对比可以看出easyExcel内存明显较小
从easypoi和easyExcel 的 源码
这两者都是引用Apache的poi 但是区别就是两者的解析不同
easypoi的解析方式是dom解析,把结果一次都读入内存操作,这样的操作平时是不会有问题的,但是并发量上来的时候就会出现OOM
而阿里的easyExcel 运用的SAX的解析方式,明显降低了内存,但是速率下降