Excel读取并数据List/Map-POI

简介: 该工具类基于POI解析.xls格式Excel文件,支持按行读取数据并映射为Java对象。通过反射机制将每行数据转换为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要保持一致,否则反射时候代码校验不通过

相关文章
|
25天前
|
安全 Java 数据安全/隐私保护
通用权限管理模型
本文介绍了ACL与RBAC等常见权限模型。ACL通过用户/角色直接授权,简单直观;RBAC则基于角色分配权限,支持角色继承与职责分离,更易维护。还简要提及DAC、MAC、ABAC等模型,帮助读者建立权限管理的全局认知。
|
25天前
|
SQL 缓存 Java
汇总
MyBatis配置优先级:方法参数 &gt; resource/url &gt; properties体内。支持多环境、事务管理(JDBC/MANAGED)、XML映射(一对一、一对多、多对多)及分页(逻辑与物理)。提供一级、二级缓存,三种执行器,支持插件扩展与源码优化。
|
25天前
|
存储 缓存 安全
One Trick Per Day
初始化Map应避免默认容量导致扩容,推荐Guava的`newHashMapWithExpectedSize`;禁用Executors创建线程池,防止OOM,应手动通过`ThreadPoolExecutor`设置合理参数;`Arrays.asList`返回不可变列表,禁止修改操作;遍历Map使用`entrySet`提升性能;`SimpleDateFormat`非线程安全,建议用`ThreadLocal`或Java8时间类;并发修改记录需加锁,优先乐观锁,冲突高则用悲观锁。
|
24天前
|
Java 测试技术 API
从Google线上故障,谈灰度发布的重要性
2025年6月12日,Google Cloud因未灰度发布的新配置引发空指针异常,导致Gmail、YouTube等服务中断超7小时。故障暴露了缺乏配置灰度与错误处理机制的风险。本文结合Nacos等配置中心的IP/标签灰度方案,探讨如何通过渐进式发布保障系统稳定性,避免全局故障。
|
25天前
|
运维 安全 Devops
生产环境缺陷管理
git-poison基于go-git实现分布式bug追溯,解决多分支开发中bug漏修、漏发等问题。通过“投毒-解毒”机制,自动化卡点发布流程,降低协同成本,避免人为失误,已在大型团队落地应用,显著提升发布安全与效率。
|
24天前
|
Java 数据安全/隐私保护
脱敏工具
提供身份证、姓名、手机号脱敏的Java实现,通过正则替换隐藏敏感信息:身份证保留前后部分,中间用*代替;姓名仅显示首尾字符;手机号显示前3后4位,中间4位脱敏,保障数据安全。
|
24天前
|
消息中间件 监控 Java
RocketMQ:底层Netty频繁OS OOM
本文记录了一例Java应用因多ClassLoader加载多个Netty的PooledByteBufAllocator导致堆外内存超限,引发OS OOM的排查过程。尽管MaxDirectMemorySize设为1G,但多个中间件独立占用堆外内存,总量远超限制。通过NMT、Arthas等工具定位到RocketMQ客户端为主要占用者。最终建议短期调小堆内存以腾出空间,并推动中间件优化。
|
24天前
|
自然语言处理 fastjson Java
FastJson:大面积故障规避案例
本文分享了一次因Kotlin语法误用导致FastJson反序列化全局异常的排查经历。在多语言混编工程中,`{}`被误赋值为Java对象字段,触发FastJson解析Kotlin类时将静态标记`kotlin_error`置为true且无法恢复,最终引发全量反序列化失败。问题隐蔽性强,影响范围大,历时两天定位。反思指出:多语言开发需谨慎、框架有局限、灰度发布至关重要,并强调Bug是成长的阶梯。
|
25天前
|
Java 测试技术 Linux
生产环境发布管理
本文介绍大型团队如何通过自动化部署平台实现多环境(dev/test/pre/prod)高效发布与运维。涵盖各环境职责、基于Jenkins+K8S的CI/CD流程、分支管理、一键发布及日志排查方案,结合Skywalking实现链路追踪,提升发布效率与问题定位能力。(238字)
|
25天前
|
缓存 Dubbo Java
什么是API网关
API网关是一种架构思想,用于统一接收外部请求并转发至后端服务,实现协议转换、路由、鉴权、限流、熔断降级等功能。通过网关,可简化客户端调用,提升系统安全性与可维护性。常见实现如Kong、Zuul、Spring Cloud Gateway等,广泛应用于微服务架构中,支持异步处理、全链路监控与多维度流量控制。

热门文章

最新文章