Excel读取并数据List/Map-POI

简介: 该工具类用于解析Excel文件(.xls格式),通过POI读取数据并利用反射将每行数据映射到Java对象。支持全局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;
}

2. 全局输出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<User> 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<User> 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<String> 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要保持一致,否则反射时候代码校验不通过


相关文章
|
5天前
|
弹性计算 运维 监控
【运维排查】服务器CPU飙升100%?别慌,教你3步精准定位“罪魁祸首”
当服务器CPU飙高时,别急着重启!本文教你四步精准排查:用`top`定位高占用进程,`top -Hp`找出耗CPU线程,`printf`转十六进制,再通过`jstack`结合线程ID定位到具体代码行。快速锁定死循环、频繁GC或复杂计算等问题根源,成为团队中的故障排查高手。
|
6月前
|
数据安全/隐私保护
贴吧自动发帖工具, 贴吧自动评论脚本,顶贴回复发帖插件
这个代码实现了贴吧自动发帖、自动回复、获取帖子列表等功能。主要使用了requests库进行网络请求
|
5天前
|
监控 Java Sentinel
Sentinel安装与集成
介绍如何切换hmall-micro项目至dev_02分支并提交代码,强调多分支并行开发模式。随后讲解Sentinel服务保护框架的安装与配置,包括控制台部署、本地运行及项目集成,实现微服务熔断降级,并通过簇点链路监控接口。
Sentinel安装与集成
|
5天前
|
人工智能 Java 微服务
微服务保护方案
Spring Cloud微服务中,服务保护机制对保障系统稳定性至关重要,主要包括熔断、降级、超时、线程隔离和限流。熔断快速失败避免雪崩,降级提供默认响应保证核心功能,超时防止长时间等待,线程隔离限制故障影响范围,限流控制流量峰值,共同提升系统容错与可用性。
微服务保护方案
|
5天前
|
数据库 微服务 数据库连接
认识分布式事务
本文以“下单扣减库存”为例,对比单体与微服务架构下的事务处理差异,揭示分布式事务的挑战。在微服务场景中,跨服务调用依赖网络,本地事务无法保证全局一致性,易因网络问题导致数据不一致。文章进一步分析典型及非典型分布式事务场景,指出其根本原因在于多数据库或远程调用的协作复杂性。
认识分布式事务
|
5天前
|
缓存 前端开发 安全
数据同步原理
Soul网关通过推拉模式实现配置数据同步,支持WebSocket、HTTP长轮询和Zookeeper三种策略。管理员在后台变更配置后,事件被发布并根据同步策略推送到网关,实现秒级更新。HTTP长轮询借鉴Apollo与Nacos设计,结合异步Servlet机制,确保准实时且高效。
数据同步原理
|
5天前
|
存储 算法 BI
xxljob本地运行
本文介绍XXL-JOB分布式任务调度框架的部署与使用,涵盖源码获取、服务端数据库配置、客户端注册及任务调度配置,支持多种路由策略与分片广播,助力高效实现定时任务管理。
 xxljob本地运行
|
5天前
|
Java Maven 数据库
Activiti工程搭建
本教程介绍如何在IntelliJ IDEA中创建Maven工程并安装ActiBPM插件,包含插件下载、版本兼容性修复及配置方法,最后引入Activiti相关依赖,完成流程引擎环境搭建。
Activiti工程搭建
|
5天前
|
Java Sentinel 微服务
实现降级
本文介绍如何在Spring Cloud微服务中通过Sentinel实现Feign接口的降级处理。重点采用`FallbackFactory`方式,在调用方(如cart-service)为`ItemClient`接口编写降级逻辑,捕获远程调用异常并返回兜底数据。需配置Feign启用Sentinel,定义降级类实现`FallbackFactory`接口,并在`@FeignClient`中指定`fallbackFactory`。最终通过停止item-service进行测试,验证购物车页面在商品信息获取失败时仍可降级展示,保障系统稳定性。适用于服务熔断与容错场景。
实现降级
|
5天前
|
存储 运维 Java
【Docker入门】5分钟彻底搞懂镜像、容器与仓库:Docker的核心三剑客
Docker 通过“镜像、容器、仓库”三大核心实现“一次构建,到处运行”。镜像如食谱,容器是做好的菜,仓库似超市货架。用生活化比喻秒懂其原理与协作流程。