Apache POI 报表导入工具类

这是进公司接受的第二个项目,在我将项目改造成springBoot项目时竟然发现同事写的导入方法竟然高达上前行,而且其他导入方法行数都是大几百行往上。难怪我下班后他还经常加班 = . =。这个整个的流程其实就是:
1、扫描@ExcelChecker 注解标记的类。
2、注册到ExcelCkeckerFactory中。
3、ExcelUtils拿到检测类list,检测并将通过的加入到返回list

下面是人员信息的导入
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

这个人员信息的导入方法高达1100多行,还有一些其他导入方法差不多类似。方法中含有大量if else以及Cell取值没有封装,导致大量重复代码的出现,后期十分难以维护,我看到这些代码头都大了。我不能让这些代码出现在我的项目中(我经过领导同意将这个项目重新搭建,改为了springboot单体服务项目),所以对这些令人头痛的代码进行了改造,下面是我改造的步骤。

1.定义注解

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({ExcelCheckerAutoConfigureRegistrar.class})
public @interface ExcelCheckerScan {
    @AliasFor("basePackages") String[] value() default {};

    @AliasFor("value") String[] basePackages() default {};

    Class<?>[] basePackageClasses() default {};
}

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ExcelChecker {
    String prefix() default "";
    String[] field();
    int order();
}

1、@ExcelCheckerScan 注解用来扫描包下面包含@ExcelChecker 注解的类,上面的@Import注解功能就是和Spring XML 里面 的 一样. @Import注解是用来导入配置类或者一些需要前置加载的类。
2、@ExcelChecker是用来标注检测类。

定义 ImportBeanDefinitionRegistrar动态注册bean

public class ExcelCheckerAutoConfigureRegistrar
        implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {

    private ResourceLoader resourceLoader;

    private Environment environment;

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        MetaBeanDefinitionScanner scanner =
                new MetaBeanDefinitionScanner(registry, true,this.environment, this.resourceLoader);
        Set<String> packagesToScan = this.getPackagesToScan(importingClassMetadata);
        scanner.scan(packagesToScan.toArray(new String[]{}));
    }

    private static class MetaBeanDefinitionScanner extends ClassPathBeanDefinitionScanner {
        public MetaBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
                                         Environment environment, ResourceLoader resourceLoader) {
            super(registry, useDefaultFilters, environment, resourceLoader);
            registerFilters();
        }

        protected void registerFilters() {
            addIncludeFilter(new AnnotationTypeFilter(ExcelChecker.class));
        }
    }

    private Set<String> getPackagesToScan(AnnotationMetadata metadata) {
        AnnotationAttributes attributes =
                AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(ExcelCheckerScan.class.getName()));
        String[] basePackages = attributes.getStringArray("basePackages");
        Class<?>[] basePackageClasses = attributes.getClassArray("basePackageClasses");

        Set<String> packagesToScan = new LinkedHashSet<>(Arrays.asList(basePackages));
        for (Class clz : basePackageClasses) {
            packagesToScan.add(ClassUtils.getPackageName(clz));
        }

        if (packagesToScan.isEmpty()) {
            packagesToScan.add(ClassUtils.getPackageName(metadata.getClassName()));
        }

        return packagesToScan;
    }
}

在这里插入图片描述

简介

  1. ImportBeanDefinitionRegistrar类只能通过其他类@Import的方式来加载,通常是启动类或配置类。
  2. 使用@Import,如果括号中的类是ImportBeanDefinitionRegistrar的实现类,则会调用接口方法,将其中要注册的类注册成bean。
  3. 实现该接口的类拥有注册bean的能力。

@ExcelCheckerScan注解配合ExcelCheckerAutoConfigureRegistrar类会将所有包下包含@ExcelChecker 注解的类注册到Spring容器之中。





定义ExcelCkeckerFactory

@Component
public class ExcelCkeckerFactory  implements ApplicationListener, ApplicationContextAware {
    private ApplicationContext applicationContext;
    //检测类MAP <属性名,检测类List>  因为同一个属性可以有多个检测
    private Map<String, List<BaseExcelCellChecker>> map = new ConcurrentHashMap();

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
        //这里从Spring容器中取出所有包含@ExcelChecker的检测类。 上面的ExcelCheckerAutoConfigureRegistrar已经将所有检测类注册到容器中,这里直接取出来就好了。
        Map<String,Object> beanWhithAnnotation = applicationContext.getBeansWithAnnotation(ExcelChecker.class);
        TreeMap<Integer,List<BaseExcelCellChecker>> orderMap = new TreeMap<Integer,List<BaseExcelCellChecker>>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2.compareTo(o1);
            }
        });

        beanWhithAnnotation.forEach((k,v)->{
        	/**只有BaseExcelCellChecker的子类才会加入到检测类Map之中,并且会根据@ExcelChecker 
        	的order值进行排序,排序的作用是检测类存在检测循序,比如检测字段为空是第一个检测的。*/
            if(BaseExcelCellChecker.class.isAssignableFrom(v.getClass())) {
                Integer order = v.getClass().getDeclaredAnnotation(ExcelChecker.class).order();
                if(orderMap.get(order) == null){
                    orderMap.put(order,new ArrayList<>());
                }
                orderMap.get(order).add((BaseExcelCellChecker) v);
            }
        });

        orderMap.forEach((k,v)->{
            v.forEach(excelCellChain->{
            /**这里拿到排序后的Map后注册到当前工厂的检测类Map中,先拿到prefix前缀,因为可能不同实体类的相同字段
            的检测方法不同,例如 A类的 a字段只需要判空,B类的 a字段可能需要判断数据库是否存在,所以通过前缀区分,
            自定了前缀的 key值会变成 prefix:属性名 这种格式。*/
            String prefix = excelCellChain.getClass().getDeclaredAnnotation(ExcelChecker.class).prefix();
                for (String s : excelCellChain.getClass().getDeclaredAnnotation(ExcelChecker.class).field()) {
                        register((prefix.isEmpty()?prefix:prefix+":")+s,excelCellChain);
                }
            });
        });
    }

    public void register(String field, BaseExcelCellChecker excelCellChain){
        List<BaseExcelCellChecker> baseExcelCellCheckers = map.get(field);
        if(baseExcelCellCheckers == null){
            map.put(field,new ArrayList<>());
        }
        map.get(field).add(excelCellChain);
    }

    public List<BaseExcelCellChecker> getChceker(String field){
        return map.get(field);
    }

    @Override
    public void onApplicationEvent(ApplicationEvent applicationEvent) {

    }

}

工厂会将上面的注册至Spring的ExcelChecker 类取出来以field为key以ExcelChecker 类为value注册到工厂类中定义的Map当中,在这个过程中会根据order值进行排序,order越大越先执行。排序的原因是有些字段需要判空以及判断数据库是否存在该字段,如果不进行排序的话可能会先执行数据库判断操作,但是如果字段为空的话,会导致判断空指针。Map的value定义为List的原因是同个字段可能存在多个判断。

BaseExcelCellChecker

@NoArgsConstructor
@AllArgsConstructor
public abstract class BaseExcelCellChecker {

    private Map setMap = new LinkedHashMap(0);

    private ThreadLocal<Map> local = new ThreadLocal<>();

    protected void setLocalValue(String key,Object value){
        if(local.get() == null){
            local.set(new LinkedHashMap(0));
        }
        local.get().put(key,value);
    }

    //获取缓存值
    protected Object getLocalValue(String key){
        if(local.get() == null){
            local.set(new LinkedHashMap(0));
            return null;
        }
        return local.get().get(key);
    }

    //给对象设置值
    public BaseExcelCellChecker setBeanValue(String field,Object xValue){
        if(field != null && !field.isEmpty()){
            setMap.put(field,xValue);
        }
        return this;
    }

    public Map getSetMap(){
        return this.setMap;
    }

    public boolean check(MetaObject original, Object obj,String fieldName, Integer row, Integer col, StringBuffer sb){
        return doCheck(original,obj,fieldName,row,col,sb);
    }

    //校验方法
    protected abstract boolean doCheck(MetaObject original,Object obj, String fieldName, Integer row,Integer col,StringBuffer sb);

    public abstract Object transfer(MetaObject original,Object xValue,String fieldName);

}

基础的检测类,只有继承这个类并且包含@ExcelChecker注解的类才会被注册到ExcelCkeckerFactory工厂的检测类Map当中。下面为多个检测类的其中两个。

NotNullChecker

@ExcelChecker(field = {"staffCode","staffName","sex","staffType","birthday","mobile","salaryType","positionName",
        "attendanceCycle","departmentName","entryCompanyTime","idCard","socreTitle"},order = 999)
public class NotNullChecker extends BaseExcelCellChecker {

	/**
		original:这个 MetaObject 是 mybatis的工具类  是通过反射将对象的所有信息封装成属性,并且提供取值,
		设置值等一系列方法。
		
		obj:读取的cell值

		fieldName:属性名
		
		row:读取的Cell行
	
		col:读取的Cell列

		sb:错误信息对象
	*/
    @Override
    protected boolean doCheck(MetaObject original, Object obj, String fieldName,Integer row, Integer col, StringBuffer sb){
        if(Objects.isNull(obj) || obj.toString().isEmpty()){
            sb.append("第"+row+"行,第"+(col)+"列不能为空!");
            return false;
        }
        return true;
    }


	/**
		这个方法是用来转换的,比如读取的cell值为是  存到数据库时  1代表是  就在这个方法进行转换,
		无需转换的话传来什么直接返回就好了。
	*/
    @Override
    public Object transfer(MetaObject original,Object xValue,String fieldName) {
        return xValue;
    }

}

DepartmentChecker

@ExcelChecker(field = {"departmentName","sectionName","attachName","groupName"},order = 1)
public class DepartmentChecker extends BaseExcelCellChecker {

    @Autowired
    HrDepartmentDao hrDepartmentDao;

    Map<String,String> fcMap = new HashMap(){{
        put("departmentName","sectionName");
        put("sectionName","attachName");
        put("attachName","groupName");
    }};

    Map<String,String> cMap = new HashMap(){{
        put("departmentName","departmentId");
        put("sectionName","sectionId");
        put("attachName","attachId");
        put("groupName","groupId");
    }};

    @Override
    protected boolean doCheck(MetaObject original, Object obj,String fieldName, Integer row,
                              Integer col, StringBuffer sb){
        HrDepartment localValue = (HrDepartment)getLocalValue(fieldName+row);
        if(Objects.nonNull(obj) && obj!="") {
            JSONObject jsonObject = new JSONObject() {{
                put("departmentName", obj);
            }};
            if (Objects.nonNull(localValue)) {
                jsonObject.put("parentId", localValue.getDepartmentId());
            }
            HrDepartment department = hrDepartmentDao.selectOneByParam(jsonObject);
            if (Objects.isNull(department)) {
                sb.append("第" + row + "行,第" + col + "列部门不存在!");
                return false;
            }
            setLocalValue(fcMap.get(fieldName)+row, department);
            setLocalValue(fieldName, department);
        }
        return true;
    }

    @Override
    public Object transfer(MetaObject original,Object xValue,String fieldName) {
        if(Objects.nonNull(xValue) && xValue!="") {
            HrDepartment localValue = (HrDepartment) getLocalValue(fieldName);
            if (Objects.nonNull(localValue)) {
                setBeanValue(cMap.get(fieldName), localValue.getDepartmentId());
            }
        }else{
            setBeanValue(cMap.get(fieldName), 0);
        }
        return ExcelUtils.transferDefaultValueForNull(xValue,xValue.getClass());
    }

}

这是多个checker中的两个,doCheck为检测方法,参数中的MetaObject 是mybatis的一个工具类,其中还包含了MetaClass对象,它通过反射将对象的各种信息保存起来,对外提供一系列的操作对象的方法,使用起来十分方便,感兴趣的小伙伴可以去看一下。transfer是转换数据的方法,例如excel中数据是 ‘是’ , ‘否’这种,存到数据库中是需要转换成 1 , 0。

Excel导入headr

	/**
		key 对应的cell的列
		value 对应的属性名
	*/
    public final static LinkedHashMap<Integer, String> salaryLevelImportHeader = new LinkedHashMap<Integer, String>() {{
        put(0,"region");
        put(1,"positionType");
        put(2,"rank");
        put(3,"level");
        put(4,"functionSalary");
        put(5,"positionAllowance");
        put(6,"housingAllowance");
        put(7,"remark");
    }};


ExcelUtils

@Component
public class ExcelUtils implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    private static ConcurrentHashMap<String,MetaObject> metaMap = new ConcurrentHashMap<>(0);

    private static ConcurrentHashMap<String,Field> fieldMap = new ConcurrentHashMap<>(0);

    public static<T> List<T> transferToList(MultipartFile multipartFile,
                                            LinkedHashMap<Integer,String> header,
                                            Class<T> clazz, Integer start,StringBuffer sb) {
        return transferToList(multipartFile,header,clazz,start,sb,"yyyy-MM-dd HH:mm:ss");
    }

    public static<T> List<T> transferToList(MultipartFile multipartFile,
                                            LinkedHashMap<Integer,String> header,
                                            Class<T> clazz,Integer start, StringBuffer sb,String dataFormart) {
                                 
        /**
			拿到Spring 中的ExcelCkeckerFactory 工厂
		*/                         
        ExcelCkeckerFactory excelCkeckerFactory  = applicationContext.getBean(ExcelCkeckerFactory.class);
        List<T> list = new ArrayList<>(0);
        Integer failCount = 0;
        Integer successCount = 0;
        try(InputStream in = multipartFile.getInputStream()){
            XSSFWorkbook sheets = new XSSFWorkbook(in);
            XSSFSheet xssfSheet = sheets.getSheetAt(0);
            if(xssfSheet != null){
                int lastRowNum = xssfSheet.getLastRowNum();
                for (int i = start - 1; i <= lastRowNum; i++) {
                    XSSFRow row = xssfSheet.getRow(i);
                    //如果一行有一个数据错误了那么整条数据都无需在添加到List当中
                    //但是需要继续判断后续数据是否有误添加至错误信息
                    boolean flag = true;
                    //getXValue 为读取cell封装的一个方法。
                    if(row != null && getXValue(row.getCell(0),String.class,dataFormart) != null){
                    /**DefaultObjectFactory 是mybatis提供的一个调用对象构造函数创建对象的。clazz为用户传的需要读取
                    	Excel后转换的类型。
                    */
                        T t = (T) new DefaultObjectFactory().create(clazz);
                        //MetaObject 上面注解已经解释过了
                        MetaObject metaObject = SystemMetaObject.forObject(t);
                        int lastCellNum = row.getLastCellNum();
                        //遍历cell
                        for (int j = 0; j < lastCellNum; j++) {
                        //从Import Header取出列对应的属性名
                            String fieldName = header.get(j);
                            if(fieldName == null || fieldName.isEmpty()){
                                continue;
                            }
                           /**
                           	如果取出来的属性名包含 : 说明是含有前缀的,需要去掉前缀,注意,这里是拿到对象的属性名,
                           	后续需要拿到这个属性名通过MetaObject 给对象设置值得,取检测类的时候并不是拿fieldName 
                           	这个变量取的。
                           */
                            if(fieldName.indexOf(":") != -1){
                                fieldName = fieldName.substring(fieldName.indexOf(":")+1);
                            }

							/**
								这里拿到属性对应的所有检测类
							*/
                            List<BaseExcelCellChecker> checkerList = excelCkeckerFactory.getChceker(header.get(j));
							
							//如果检测类 List 不为空,表示这个字段需要进行检测
                            if(checkerList != null){
                            //便利检测类,这里是根据order排序后的检测类 list order值越大越先进行检测。
                                for (BaseExcelCellChecker baseExcelCellChecker : checkerList) {
										//调用检测类的检测方法
	                                    if(baseExcelCellChecker.check(metaObject,getXValue(row.getCell(j),metaObject.getSetterType(fieldName),dataFormart),
                                            fieldName,i+1,j+1,sb)){
										//flag标识excel这一行数据是否已经出现过一次cell检测失败,如果只要一个cell检测失败,这一行就没必要继续检测了。
                                        if(flag && metaObject.getSetterType(fieldName) != null){
                                            metaObject.setValue(fieldName,
                                                    baseExcelCellChecker.transfer(metaObject,getXValue(row.getCell(j),
                                                    metaObject.getSetterType(fieldName),dataFormart),fieldName));
                                            Map setMap = baseExcelCellChecker.getSetMap();
                                            //额外的值设置,也就是检测类中setBeanValue()方法设置的map中的值。
                                            if(setMap != null && setMap.size() > 0){
                                                String finalField = fieldName;
                                                setMap.forEach((k, v)->{
                                                    metaObject.setValue(k.toString(),transferDefaultValueForNull(v,metaObject.getSetterType(finalField)));
                                                });
                                            }
                                        }

                                    }else{
                                        flag = false;
                                        break;
                                    }
                                }
                            }else{
                                if(flag && metaObject.getSetterType(fieldName) != null) {
                                    Object xValue = getXValue(row.getCell(j), metaObject.getSetterType(fieldName),dataFormart);
                                    metaObject.setValue(fieldName, transferDefaultValueForNull(xValue,metaObject.getSetterType(fieldName)));
                                }
                            }
                        }
                        if(flag){
                            successCount++;
                            list.add(t);
                        }else{
                            failCount++;
                            sb.append("<br/>");
                        }
                    }
                }
                sb.insert(0,"一共"+(successCount + failCount)+"条数据,其中<span style='color:#409eff'>"+successCount+"</span>条导入成功," +
                        "<span style='color:red'>"+failCount+"</span>条导入失败。" +(failCount > 0?"失败原因如下:":"")+"<br/>");
            }else{
                sb.append("请检查excle是否填写正确");
            }
        }catch (Exception e){
            throw new BaseException("解析excle错误", ResultCode.EXCEPTION);
        }
        return list;
    }



    public static Object transferDefaultValueForNull(Object obj,Class type){
        if(obj == null || obj.toString().isEmpty()){
            if (String.class == type) {
                return "";
            } else if (int.class == type || Integer.class == type || short.class == type || Short.class == type
                 || byte.class == type || Byte.class == type) {
                return 0;
            }
            else if (float.class == type || Float.class == type) {
                return 0F;
            }
            else if (double.class == type || Double.class == type) {
                return 0D;
            }
            else if (long.class == type || Long.class == type) {
                return 0L;
            }
            else if (boolean.class == type
                    || Boolean.class == type) {
                return true;
            }
            return new Object();
        }
        return obj;
    }

    private static Object getXValue(Cell  cell,Class clazz,String dataFormart){
        if (cell == null) {
            return "";
        }
        if(Cell.CELL_TYPE_NUMERIC == cell.getCellType() && HSSFDateUtil.isCellDateFormatted(cell)){
            if(!String.class.isAssignableFrom(clazz)){
                return cell.getDateCellValue().getTime();
            }else if(Data.class.isAssignableFrom(clazz)){
                return cell.getDateCellValue();
            }else {
                return new SimpleDateFormat(dataFormart).format(cell.getDateCellValue());
            }
        }

        String string = "";
        if(cell.getCellType()==Cell.CELL_TYPE_FORMULA){
            try {
                string = String.valueOf(cell.getNumericCellValue());
            } catch (IllegalStateException e) {
                string =  String.valueOf(cell.getRichStringCellValue());
            }
        }else{
            cell.setCellType(Cell.CELL_TYPE_STRING);
            string = cell.getRichStringCellValue().getString();
        }

        if(string.isEmpty() && clazz != String.class){
            string = "0";
        }

        if (null != cell) {
            switch (clazz.getName()) {
                case "java.lang.String":
                    return string;
                case "java.lang.Integer":
                case "int":
                    return Integer.parseInt(string);
                case "java.lang.Long":
                case "long":
                    return Long.parseLong(string);
                case "java.lang.Short":
                case "short":
                    return Short.parseShort(string);
                case "java.lang.Double":
                case "double":
                    return Double.parseDouble(string);
                case "java.lang.Float":
                case "float":
                    return Float.parseFloat(string);
                default:
                    return new Object();
            }
        } else {
            return new Object();
        }
    }

    private static void setCellValue(Cell cell, Object obj) {
        if (obj == null) {
            return;
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        if (obj instanceof String) {
            cell.setCellValue((String) obj);
        } else if (obj instanceof Date) {
            Date date = (Date) obj;

            if (date != null) {
                cell.setCellValue(sdf.format(date));
            }
        } else if (obj instanceof Calendar) {
            Calendar calendar = (Calendar) obj;
            if (calendar != null) {
                cell.setCellValue(sdf.format(calendar.getTime()));
            }
        } else if (obj instanceof Timestamp) {
            Timestamp timestamp = (Timestamp) obj;
            if (timestamp != null) {
                cell.setCellValue(sdf.format(new Date(timestamp.getTime())));
            }
        } else if (obj instanceof Double) {
            cell.setCellValue((Double) obj);
        } else {
            cell.setCellValue(obj.toString());
        }
    }


/**
	这下面的就没必要看的,与导入无关,是导出部分,配合自己封装的metaResponse,metaFile使用的。
*/

    private static Field getFiled(String key,MetaObject metaObject,Class clazz){
        try{
            if(fieldMap.containsKey(key)){
                return fieldMap.get(key);
            }
            PropertyTokenizer prop = new PropertyTokenizer(key);
            if (prop.hasNext()) {
                if(!metaMap.containsKey(prop.getIndexedName())){
                    Object temp = new DefaultObjectFactory().create(metaObject.getGetterType(prop.getIndexedName()));
                    metaMap.put(prop.getIndexedName(),SystemMetaObject.forObject(temp));
                }
                MetaObject metaValue = metaMap.get(prop.getIndexedName());
                if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
                    return null;
                } else {
                    return getFiled(prop.getChildren(),metaValue,metaObject.getGetterType(prop.getIndexedName()));
                }
            }else {
                Field declaredField = clazz.getDeclaredField(key);
                declaredField.setAccessible(true);
                if(!fieldMap.containsKey(key)){
                    fieldMap.put(key,declaredField);
                }
                return declaredField;
            }
        }catch (Exception e){
            return null;
        }
    }

    public static Workbook exportXlsx(Map<String,List> maps,Map<String,LinkedHashMap<String, String>> headMap) {
        Workbook workbook = new XSSFWorkbook();
        Set<String> strings = maps.keySet();
        for (String sheetName : strings) {
            exportXlsx(workbook,sheetName,maps.get(sheetName),headMap.get(sheetName));
        }
        return workbook;
    }


    /**
     * 导出数据
     *
     * @param headMap
     * @param dataList
     */
    public static Workbook exportXlsx(String sheetName,  List dataList ,LinkedHashMap<String, String> headMap) {
        Workbook workbook = new XSSFWorkbook();
        return exportXlsx(workbook,sheetName,dataList,headMap);
    }

    public static Workbook exportXlsx(Workbook workbook,String sheetName,  List dataList ,LinkedHashMap<String, String> headMap) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat();
        Sheet sheet = workbook.createSheet(sheetName);
        int rowIndex = 0, columnIndex = 0;
        Set<String> keys = headMap.keySet();
        //表头
        Row row = sheet.createRow(rowIndex++);
        for (String key : keys) {
            Cell cell = row.createCell(columnIndex++);
            cell.setCellValue(headMap.get(key));
        }
        //内容
        if (dataList != null && !dataList.isEmpty()) {
            for (Object o : dataList) {
                columnIndex = 0;
                row = sheet.createRow(rowIndex++);
                MetaObject metaObject = SystemMetaObject.forObject(o);
                for (String key : keys) {
                    Cell cell = row.createCell(columnIndex++);
                    try{
                        Field declaredField = getFiled(key,metaObject,o.getClass());
                        ExcelDateFormart declaredAnnotation = declaredField.getDeclaredAnnotation(ExcelDateFormart.class);
                        if(declaredAnnotation != null){
                            try {
                                if(Objects.isNull(metaObject.getValue(key))){
                                    setCellValue(cell, "");
                                }else{
                                    simpleDateFormat.applyPattern(declaredAnnotation.pattern());
                                    if(declaredField.getType() == Date.class){
                                            setCellValue(cell, simpleDateFormat.format(metaObject.getValue(key)));
                                    }else{
                                        if((Long)metaObject.getValue(key) <= 0){
                                            setCellValue(cell, "");
                                        }else{
                                            setCellValue(cell, simpleDateFormat.format(new Date((Long) metaObject.getValue(key))));
                                        }
                                    }
                                }
                            }catch (Exception e){
                                setCellValue(cell, metaObject.getValue(key));
                            }
                        }else{
                            setCellValue(cell, metaObject.getValue(key));
                        }
                    }catch (Exception e){
                        setCellValue(cell, "");
                    }

                }
            }
        }
        return workbook;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }


}

这个工具类解释起来比较麻烦,导入方法最主要的时transferToList方法,在读取excel根据Excel Header常量给定的Map对应的key值也就是excel的列数从ExcelCkeckerFactory拿到对应的的ExcelChecker调用check方法检测,检车通过则根据Excel Header常量给定的Map对应的value值以及MetaObject给对象设置值并添加到List中最终返回List,如果校验不通过则将错误信息添加至errorMsg,在这里可以解释ExcelChecker prefix的作用,不同实体类的相同字段检测方法可能不同,每个实体都有Excel Header,其中key值就可以设置 前置:字段这种,这样就可以做到不同实体类相同字段通过前缀拿到不同的检测类。拿到List后就可以进行业务逻辑操作了,通过重构将检测方法封装成不同的类,方便拓展以及不容易出错并且可以复用。重构后使用只需要编写 ExcelChecker类以及Excel Header常量即可。





使用

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值