Excel读取并数据List/Map-POI

简介: 该工具类使用POI解析.xls格式Excel,通过反射将每行数据映射为VO对象,支持日期、数字等类型处理,可全局输出Map或List,适用于固定模板的数据导入场景,需保证列数与VO字段一致。
  1. 全局输出Map
    import com.test.ExcelVO;
    import org.apache.commons.lang.StringUtils;
    import org.apache.poi.hssf.usermodel.HSSFCell;
    import org.apache.poi.hssf.usermodel.HSSFRow;
    import org.apache.poi.hssf.usermodel.HSSFSheet;
    import org.apache.poi.hssf.usermodel.HSSFWorkbook;
    import org.apache.poi.poifs.filesystem.POIFSFileSystem;
    import org.apache.poi.ss.usermodel.DateUtil;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ParseExcelUtil {

// 解析后存放的全局Map
public static Map<String, DoctorForExcelVO> STATIC_MAP = new HashMap<>();

private static String val = null;

// 这里会对日期格式数据做处理,如不期望更改则删掉
private static SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");

// 这里会对数字格式数据做处理,如不期望更改则删掉
private static DecimalFormat df = new DecimalFormat("0");

private static HSSFWorkbook wb;

// 文件路径
private final static String IMPORT_EXCEL_NAME = "D:Excel_Data.xls";

/**
 * 列数传入,解决列情况: X,X,,X读取列数为3
 **/
private static int colNum = 20;

// 开始行数
private static int startRowNum = 3;

// sheet坐标
private static int index = 1;

/**
 * @return
 */
public static Map<String, DoctorForExcelVO> readExcelData() {

    FileInputStream file = null;
    POIFSFileSystem ts;
    // 读取默认清除上一次数据
    JGPT_DOCTOR_MAP.clear();
    try {
        file = new FileInputStream(DOCTOR_IMPORT_EXCEL_NAME);
        ts = new POIFSFileSystem(file);
        wb = new HSSFWorkbook(ts);
        // 获取表
        HSSFSheet sheet = wb.getSheetAt(index);
        // 获取行数
        int rowNum = sheet.getPhysicalNumberOfRows();
        HSSFRow row;
        for (int i = startRowNum - 1; i < rowNum; i++) {
            List<String> list = new ArrayList<>();
            // 每行
            row = sheet.getRow(i);
            // 每列
            for (int j = 0; j < colNum; j++) {
                HSSFCell cell = row.getCell(j);
                list.add(getXcellVal(cell));
            }
            String key = list.get(3);
            if (StringUtils.isEmpty(key)) {
                continue;
            }
            JGPT_DOCTOR_MAP.put(key, listToModel(list, new DoctorForExcelVO()));
        }
        return JGPT_DOCTOR_MAP;
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            if (null != file) {
                file.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return null;
}

/**
 * 类型转换与数据解析
 *
 * @param cell
 * @return
 */
private static String getXcellVal(HSSFCell cell) {

    if (null == cell) {
        return "";
    }
    // 同上,如不希望截取数据,添加下面注释这行
    // 包路径import org.apache.poi.ss.usermodel.Cell;
    // cell.setCellType(Cell.CELL_TYPE_STRING);
    switch (cell.getCellType()) {
        case HSSFCell.CELL_TYPE_NUMERIC:
            if (DateUtil.isCellDateFormatted(cell)) {
                // 日期型
                val = fmt.format(cell.getDateCellValue());
                // 上面如果删掉格式处理,这里统一转成String即可
                // val = String.valueOf(cell.getDateCellValue());
            } else {
                // 数字型
                val = df.format(cell.getNumericCellValue());
                // 上面如果删掉格式处理,这里统一转成String即可
                // val = String.valueOf(cell.getNumericCellValue());
            }
            break;
        // 文本类型
        case HSSFCell.CELL_TYPE_STRING:
            val = cell.getStringCellValue();
            break;
        // 公式特殊处理
        case HSSFCell.CELL_TYPE_FORMULA:
            try {
                val = String.valueOf(cell.getStringCellValue());
            } catch (IllegalStateException e) {
                val = String.valueOf(cell.getNumericCellValue());
            }
            break;
        // 空
        case HSSFCell.CELL_TYPE_BLANK:
            val = cell.getStringCellValue();
            break;
        /** 布尔 **/
        case HSSFCell.CELL_TYPE_BOOLEAN:
            val = String.valueOf(cell.getBooleanCellValue());
            break;
        /** 错误 **/
        case HSSFCell.CELL_TYPE_ERROR:
            val = "ERROR..CHECK DATA";
            break;
        default:
            val = cell.getRichStringCellValue() == null ? null : cell
                    .getRichStringCellValue().toString();
    }

    return val;
}

/**
 * 反射填充属性
 *
 * @param list 数据集
 * @param vo   被反射的对象
 * @return
 * @throws Exception
 */
private static DoctorForExcelVO listToModel(List<String> list, DoctorForExcelVO vo) throws Exception {
    Field[] fields = vo.getClass().getDeclaredFields();
    if (list.size() != fields.length) {
        return null;
    }
    for (int k = 0, len = fields.length; k < len; k++) {
        // 根据属性名称,找寻合适的set方法
        String fieldName = fields[k].getName();
        String setMethodName = "set" + fieldName.substring(0, 1).toUpperCase()
                + fieldName.substring(1);
        Method method = null;
        Class<?> clazz = vo.getClass();
        try {
            method = clazz.getMethod(setMethodName, new Class[]{list.get(k).getClass()});
        } catch (SecurityException e1) {
            e1.printStackTrace();
            return null;
        } catch (NoSuchMethodException e1) {
            String newMethodName = "set" + fieldName.substring(0, 1).toLowerCase()
                    + fieldName.substring(1);
            try {
                method = clazz.getMethod(newMethodName, new Class[]{list.get(k).getClass()});
            } catch (SecurityException e) {
                e.printStackTrace();
                return null;
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
                return null;
            }
        }
        if (method == null) {
            return null;
        }
        method.invoke(vo, new Object[]{list.get(k)});
    }
    return vo;
}

反射的VO
@Data
public class DoctorForExcelVO {
private String organ_code;
private String organ_name;
private String remark;
}

  1. 全局输出List
    import org.apache.poi.hssf.usermodel.HSSFCell;
    import org.apache.poi.hssf.usermodel.HSSFRow;
    import org.apache.poi.hssf.usermodel.HSSFSheet;
    import org.apache.poi.hssf.usermodel.HSSFWorkbook;
    import org.apache.poi.poifs.filesystem.POIFSFileSystem;
    import org.apache.poi.ss.usermodel.DateUtil;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

/**

  • @author herb
  • @version 1.0
  • @date 2020/6/9 10:01
  • @Desc 解析Excel模板
    */
    public class ExcelForReturnListUtil {

    // 解析后存放的全局List
    public static List OnlineDataList = new ArrayList<>();

    private static String val = null;

    // 这里的format同上,需要注意,否则会截取数据
    private static SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");

    // 这里的format同上,需要注意,否则会截取数据
    private static DecimalFormat df = new DecimalFormat("0");

    private static HSSFWorkbook wb;

    // 文件路径
    private final static String IMPORT_EXCEL_NAME = "D:/DATA.xls";

    /**

    • 列数传入,解决列情况: X,X,,X读取列数为3
      **/
      private static int colNum = 16;

      // 开始行数
      private static int startRowNum = 3;

      // sheet坐标
      private static int index = 1;

      public static List readExcelData() {
      FileInputStream file = null;
      POIFSFileSystem ts;
      // 读取默认清除上一次数据
      OnlineDataList.clear();
      try {

       file = new FileInputStream(IMPORT_EXCEL_NAME);
       ts = new POIFSFileSystem(file);
       wb = new HSSFWorkbook(ts);
       // 获取表
       HSSFSheet sheet = wb.getSheetAt(index);
       // 获取行数
       int rowNum = sheet.getPhysicalNumberOfRows();
       HSSFRow row;
       for (int i = startRowNum - 1; i < rowNum; i++) {
           List<String> list = new ArrayList<>();
           // 每行
           row = sheet.getRow(i);
           // 每列
           for (int j = 0; j < colNum; j++) {
               HSSFCell cell = row.getCell(j);
               list.add(getXcellVal(cell));
           }
           OnlineDataList.add(listToModel(list, new User()));
       }
       return OnlineDataList;
      

      } catch (Exception e) {

       e.printStackTrace();
      

      } finally {

       try {
           if (null != file) {
               file.close();
           }
       } catch (IOException e) {
           e.printStackTrace();
       }
      

      }
      return null;
      }
      /**

    • 类型转换与数据解析
      *
    • @param cell
    • @return
      */
      private static String getXcellVal(HSSFCell cell) {

      if (null == cell) {

       return "";
      

      }
      // 同上,如不希望截取数据,添加下面注释这行
      // 包路径import org.apache.poi.ss.usermodel.Cell;
      // cell.setCellType(Cell.CELL_TYPE_STRING);
      switch (cell.getCellType()) {

       case HSSFCell.CELL_TYPE_NUMERIC:
           if (DateUtil.isCellDateFormatted(cell)) {
               // 日期型
               val = fmt.format(cell.getDateCellValue());
           } else {
               // 数字型
               val = df.format(cell.getNumericCellValue());
           }
           break;
       // 文本类型
       case HSSFCell.CELL_TYPE_STRING:
           val = cell.getStringCellValue();
           break;
       // 公式特殊处理
       case HSSFCell.CELL_TYPE_FORMULA:
           try {
               val = String.valueOf(cell.getStringCellValue());
           } catch (IllegalStateException e) {
               val = String.valueOf(cell.getNumericCellValue());
           }
           break;
       // 空
       case HSSFCell.CELL_TYPE_BLANK:
           val = cell.getStringCellValue();
           break;
       /** 布尔 **/
       case HSSFCell.CELL_TYPE_BOOLEAN:
           val = String.valueOf(cell.getBooleanCellValue());
           break;
       /** 错误 **/
       case HSSFCell.CELL_TYPE_ERROR:
           val = "ERROR..CHECK DATA";
           break;
       default:
           val = cell.getRichStringCellValue() == null ? null : cell
                   .getRichStringCellValue().toString();
      

      }
      return val;
      }

      /**

    • 反射填充属性
      *
    • @param list 数据集
    • @param vo 被反射的对象
    • @return
    • @throws Exception
      */
      private static ImMedicalOnlineForUploadEntity listToModel(List list, User vo) throws Exception {
      Field[] fields = vo.getClass().getDeclaredFields();
      if (list.size() != fields.length) {
       return null;
      
      }
      for (int k = 0, len = fields.length; k < len; k++) {
       // 根据属性名称,找寻合适的set方法
       String fieldName = fields[k].getName();
       String setMethodName = "set" + fieldName.substring(0, 1).toUpperCase()
               + fieldName.substring(1);
       Method method = null;
       Class<?> clazz = vo.getClass();
       try {
           method = clazz.getMethod(setMethodName, new Class[]{list.get(k).getClass()});
       } catch (SecurityException e1) {
           e1.printStackTrace();
           return null;
       } catch (NoSuchMethodException e1) {
           String newMethodName = "set" + fieldName.substring(0, 1).toLowerCase()
                   + fieldName.substring(1);
           try {
               method = clazz.getMethod(newMethodName, new Class[]{list.get(k).getClass()});
           } catch (SecurityException e) {
               e.printStackTrace();
               return null;
           } catch (NoSuchMethodException e) {
               e.printStackTrace();
               return null;
           }
       }
       if (method == null) {
           return null;
       }
       method.invoke(vo, new Object[]{list.get(k)});
      
      }
      return vo;
      }

注意点:

  1. VO一定要生成set/get方法,我这里借助的@Data注解实现,也可以直接手动生成

  2. 我这里Excel读取行数,列数是写死的,建议作为入参介入【我这里业务场景特殊】

  3. 模板为 *.xls

  4. 模板列数和VO要保持一致,否则反射时候代码校验不通过

相关文章
|
19小时前
|
缓存 开发工具 git
QLExpress使用及源码分析
QLExpress是阿里开源的轻量级规则引擎,支持通过注解与YAML配置实现业务逻辑解耦。基于AST语法树解析,提供上下文绑定、动态脚本执行与缓存机制,适用于复杂条件判断与计算场景,如BMI计算、用户规则校验等,具备高扩展性与易维护性。
|
19小时前
|
Arthas 监控 Java
arthas 安装
本教程介绍Arthas的安装与基础使用。需提前安装JDK并确保服务器有Java应用运行。下载arthas-boot.jar,上传Java应用(如Arthas-demo.jar),启动后通过`java -jar arthas-boot.jar`接入,选择对应进程即可监控。支持多Java进程管理,为后续深入使用奠定基础。(239字)
|
19小时前
|
Java 大数据
Java基础集合ArrayList扩容机制
本文详解ArrayList的add及扩容机制:添加元素时先调用ensureCapacityInternal(),首次扩容至10;通过grow()实现容量1.5倍增长(oldCapacity + (oldCapacity &gt;&gt; 1)),当元素数超当前容量时触发扩容。length为数组属性,length()为字符串方法,size()用于集合大小获取。
|
18小时前
|
Java 测试技术 API
从Google线上故障,谈灰度发布的重要性
2025年6月12日,Google Cloud因未灰度发布的新功能引发空指针异常,导致全球服务中断超7小时。故障暴露了配置管理与错误处理的短板。本文结合Nacos等配置中心的IP/标签灰度方案,探讨如何通过渐进式发布降低系统风险,提升稳定性。
|
19小时前
|
Java 应用服务中间件 网络安全
Eclipse运行SSM/SSH项目教程
本教程介绍如何在Eclipse中配置Java Web开发环境,包括JDK、Tomcat安装与版本匹配,项目导入(支持Maven与非Maven),Eclipse中绑定Tomcat服务器并部署运行项目,附常见问题如数据库连接配置错误的解决方法。
|
18小时前
|
SQL Dubbo Java
线程池:故障梳理总结
本文从故障与技术双重视角,总结线程池类故障的常见成因及应对策略。涵盖数据库慢查询、连接池配置不当、超时设置缺失等问题,结合真实案例剖析线程池满的根本原因,并提出fast-fail、流控、背压、谨慎重试等最佳实践,助力开发者提升系统稳定性。
|
18小时前
|
运维 NoSQL 测试技术
Redis:内存陡增100%深度复盘
事故源于大KEY导致带宽占满,触发Redis内存使用率骤增至100%,缓冲区溢出致服务全面超时。根本原因为输出/输入缓冲区内存激增,超出实例容量,阻塞正常请求。虽有淘汰策略,但仅作用于数据内存,无法缓解缓冲区占用问题。最终引发GET/SET全线超时,服务不可用。
|
18小时前
|
SQL 分布式计算 运维
XXLJOB:超长定时任务慢节点优化实践
该文针对ODPS大宽表任务运行缓慢问题,通过分析DAG图与耗时节点,定位数据倾斜和计算堆积等核心瓶颈。采用提升资源、加盐打散空值、视图落表、前置裁剪、MapJoin与DistMapJoin优化关联,并拆分节点降低回刷成本。最终产出时间从13:00提前至8:30,节省超4小时,显著提升效率与可维护性。
|
20小时前
|
存储 缓存 安全
Java基础 One Trick Per Day
初始化Map应避免默认容量导致扩容开销,推荐Guava或手动计算;禁用Executors创建线程池,防止OOM,应显式定义ThreadPoolExecutor参数;Arrays.asList返回不可变列表,禁止修改操作;遍历Map优先使用entrySet或forEach提升性能;SimpleDateFormat非线程安全,建议用ThreadLocal或Java8新时间API;并发更新记录需加锁,推荐乐观锁配合version控制。
|
19小时前
|
SpringCloudAlibaba NoSQL Java
基础环境配置
项目基于JDK8+、Maven、Redis 3.2+、MySQL 5.7+,使用Idea开发,需安装Lombok插件和JRebel热部署。技术栈涵盖SpringBoot、MybatisPlus、Shiro(可参考SpringSecurity)、SpringCloud Alibaba。