赞
踩
Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams("日程主表", "日程"), AgendaExcelVO.class, agendaExcels);
其中ExportParams第一个参数是表名,第二个参数是sheet 名字, 第三个参数是需要生成表的实体类名, 第四个是数据集合!
最主要的是实体类的注解类型:
/** * @author allenj * @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 qiaomu@vichain.com * @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的解析方式,明显降低了内存,但是速率下降
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。