Java读取Excel


本文使用的技术是Alibaba集团开源的EasyExcel技术,该技术是针对Apache POI技术的封装和优化,主要解决了POI技术的耗内存问题,并且提供了较好的API使用。不需要大量的代码就可以实现excel的操作功能。

一、详解读取Excel

简单读取

对象

// 如果没有特殊说明,下面的案例将默认使用这个实体类
public class DemoData {
    private String string;
    private Date date;
    private Double doubleData;
    // getting setting
}

监听器

// 如果没有特殊说明,下面的案例将默认使用这个监听器
public class DemoDataListener extends AnalysisEventListener<DemoData> {

    List<DemoData> list = new ArrayList<DemoData>();
    
    /**
     * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
     */
    public DemoDataListener() {}

    /**
     * 这个每一条数据解析都会来调用
     *
     * @param data
     * @param context
     */
    @Override
    public void invoke(DemoData data, AnalysisContext context) {
        System.out.println("解析到一条数据:{}", JSON.toJSONString(data));
        list.add(data);
    }

    /**
     * 所有数据解析完成了 都会来调用
     *
     * @param context
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        System.out.println(JSON.toJSONString(list));
    }
}

代码

@Test
public void simpleRead() {
    // 写法1:
    String fileName = "demo.xlsx";
    // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
    EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead();

    // 写法2:
    fileName = "demo.xlsx";
    ExcelReader excelReader = EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).build();
    ReadSheet readSheet = EasyExcel.readSheet(0).build();
    excelReader.read(readSheet);
    // 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的
    excelReader.finish();
}

指定列的下标或名称

对象

public class DemoData {
    /**
     * 强制读取第三个 这里不建议 index 和 name 同时用,要么一个对象只用index,要么一个对象只用name去匹配
     */
    @ExcelProperty(index = 2)
    private Double doubleData;
    /**
     * 用名字去匹配,这里需要注意,如果名字重复,会导致只有一个字段读取到数据
     */
    @ExcelProperty("字符串标题")
    private String string;
    @ExcelProperty("日期标题")
    private Date date;
}

代码

@Test
public void indexOrNameRead() {
    String fileName = "demo.xlsx";
    // 这里默认读取第一个sheet
    EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead();
}

读取多个sheet

代码

@Test
public void repeatedRead() {
    String fileName = "demo.xlsx";
    // 读取全部sheet
    // 这里需要注意 DemoDataListener的doAfterAllAnalysed 会在每个sheet读取完毕后调用一次。然后所有sheet都会往同一个DemoDataListener里面写
    EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).doReadAll();

    // 读取部分sheet
    fileName = "demo.xlsx";
    ExcelReader excelReader = EasyExcel.read(fileName).build();
    // 这里为了简单 所以注册了 同样的head 和Listener 自己使用功能必须不同的Listener
    // readSheet参数设置读取sheet的序号
    ReadSheet readSheet1 =
        EasyExcel.readSheet(0).head(DemoData.class).registerReadListener(new DemoDataListener()).build();
    ReadSheet readSheet2 =
        EasyExcel.readSheet(1).head(DemoData.class).registerReadListener(new DemoDataListener()).build();
    // 这里注意 一定要把sheet1 sheet2 一起传进去,不然有个问题就是03版的excel 会读取多次,浪费性能
    excelReader.read(readSheet1, readSheet2);
    // 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的
    excelReader.finish();
}

自定义格式转换

对象

@Data
public class ConverterData {
    /**
     * converter属性定义自己的字符串转换器
     */
    @ExcelProperty(converter = CustomStringConverter.class)
    private String string;
    /**
     * 这里用string 去接日期才能格式化
     */
    @DateTimeFormat("yyyy年MM月dd日 HH时mm分ss秒")
    private String date;
    /**
     * 我想接收百分比的数字
     */
    @NumberFormat("#.##%")
    private String doubleData;
}

自定义转换器

public class CustomStringStringConverter implements Converter<String> {
    @Override
    public Class supportJavaTypeKey() {
        return String.class;
    }

    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.STRING;
    }

    /**
     * 这里读的时候会调用
     *
     * @param cellData
     *            NotNull
     * @param contentProperty
     *            Nullable
     * @param globalConfiguration
     *            NotNull
     * @return
     */
    @Override
    public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
        GlobalConfiguration globalConfiguration) {
        return "自定义:" + cellData.getStringValue();
    }

    /**
     * 这里是写的时候会调用 不用管
     *
     * @param value
     *            NotNull
     * @param contentProperty
     *            Nullable
     * @param globalConfiguration
     *            NotNull
     * @return
     */
    @Override
    public CellData convertToExcelData(String value, ExcelContentProperty contentProperty,
        GlobalConfiguration globalConfiguration) {
        return new CellData(value);
    }

}

代码

@Test
public void converterRead() {
    String fileName = "demo.xlsx";
    // 这里 需要指定读用哪个class去读,然后读取第一个sheet 
    EasyExcel.read(fileName, ConverterData.class, new ConverterDataListener())
        // 这里注意 我们也可以registerConverter来指定自定义转换器, 但是这个转换变成全局了, 所有java为string,excel为string的都会用这个转换器。
        // 如果就想单个字段使用请使用@ExcelProperty 指定converter
        // .registerConverter(new CustomStringStringConverter())
        // 读取sheet
        .sheet().doRead();
}

多行头

代码

@Test
public void complexHeaderRead() {
    String fileName = "demo.xlsx";
    // 这里 需要指定读用哪个class去读,然后读取第一个sheet 
    EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet()
        // 这里可以设置1,因为头就是一行。如果多行头,可以设置其他值。不传入默认1行
        .headRowNumber(1).doRead();
}

读取表头数据

监听器

/**
 * 这里会一行行的返回头
 * 监听器只需要重写这个方法就可以读取到头信息
 * @param headMap
 * @param context
 */
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
    LOGGER.info("解析到一条头数据:{}", JSON.toJSONString(headMap));
}

代码

@Test
public void headerRead() {
    String fileName = "demo.xlsx";
    // 这里 需要指定读用哪个class去读,然后读取第一个sheet
    EasyExcel.read(fileName, DemoData.class, new ReadDataListener()).sheet().doRead();
}

异常处理

监听器

/**
* 监听器实现这个方法就可以在读取数据的时候获取到异常信息
*/
@Override
public void onException(Exception exception, AnalysisContext context) {
    LOGGER.error("解析失败,但是继续解析下一行:{}", exception.getMessage());
    // 如果是某一个单元格的转换异常 能获取到具体行号
    // 如果要获取头的信息 配合invokeHeadMap使用
    if (exception instanceof ExcelDataConvertException) {
        ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception;
        LOGGER.error("第{}行,第{}列解析异常", excelDataConvertException.getRowIndex(),
            excelDataConvertException.getColumnIndex());
    }
}

web读取

代码

@PostMapping("upload")
@ResponseBody
public String upload(MultipartFile file) throws IOException {
    EasyExcel.read(file.getInputStream(), UploadData.class, new UploadDataListener(uploadDAO)).sheet().doRead();
    return "SUCCESS";
}
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: Age of Ai 设计师: meimeiellie
应支付0元
点击重新获取
扫码支付

支付成功即可阅读