基于easyExcel,Java简单实现对Excel数据的读取

在日常开发过程中, 对Excel表格中的数据读取非常常见,比如根据指定模板将数据导入进数据库等等。

以下代码仅仅实现简单的从excel中实现读取,更复杂的表头及数据解析,请自行封装。

1. 实现代码

  1. 导入依赖

    <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>easyexcel</artifactId>
          <version>1.1.1</version>
        </dependency>
        <dependency>
          <groupId>org.apache.commons</groupId>
          <artifactId>commons-lang3</artifactId>
          <version>3.4</version>
        </dependency>
    
  2. 编写MyStringUtils ,去除空格使用

    package org.example.excel;
    
    public class MyStringUtils {
    
        private MyStringUtils() {}
    
        /**
         * 与StringUtils.isEmpty()的区别在于只有空格的字符串也返回true
         * @param cs
         * @return
         */
        private static boolean isBlank(final CharSequence cs) {
            int strLen;
            if (cs == null || (strLen = cs.length()) == 0) {
                return true;
            }
            for (int i = 0; i < strLen; i++) {
                if (!Character.isWhitespace(cs.charAt(i))) {
                    return false;
                }
            }
            return true;
        }
    
        public static boolean isNotBlank(final CharSequence cs) {
            return !isBlank(cs);
        }
    }
    
  3. 实现对象之间的copy

    package org.example.excel;
    
    import org.springframework.beans.*;
    import org.springframework.beans.propertyeditors.CustomDateEditor;
    import org.springframework.core.convert.ConversionService;
    import org.springframework.core.convert.converter.Converter;
    import org.springframework.core.convert.support.DefaultConversionService;
    import org.springframework.core.convert.support.GenericConversionService;
    import org.springframework.util.Assert;
    
    import java.beans.PropertyDescriptor;
    import java.lang.reflect.Method;
    import java.lang.reflect.Modifier;
    import java.text.DateFormat;
    import java.text.SimpleDateFormat;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Date;
    import java.util.List;
    
    public class BeanCopy {
    
    	private final class DateToStringConverter implements Converter<Date, String> {
            private DateFormat df ;
    		private DateToStringConverter(String format) {
                df = new SimpleDateFormat(format);
    		}
    		@Override
    		public String convert(Date source) {
    
    			return df.format(source);
    		}
    	}
    
    	private static final String DATE_FORMAT = "yyyy-MM-dd";
    
    	private static Object convertForProperty(Wrapper wrapper, Object object, Object value, String propertyName)
    			throws TypeMismatchException {
    		Object result;
    		if (wrapper == null) {
    			result = null;
    		} else {
    			wrapper.setWrappedInstance(object);
    			result = wrapper.getBeanWrapper().convertForProperty(value, propertyName);
    		}
    		return result;
    	}
    
    	private static Object copyProperties(Object source, Object target) throws BeansException {
    		Wrapper wrapper = new BeanCopy().new Wrapper(source);
    		copyProperties(wrapper, source, target);
    		return target;
    	}
    
    	private static void copyProperties(Wrapper wrapper, Object source, Object target) throws BeansException {
    		Assert.notNull(source, "Source must not be null");
    		Assert.notNull(target, "Target must not be null");
    
    		Class<?> actualEditable = target.getClass();
    		PropertyDescriptor[] targetPds = BeanUtils.getPropertyDescriptors(actualEditable);
    
    		for (PropertyDescriptor targetPd : targetPds) {
    			if (targetPd.getWriteMethod() != null) {
    				PropertyDescriptor sourcePd = BeanUtils.getPropertyDescriptor(source.getClass(), targetPd.getName());
    				if ( sourcePd.getReadMethod() != null) {
    					try {
    						Method readMethod = sourcePd.getReadMethod();
    						if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
    							readMethod.setAccessible(true);
    						}
    						Object value = readMethod.invoke(source);
    						// 判断是否类型不一致
    						if (value != null && !(targetPd.getPropertyType().isInstance(value))) {
    							// 数据转型
    							value = convertForProperty(wrapper, target, value, targetPd.getName());
    						}
    						Method writeMethod = targetPd.getWriteMethod();
    						if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
    							writeMethod.setAccessible(true);
    						}
    						writeMethod.invoke(target, value);
    					} catch (Exception ex) {
    						throw new FatalBeanException("Could not copy properties from source to target", ex);
    					}
    				}
    			}
    		}
    
    	}
    
    	private final class Wrapper {
    
    		private GenericConversionService conversion;
    		private BeanWrapperImpl bean;
    
    		private Wrapper(Object object) {
    			conversion = initDefaultConversionService();
    			bean = initDefaultBeanWrapper(conversion, object);
    		}
    
    		private void setWrappedInstance(Object object) {
    			bean.setWrappedInstance(object);
    		}
    
    		private GenericConversionService initDefaultConversionService() {
    			GenericConversionService conversionService = new DefaultConversionService();
    			conversionService.addConverter(new DateToStringConverter(DATE_FORMAT));
    			return conversionService;
    		}
    
    		private BeanWrapperImpl initDefaultBeanWrapper(@SuppressWarnings("hiding") ConversionService conversion,
                                                           Object object) {
    			BeanWrapperImpl beanWrapper = new BeanWrapperImpl(object);
    			beanWrapper.setConversionService(conversion);
    			SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
    			dateFormat.setLenient(false);
    			beanWrapper.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
    			return beanWrapper;
    		}
    
    		private BeanWrapperImpl getBeanWrapper() {
    			return bean;
    		}
    	}
    
    	/**
    	 * 复制源对象到目的对象
    	 */
    	private static void convert(Object source, Object target) {
    		copyProperties(source, target);
    	}
    
    	public static <T> List<T> convert(List<?> sources, Class<T> targetClass) {
    		List<?> sourcesObj = sources;
    		if (sourcesObj == null) {
    			sourcesObj = Collections.emptyList();
    		}
    		List<T> targets = new ArrayList<>(sourcesObj.size());
    		BeanCopy.convert(sourcesObj, targets, targetClass);
    		return targets;
    	}
    
    	private static <T> void convert(List<?> sources, List<T> targets, Class<T> targetClass) {
    		if (targets == null) {
    			return;
    		}
    		targets.clear();
    		if (sources == null) {
    			return;
    		}
    		for (Object obj : sources) {
    			try {
    				T target = targetClass.newInstance();
    				targets.add(target);
    				convert(obj, target);
    			} catch (Exception e) {
                    //do something
    				return;
    			}
    		}
    	}
    }
    
    
  4. 编写 ExcelListener ,校验对象属性中是否携带 ExcelProperty 注解

    
    package org.example.excel;
    
    import com.alibaba.excel.annotation.ExcelProperty;
    import com.alibaba.excel.context.AnalysisContext;
    import com.alibaba.excel.event.AnalysisEventListener;
    
    import java.lang.reflect.Field;
    import java.util.ArrayList;
    import java.util.List;
    
    public class ExcelListener extends AnalysisEventListener {
    
        private List<Object> dataList = new ArrayList<>();
    
        /**
         * 通过 AnalysisContext 对象还可以获取当前 sheet,当前行等数据
         */
        @Override
        public void invoke(Object object, AnalysisContext context) {
            if (!checkObjAllFieldsIsNull(object)) {
                dataList.add(object);
            }
        }
    
        @Override
        public void doAfterAllAnalysed(AnalysisContext context) {
    
        }
    
        private static final String SERIAL_VERSION_UID = "serialVersionUID";
    
        /**
         * 判断对象中属性值是否全为空
         */
        private static boolean checkObjAllFieldsIsNull(Object object) {
            if (null == object) {
                return true;
            }
            try {
                for (Field f : object.getClass().getDeclaredFields()) {
                    f.setAccessible(true);
                    //只校验带ExcelProperty注解的属性
                    ExcelProperty property = f.getAnnotation(ExcelProperty.class);
                    if (property == null || SERIAL_VERSION_UID.equals(f.getName())) {
                        continue;
                    }
                    if (f.get(object) != null && MyStringUtils.isNotBlank(f.get(object).toString())) {
                        return false;
                    }
                }
            } catch (Exception e) {
                //do something
            }
            return true;
        }
    
        public List<Object> getDataList() {
            return dataList;
        }
    }
    
    
  5. 核心类 ExcelUtil

    package org.example.excel;
    
    import com.alibaba.excel.ExcelReader;
    import com.alibaba.excel.metadata.BaseRowModel;
    import com.alibaba.excel.metadata.Sheet;
    import org.apache.commons.lang3.StringUtils;
    import org.example.entity.Student;
    import org.springframework.web.multipart.MultipartFile;
    
    import java.io.BufferedInputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.InputStream;
    import java.util.List;
    
    public class ExcelUtil {
        /**
         * 私有化构造方法
         */
        private ExcelUtil() {
        }
    
        private static List<?> readExcel(String path, Class<? extends BaseRowModel> clazz) throws Exception {
            if (StringUtils.isNotEmpty(path)) {
                File file = new File(path);
                if (!file.exists()) {
                    throw new Exception("文件不存在 !");
                }
                InputStream inputStream = new FileInputStream(file);
                BufferedInputStream bis = new BufferedInputStream(inputStream);
                return readExcel(bis, clazz);
            }
            return null;
        }
    
        private static List<?> readExcel(File file, Class<? extends BaseRowModel> clazz) throws Exception {
            if (file != null && file.exists()) {
                InputStream inputStream = new FileInputStream(file);
                BufferedInputStream bis = new BufferedInputStream(inputStream);
                return readExcel(bis, clazz);
            }
            return null;
        }
    
        private static List<?> readExcel(InputStream inputStream, Class<? extends BaseRowModel> clazz) throws Exception {
            return readExcel(inputStream, null, clazz);
        }
    
        private static List<?> readExcel(MultipartFile excelFile, Class<? extends BaseRowModel> clazz) throws Exception {
            if (excelFile != null) {
                return readExcel(excelFile.getInputStream(), null, clazz);
            }
            return null;
        }
    
        public static List<?> readExcel(InputStream inputStream, Object customContent, Class<? extends BaseRowModel> clazz) throws Exception {
            ExcelListener excelListener = new ExcelListener();
            ExcelReader excelReader;
            if (inputStream instanceof BufferedInputStream) {
                excelReader = new ExcelReader(inputStream, customContent, excelListener);
            } else {
                excelReader = new ExcelReader(new BufferedInputStream(inputStream), customContent, excelListener);
            }
            excelReader.read(new Sheet(1, 1, clazz));
            return excelListener.getDataList();
        }
    
        public static List<Student> readStudentExcel(InputStream inputStream) throws Exception{
            List<?> list = readExcel(inputStream,Student.class);
            return BeanCopy.convert(list, Student.class) ;
        }
    
    }
    

2. 使用

  1. 创建excel模板
    在这里插入图片描述

  2. 编写与excel模板对应的JavaBean

    package org.example.entity;
    
    import com.alibaba.excel.annotation.ExcelProperty;
    import com.alibaba.excel.metadata.BaseRowModel;
    
    import java.io.Serializable;
    
    /**
     * @author zfl_a
     * @date 2021/4/11
     * @project test-spring-boot-starter
     */
    public class Student extends BaseRowModel implements Serializable {
    
        @ExcelProperty(index = 0)
        private String userName;
    
        @ExcelProperty(index = 1)
        private Integer age ;
    
        @ExcelProperty(index = 2)
        private String className ;
    
        @ExcelProperty(index = 3)
        private Double totalScore ;
    
        ...省略getter/setter
    
  3. 调用ExcelUtil

    
    InputStream inputStream = new FileInputStream(new File("D:\\student.xlsx"));
    
    List<Student> students = ExcelUtil.readStudentExcel(inputStream);
    
    System.out.println(students);
    
    
  4. 读取内容如下:
    在这里插入图片描述

3. 使用时注意事项

  • 默认从excel表格中第一个sheet中的第一行数据开始读取,设置的地方
    在这里插入图片描述
  • JavaBean要与导入的数据一一对应。属性上使用@ExcelProperty(index = 0),index=0表示从第一个开始读取,以此类推。
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陆小叁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值