导入excel时,共通校验数据是否为空,长度等

项目在做导入时,每个模块的导入都要写数据校验,这样抽出共通比较方便且代码复用率高

@PostMapping("/import")
public AjaxResult importAnalysis(MultipartFile file) {
	try {
		//异步操作
//            BaseDataListener dataListener = new BaseDataListener<IBbbApplication>(iBbbApplication, "importBbb", 2000);
//            EasyExcel.read(file.getInputStream(),
//                    SpecialEquipmentTemp.class,
//                    dataListener
//            ).sheet().doRead();

		//EasyExcel支持对实体类的属性进行注解,方便后续进行读写操作
		List<BbbTemp> objects = EasyExcel.read(file.getInputStream()).head(BbbTemp.class).sheet().doReadSync();
		//处理校验
		List<String> emsg = ExcelUtil.doValidate(objects);
		if (emsg.size() > 0) {
			return new AjaxResult().message("1", JSON.toJSONString(emsg));
		} else {
			//处理业务数据
			List<String> result = iBbbApplication.import(objects);
			if (result.size() > 0) {
				return new AjaxResult().message("1", JSON.toJSONString(result));
			}else {
				return new AjaxResult().success("保存成功");
			}
		}
	} catch (Exception e) {
		return error("导入失败");
	} finally {

	}
}

共同类

public class ExcelUtil {

    public static String validate(@Valid Object data, int rowNum) {
        Set<ConstraintViolation<Object>> validate = Validation.buildDefaultValidatorFactory()
                .getValidator()
                .validate(data, new Class[0]);
        if (CollectionUtils.isNotEmpty(validate)) {

            StringBuilder msg = new StringBuilder();
            msg.append("第" + (rowNum + 2) + "行: ");
            for (ConstraintViolation<Object> cv : validate) {
                msg.append(cv.getMessage()).append(",");
            }
            msg.delete(msg.length() - 1, msg.length());
            return msg.toString();
        }
        return null;
    }

    public static List<String> doValidate(List datas) {

        StringBuilder msg = new StringBuilder();
        List<Object> list = new ArrayList<>();
        List<String> errorMsgs = new ArrayList<>();
        datas.stream().forEach(item -> {
            int i = datas.indexOf(item);
            String strings = validate(item, i);
            if (strings != null) {
                errorMsgs.add(strings);
            }
            if (!list.contains(item)) {
                list.add(item);
            } else {
                msg.append("第" + (i + 3) + "行: 数据与之前数据重复");
                errorMsgs.add(msg.toString());
            }
        });
        return errorMsgs;
    }
}

异步的话需要个监听类 防止数据量大导致OOM

public class BaseDataListener<T> extends AnalysisEventListener<T> {

    private static final Logger LOGGER = LoggerFactory.getLogger(BaseDataListener.class);
    /**
     * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收
     */
    private int batchCount = 100;
    List<T> list = new ArrayList<T>();
    private Object dataService;
    private String methodName;

    /**
     * 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。
     */
    public BaseDataListener() {
        // 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数
    }

    /**
     * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
     */
    public BaseDataListener(Object object, String methodName, int size) {
        this.dataService = object;
        this.methodName = methodName;
        this.batchCount = size;
    }

    public BaseDataListener(Object object, String methodName) {
        this(object, methodName, 100);
    }

    /**
     * 这个每一条数据解析都会来调用
     *
     * @param data    one row value. Is is same as {@link AnalysisContext#readRowHolder()}
     * @param context
     */
    @Override
    public void invoke(T data, AnalysisContext context) {
        LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data));
        String msg = ExcelUtil.validate(data, context.readRowHolder().getRowIndex());
        if (msg != null) {
            list.add(data);
            // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
            if (list.size() >= batchCount) {
                saveData();
                // 存储完成清理 list
                list.clear();
            }
        }

    }

    /**
     * 所有数据解析完成了 都会来调用
     *
     * @param context
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 这里也要保存数据,确保最后遗留的数据也存储到数据库
        LOGGER.info("所有数据解析完成!");
        saveData();
    }

    /**
     * 加上存储数据库
     */
    private void saveData() {
        LOGGER.info("{}条数据,开始存储数据库!", list.size());
        Class<?> clz = dataService.getClass();
        try {
            Method method = clz.getMethod(methodName, List.class);
            method.invoke(dataService, list);
        } catch (NoSuchMethodException e) {
            LOGGER.error("未在服务类内找到{}方法", methodName);
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        LOGGER.info("存储数据库成功!");
    }


}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值