Excel读取并数据List/Map-POI

本文涉及的产品
RDS DuckDB + QuickBI 企业套餐,8核32GB + QuickBI 专业版
简介: 该工具类用于解析Excel文件(*.xls),通过POI读取数据并利用反射将每行数据映射到指定VO对象中,支持全局Map或List输出,适用于固定模板的数据导入场景。

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要保持一致,否则反射时候代码校验不通过


相关文章
|
前端开发 JavaScript 数据库
layui联动菜单搜索select表单选项的设置方法
layui联动菜单搜索select表单选项的设置方法
1268 0
|
11月前
|
JSON 关系型数据库 Java
国内五大报表工具横评:从数据兼容性到成本,教你避开选型坑!
在企业数据分析和报表开发中,能否选到合适的报表工具直接影响效率与成本。本文从图形、多样性数据源支持度、打印与导出、价格这4个方面对比国内主流报表软件:润乾报表、帆软报表、Smartbi、永洪、亿信。通过对比我们选择一款适合自己的工具。
|
JavaScript 算法 前端开发
layui框架实战案例(16):xm-select下拉多选插件实战记录(远程搜索、过滤、翻页、单选、提示文字)
layui框架实战案例(16):xm-select下拉多选插件实战记录(远程搜索、过滤、翻页、单选、提示文字)
3660 0
|
4月前
|
监控 Java 测试技术
OOM排查之路:一次曲折的线上故障复盘
本文记录了一次Paimon数据湖与RocksDB集成服务中反复出现的内存溢出(OOM)问题排查全过程。通过MAT、NMT、async-profiler等工具,结合监控分析与专家协作,最终定位到RocksDB通过JNI申请的堆外内存未释放是根因,并分享了转向Flink写入Paimon的解决方案及排查思路,为类似技术栈提供借鉴。(239字)
|
4月前
|
负载均衡 算法 Java
5-微服务篇
本文详解SpringBoot自动装配原理、启动流程、核心注解@SpringBootApplication组成,以及SpringCloud微服务中注册发现、负载均衡、限流熔断等机制,涵盖常用组件如Nacos、Ribbon、Feign、Sentinel及Gateway的使用与配置,适用于面试与实战。
|
7月前
|
人工智能 Java 机器人
基于Spring AI Alibaba + Spring Boot + Ollama搭建本地AI对话机器人API
Spring AI Alibaba集成Ollama,基于Java构建本地大模型应用,支持流式对话、knife4j接口可视化,实现高隐私、免API密钥的离线AI服务。
6475 2
基于Spring AI Alibaba + Spring Boot + Ollama搭建本地AI对话机器人API
|
人工智能 安全 Dubbo
Spring AI 智能体通过 MCP 集成本地文件数据
MCP 作为一款开放协议,直接规范了应用程序如何向 LLM 提供上下文。MCP 就像是面向 AI 应用程序的 USB-C 端口,正如 USB-C 提供了一种将设备连接到各种外围设备和配件的标准化方式一样,MCP 提供了一个将 AI 模型连接到不同数据源和工具的标准化方法。
8284 116
|
存储 Linux Docker
centos系统清理docker日志文件
通过以上方法,可以有效清理和管理CentOS系统中的Docker日志文件,防止日志文件占用过多磁盘空间。选择合适的方法取决于具体的应用场景和需求,可以结合手动清理、logrotate和调整日志驱动等多种方式,确保系统的高效运行。
1451 2
|
消息中间件 编解码 网络协议
Netty从入门到精通:高性能网络编程的进阶之路
【11月更文挑战第17天】Netty是一个基于Java NIO(Non-blocking I/O)的高性能、异步事件驱动的网络应用框架。使用Netty,开发者可以快速、高效地开发可扩展的网络服务器和客户端程序。本文将带您从Netty的背景、业务场景、功能点、解决问题的关键、底层原理实现,到编写一个详细的Java示例,全面了解Netty,帮助您从入门到精通。
2713 0

热门文章

最新文章