基于poi的Excel读取器

1.工具方法:
package com.visy.utils;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.*;
import java.util.function.Function;

/**
 * @author visy.wang
 * @description: 基于poi的Excel读取器
 * @date 2023/2/16 15:09
 */
public class ExcelReader {
    private static final ObjectMapper objectMapper = new ObjectMapper();
    static {
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    public static List<Map<String,Object>> readToMapList(File file){
        return readToList(file, null, null);
    }
    public static List<Map<String,Object>> readToMapList(File file, Integer sheetIndex){
        return readToList(file, sheetIndex, null);
    }
    public static List<Map<String,Object>> readToMapList(File file, String sheetName){
        return readToList(file, null, sheetName);
    }
    public static <T> List<T> readToEntityList(File file, Class<T> clazz){
        return readToList(file, null, null, clazz);
    }
    public static <T> List<T> readToEntityList(File file, Integer sheetIndex, Class<T> clazz){
        return readToList(file, sheetIndex, null, clazz);
    }
    public static <T> List<T> readToEntityList(File file, String sheetName, Class<T> clazz){
        return readToList(file, null, sheetName, clazz);
    }
    public static List<Map<String,Object>> readToMapList(MultipartFile file){
        return readToList(file, null, null);
    }
    public static List<Map<String,Object>> readToMapList(MultipartFile file, Integer sheetIndex){
        return readToList(file, sheetIndex, null);
    }
    public static List<Map<String,Object>> readToMapList(MultipartFile file, String sheetName){
        return readToList(file, null, sheetName);
    }
    public static <T> List<T> readToEntityList(MultipartFile file, Class<T> clazz){
        return readToList(file, null, null, clazz);
    }
    public static <T> List<T> readToEntityList(MultipartFile file, Integer sheetIndex, Class<T> clazz){
        return readToList(file, sheetIndex, null, clazz);
    }
    public static <T> List<T> readToEntityList(MultipartFile file, String sheetName, Class<T> clazz){
        return readToList(file, null, sheetName, clazz);
    }

    private static List<Map<String,Object>> readToList(File file, Integer sheetIndex, String sheetName){
        try (InputStream inputStream = getInputStream(file)){
            String fileName = file.getName();//文件名
            if (isExcelFile(fileName)) {
                return readToList(isXlsx(fileName), inputStream, sheetIndex, sheetName);
            }
            System.out.println("文件格式不正确");
            return Collections.emptyList();
        }catch (IOException e){
            System.out.println("文件读取失败:"+e.getMessage());
            return Collections.emptyList();
        }
    }

    private static <T> List<T> readToList(File file, Integer sheetIndex, String sheetName, Class<T> clazz){
        try (InputStream inputStream = getInputStream(file)){
            String fileName = file.getName();//文件名
            if (isExcelFile(fileName)) {
                return readToList(isXlsx(fileName), inputStream, sheetIndex, sheetName, clazz);
            }
            System.out.println("文件格式不正确");
            return Collections.emptyList();
        }catch (IOException e){
            System.out.println("文件读取失败:"+e.getMessage());
            return Collections.emptyList();
        }
    }

    private static List<Map<String,Object>> readToList(MultipartFile file, Integer sheetIndex, String sheetName){
        try (InputStream inputStream = getInputStream(file)){
            String fileName = file.getOriginalFilename();
            if (isExcelFile(fileName)) {
                return readToList(isXlsx(fileName), inputStream, sheetIndex, sheetName);
            }
            System.out.println("文件格式不正确");
            return Collections.emptyList();
        }catch (IOException e){
            System.out.println("文件读取失败:"+e.getMessage());
            return Collections.emptyList();
        }
    }
    private static <T> List<T> readToList(MultipartFile file, Integer sheetIndex, String sheetName, Class<T> clazz){
        try (InputStream inputStream = getInputStream(file)){
            String fileName = file.getOriginalFilename();
            if (isExcelFile(fileName)) {
                return readToList(isXlsx(fileName), inputStream, sheetIndex, sheetName, clazz);
            }
            System.out.println("文件格式不正确");
            return Collections.emptyList();
        }catch (IOException e){
            System.out.println("文件读取失败:"+e.getMessage());
            return Collections.emptyList();
        }
    }

    private static List<Map<String,Object>> readToList(boolean isXlsx, InputStream inputStream,
                                          Integer sheetIndex, String sheetName){
        return readToList(isXlsx, inputStream, sheetIndex, sheetName, Function.identity());
    }
    private static <T> List<T> readToList(boolean isXlsx, InputStream inputStream,
                                          Integer sheetIndex, String sheetName, Class<T> clazz){
        return readToList(isXlsx, inputStream, sheetIndex, sheetName, mp -> mapToEntity(mp, clazz));
    }

    /**
     * 通过输入流读取Excel
     * @param inputStream 输入流
     * @param sheetIndex sheet下标(从0开始,优先级高于“sheetName”)
     * @param sheetName sheet名称 sheetIndex和sheetName都为空时读取所有的Sheet
     * @param f 将行数据映射为一个实体的转换器函数
     * @return 数据列表
     * @param <T> 行数据实体类型
     */
    private static <T> List<T> readToList(boolean isXlsx, InputStream inputStream,
                                          Integer sheetIndex, String sheetName, Function<Map<String,Object>,T> f){
        try(Workbook wb = isXlsx ? (new XSSFWorkbook(inputStream)) : (new HSSFWorkbook(inputStream))){
            int numberOfSheets = wb.getNumberOfSheets();

            if(Objects.nonNull(sheetIndex)){
                if(sheetIndex<0 || sheetIndex>=numberOfSheets){
                    return Collections.emptyList();
                }
                return readSheet(wb.getSheetAt(sheetIndex), f);
            }else if(StringUtils.isNotBlank(sheetName)){
                return readSheet(wb.getSheet(sheetName), f);
            }else {
                List<T> list = new ArrayList<>();
                for(int i=0; i<numberOfSheets; i++){
                    list.addAll(readSheet(wb.getSheetAt(i), f));
                }
                return list;
            }
        }catch (IOException e){
            System.out.println("Excel读取出错:"+ e.getMessage());
            return Collections.emptyList();
        }
    }

    private static <T> List<T> readSheet(Sheet sheet, Function<Map<String,Object>,T> f){
        List<T> list = new ArrayList<>();

        if(Objects.isNull(sheet)){
            return list;
        }

        System.out.println("正在读取Sheet: "+sheet.getSheetName());

        Row titles = sheet.getRow(0);

        for (int rowIndex=1; rowIndex<sheet.getPhysicalNumberOfRows(); rowIndex++) {
            Row row = sheet.getRow(rowIndex);
            if (Objects.isNull(row)){
                continue;
            }

            Map<String,Object> item = new HashMap<>();
            for(int colIndex=0; colIndex<titles.getPhysicalNumberOfCells(); colIndex++){
                String colName = titles.getCell(colIndex).getStringCellValue();

                Cell cell = row.getCell(colIndex);
                Object cellVal = readCellVal(cell);

                item.put(colName, cellVal);
            }

            list.add(f.apply(item));
        }

        return list;
    }

	//读取单元格的值,写得比较简单,可进一步修改
	//建议cell.setCellType(CellType.STRING);
	//然后统一按String读取:cell.getStringCellValue();
    private static Object readCellVal(Cell cell){
        if(Objects.isNull(cell)){
            return null;
        }

        CellType type = cell.getCellTypeEnum();

        if(CellType.STRING.equals(type)){
            return cell.getStringCellValue();
        }else if(CellType.NUMERIC.equals(type)){
            return cell.getNumericCellValue();
            //return cell.getDateCellValue();
        }else if (CellType.BOOLEAN.equals(type)){
            return cell.getBooleanCellValue();
        }else if (CellType.BLANK.equals(type)){
            return null;
        }else if (CellType.FORMULA.equals(type)){
            return cell.getCellFormula();
        }else if (CellType.ERROR.equals(type)){
            return cell.getErrorCellValue();
        }else {
            return null;
        }
    }

    private static boolean isExcelFile(String fileName){
        return fileName.endsWith(".xls") || fileName.endsWith(".xlsx");
    }

    private static InputStream getInputStream(File file) throws IOException {
        return Files.newInputStream(file.toPath());
    }
    private static InputStream getInputStream(MultipartFile file) throws IOException {
        return file.getInputStream();
    }

    private static boolean isXlsx(String fileName){
        return Objects.nonNull(fileName) && fileName.endsWith(".xlsx");
    }

    private static <T> T mapToEntity(Map<String,Object> mp, Class<T> clazz){
        //实际使用也可以:
        //自定义注解添加到类T的字段上
        //通过clazz反射及注解生成T的实体并写入字段值
        //反射可考虑缓存中间量

        //此处直接使用JSON工具,字段名需和表格标题名对应,不一样需注解标注
        return objectMapper.convertValue(mp, clazz);
    }
}
2.测试类:
package com.visy.utils.test;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.visy.utils.ExcelReader;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * @author visy.wang
 * @description:
 * @date 2023/2/17 15:27
 */
public class ExcelReaderTest {

    public static void main(String[] args) throws IOException {
        //excel存在“id”,“address”, "flag"等标题的列
        String path = "E:\\test\\data.xlsx";

        File file = new File(path);

		//读取第一个sheet的数据到Map列表
        List<Map<String,Object>> mapList = ExcelReader.readToMapList(file, 0);
        //List<Map<String,Object>> mapList = ExcelReader.readToMapList(file, "Sheet1");
        System.out.println("mapList记录数:"+mapList.size());
        mapList.forEach(System.out::println);

        System.out.println("-----------------------------------");

		//读取第一个sheet的数据到Entity实体列表
        List<Entity> entityList = ExcelReader.readToEntityList(file, 0, Entity.class);
        //List<Entity> entityList = ExcelReader.readToEntityList(file, "Sheet1", Entity.class);
        System.out.println("entityList记录数:"+entityList.size());
        entityList.forEach(System.out::println);
    }


    static class Entity{
        private Long id;
        private String address;
        @JsonProperty("flag") //标注别名
        private Integer flaggg;

        public String getAddress() {
            return address;
        }

        public void setAddress(String address) {
            this.address = address;
        }

        public Long getId() {
            return id;
        }

        public void setId(Long id) {
            this.id = id;
        }

        public Integer getFlaggg() {
            return flaggg;
        }

        public void setFlaggg(Integer flaggg) {
            this.flaggg = flaggg;
        }

        @Override
        public String toString() {
            return "Entity{" +
                    "address='" + address + '\'' +
                    ", id=" + id +
                    ", flaggg=" + flaggg +
                    '}';
        }
    }
}
3.打印:

略。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值