package com.ciics.cscloud.xinsurance.social.utils.excel;
import com.alibaba.excel.EasyExcel; import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.exception.ExcelAnalysisException; import com.alibaba.excel.util.StringUtils; import lombok.Data; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.util.CollectionUtils;
import javax.validation.ConstraintViolation; import javax.validation.Validation; import javax.validation.Validator; import javax.validation.ValidatorFactory; import java.io.InputStream; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.*; import java.util.stream.Collectors;
/**
-
@author cxy
-
@date 2020/12/28 9:46 */ @Slf4j public class ExcelUtil {
/**
- 导入Excel并做数据校验
- @param in Excel文件输入流
- @param t 返回对象的泛型
- @param businessValidator 业务校验的接口(自主去实现业务校验,比如:导入的用户是否已存在)
- @param sheetNumber 第几个sheet,从0开始
- @param headNumber 表头行号,从1开始
- @param headMap 表头描述,map的key是第几列(从0开始),value是表头第几列对应的内容,用来校验Excel格式,如果不传,则取返回实体@ExcelProperty的value属性做校验
- @param <T>
- @return */ public static <T extends BaseExcelDto> ImportResult importExcelAndValidate(InputStream in, T t, BusinessValidator businessValidator, int sheetNumber, int headNumber, Map<Integer, String> headMap) { ExcelModelListener<T> modelListener = new ExcelModelListener<>(headMap, t.getClass()); EasyExcel.read(in, t.getClass(), modelListener).sheet(sheetNumber).headRowNumber(headNumber).doRead(); ArrayList<T> successList = modelListener.successList; ImportResult result = businessValidator.validate(successList); if (result == null) { result = new ImportResult<>(); result.setFailedData(modelListener.failedList); result.setFailedMsg(modelListener.failedMsg); result.setSuccessData(successList); } else { if (!CollectionUtils.isEmpty(result.getFailedData())) { result.getFailedData().addAll(modelListener.failedList); result.getFailedMsg().addAll(modelListener.failedMsg); } else { result.setFailedMsg(modelListener.failedMsg); result.setFailedData(modelListener.failedList); } } return result; }
/**
-
Excel导入返回实体
-
@param <T> / @Data public static class ImportResult<T extends BaseExcelDto> { /*
- 导入状态,全部成功true,有失败几率false / private Boolean importStatus; /*
- 成功记录(校验合法的数据) / private List<T> successData; /*
- 校验不合法的数据 / private List<T> failedData; /*
- 错误信息 */ private List<String> failedMsg;
public Boolean getImportStatus() { return CollectionUtils.isEmpty(failedData); } }
/**
- excel基类,统一存储行号字段
- @param <T> */ @Data public static class BaseExcelDto<T> { private Integer rowNumber; }
/**
-
业务校验的接口
-
@param <T> */ public interface BusinessValidator<T extends BaseExcelDto> {
/**
- 业务校验(校验数据是否符合业务要求,比如;用户不能重复)
- @param excelData
- @return */ ImportResult<T> validate(List<T> excelData);
}
static class ExcelModelListener<T> extends AnalysisEventListener<T> { private Class classz; private final ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); private final Validator beanValidator = factory.getValidator(); private List<String> failedMsg; private Map<Integer, String> head; private static final String ERR_MSG = "第--%d--行"; private ArrayList<T> failedList = new ArrayList<>(); private ArrayList<T> successList = new ArrayList<>();
public ExcelModelListener(Map<Integer, String> headMap, Class c) { failedMsg = new ArrayList<>(); head = headMap; classz = c; } /** * 解析行数据时做必填校验 * * @param data * @param context */ @Override public void invoke(T data, AnalysisContext context) { int rouNumber = context.readRowHolder().getRowIndex() + 1; Method method = BeanUtils.findMethod(data.getClass(), "setRowNumber", Integer.class); if (null != method) { try { method.invoke(data, rouNumber); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } Set<ConstraintViolation<T>> violationSet = beanValidator.validate(data); if (!CollectionUtils.isEmpty(violationSet)) { List<String> messages = violationSet.stream().map(ConstraintViolation::getMessage).collect(Collectors.toList()); String join = org.apache.commons.lang3.StringUtils.join(messages, ","); failedMsg.add(String.format(ERR_MSG, rouNumber) + ":" + join); failedList.add(data); } else { successList.add(data); } } /** * 校验表头 * * @param headMap * @param context */ @SneakyThrows @Override public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) { if (null == head) { head = getIndexNameMap(classz); } if (CollectionUtils.isEmpty(head)) { return; } Set<Integer> keySet = head.keySet(); for (Integer key : keySet) { if (StringUtils.isEmpty(headMap.get(key))) { throw new ExcelAnalysisException("解析excel出错,请传入正确格式的excel"); } if (!headMap.get(key).equals(head.get(key))) { log.info(headMap.get(key)); log.info(head.get(key)); throw new ExcelAnalysisException("解析excel出错,请传入正确格式的excel"); } } } @Override public void doAfterAllAnalysed(AnalysisContext context) { log.info("导入完成!"); } public Map<Integer, String> getIndexNameMap(Class clazz) throws NoSuchFieldException { Map<Integer, String> result = new HashMap<>(); Field field; Field[] fields = clazz.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { field = clazz.getDeclaredField(fields[i].getName()); field.setAccessible(true); ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class); if (excelProperty != null) { int index = excelProperty.index(); String[] values = excelProperty.value(); StringBuilder value = new StringBuilder(); for (String v : values) { value.append(v); } result.put(index, value.toString()); } } return result; }
}
}
来源:oschina
链接:https://my.oschina.net/u/3116305/blog/4865728