zoukankan      html  css  js  c++  java
  • 基于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表示从第一个开始读取,以此类推。
    充满鲜花的世界到底在哪里
  • 相关阅读:
    python及pandas,numpy等知识点技巧点学习笔记
    人工智能,大数据,云计算大杂烩
    python开发环境
    机器学习vs深度学习及其知识点
    深入理解SVG坐标体系和transformations- viewport, viewBox,preserveAspectRatio
    军队改革看管理
    d3js path generator vs layouts
    d3js layout 深入理解
    RedisTemplate 事务处理方法 watch multi exec 的使用
    阻止联网
  • 原文地址:https://www.cnblogs.com/aliases/p/14693289.html
Copyright © 2011-2022 走看看