Java使用poi/easyexcel操作excel

前言

在工作的开发过过程中,我们总会遇到将数据导出到excel的需求,和导入excel到数据库,下面会讲解当今比较流行的两个工具实现Java操作excel:

  1. Apache POI
  2. 阿里巴巴的easyexcel

POI介绍

使用poi会相对比较原生,相较于easyExcel比较复杂(easyExcel读写的时候可以做到一行代码就可以搞定,相当优雅)
Java使用poi/easyexcel操作excel_第1张图片
针对上图的基本功能的 1 ,2,workbook的实现类有三个接口。其中SXSSFWorkbook操作excel07版XSSF的升级,速度比XSSF更快。具体下面有写。
Java使用poi/easyexcel操作excel_第2张图片
Java使用poi/easyexcel操作excel_第3张图片
Java使用poi/easyexcel操作excel_第4张图片

POI实战-写的操作:

都入相关依赖

<!--xls 03-->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>3.9</version>
</dependency>

<!--xlsx 07版本-->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.9</version>
</dependency>

<!--      测试依赖-->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>

03版本写excel

@Test
public void writeExcel03() throws IOException {
    String path = "E:\\excel\\";
    //创建一个工作簿
    Workbook workbook = new HSSFWorkbook();
    //创建一个工作表
    Sheet sheet = workbook.createSheet("sheet01");
    //创建行
    Row row01 = sheet.createRow(0);//行从0开始,第一行
    //创建一个单元格
    Cell cell01 = row01.createCell(0);//列也是从0开始
    //设置单元格中的内容
    cell01.setCellValue("码农");

    Cell cell02 = row01.createCell(1);
    cell02.setCellValue("IT民工");

    FileOutputStream outputStream = new FileOutputStream(path + "码农.xls");
    //工作簿通过流写出
    workbook.write(outputStream);
    outputStream.close();

    System.out.println(">>>>>>>>excel 03 write finish");
}

07版本:跟03版本基本一样,只是工作簿的对象不同(03-HSSFWorkbook;07-XSSFWorkbook),和文件后缀的不同

@Test
public void writeExcel07() throws IOException {
    String path = "E:\\excel\\";
    //创建一个工作簿
    Workbook workbook = new XSSFWorkbook();
    //创建一个工作表
    Sheet sheet = workbook.createSheet("sheet01");
    //创建行
    Row row01 = sheet.createRow(0);//行从0开始,第一行
    //创建一个单元格
    Cell cell01 = row01.createCell(0);//列也是从0开始
    //设置单元格中的内容
    cell01.setCellValue("码农");

    Cell cell02 = row01.createCell(1);
    cell02.setCellValue("IT民工");

    FileOutputStream outputStream = new FileOutputStream(path + "07码农.xlsx");
    //工作簿通过流写出
    workbook.write(outputStream);
    outputStream.close();

    System.out.println(">>>>>>>>excel 07 write finish");
}

运行之后的效果图
Java使用poi/easyexcel操作excel_第5张图片

大文件的写入

Java使用poi/easyexcel操作excel_第6张图片

大文件写HSSF

下面例子用时 2秒

@Test
public void bigDatawriteExcel03() throws IOException {
    String path = "E:\\excel\\";
    long beginTime = System.currentTimeMillis();
    //创建一个工作簿
    Workbook workbook = new HSSFWorkbook();
    //创建一个工作表
    Sheet sheet = workbook.createSheet("sheet01");
    //创建行
    for (int i = 0; i< 65536; i ++) {
        Row row = sheet.createRow(i);
        for (int j = 0 ; j < 10; j++) {
            Cell cell = row.createCell(j);
            cell.setCellValue(j);
        }
    }

    FileOutputStream outputStream = new FileOutputStream(path + "bigData03码农.xls");
    //工作簿通过流写出
    workbook.write(outputStream);
    outputStream.close();
    long endTime = System.currentTimeMillis();


    System.out.println("用时" + ((endTime-beginTime) / 1000) + " 秒" );
}
大文件写XSSF

下面例子用时 7秒.
虽然它比03的用时长,但是它比03可以写更多的数据,比如超过6553行的数据都可以,而03的超过6553行就会报错

@Test
public void bigDatawriteExcel07() throws IOException {
    String path = "E:\\excel\\";
    long beginTime = System.currentTimeMillis();
    //创建一个工作簿
    Workbook workbook = new XSSFWorkbook();
    //创建一个工作表
    Sheet sheet = workbook.createSheet("sheet01");
    //创建行
    for (int i = 0; i< 65536; i ++) {
        Row row = sheet.createRow(i);
        for (int j = 0 ; j < 10; j++) {
            Cell cell = row.createCell(j);
            cell.setCellValue(j);
        }
    }

    FileOutputStream outputStream = new FileOutputStream(path + "bigData07码农.xlsx");
    //工作簿通过流写出
    workbook.write(outputStream);
    outputStream.close();
    long endTime = System.currentTimeMillis();


    System.out.println("用时" + ((endTime-beginTime) / 1000) + " 秒" );
}
大文件写SXSSF

Java使用poi/easyexcel操作excel_第7张图片
此例子用SXSSF用时1.5秒

@Test
public void bigDatawriteExcelS07() throws IOException {
    String path = "E:\\excel\\";
    long beginTime = System.currentTimeMillis();
    //创建一个工作簿
    Workbook workbook = new SXSSFWorkbook();
    //创建一个工作表
    Sheet sheet = workbook.createSheet("sheet01");
    //创建行
    for (int i = 0; i< 65536; i ++) {
        Row row = sheet.createRow(i);
        for (int j = 0 ; j < 10; j++) {
            Cell cell = row.createCell(j);
            cell.setCellValue(j);
        }
    }

    FileOutputStream outputStream = new FileOutputStream(path + "bigData07码农S.xlsx");
    //工作簿通过流写出
    workbook.write(outputStream);
    outputStream.close();

    long endTime = System.currentTimeMillis();


    System.out.println("用时" + ((endTime-beginTime) / 1000) + " 秒" );
}

实际开发过程中的导出数据的案例:

controller中

package com.qhy.test;

import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletResponse;

/**
 * @author qiuhongyu
 * @date 2022/3/24 14:09
 */
@Api(tags = "数据导出demo")
@RestController
@RequestMapping("/export")
public class ExportExcelController {
    
    @Autowired
    private ExportExcelService exportExcelService;
    
    @PostMapping("excelTest")
    public void exportExcel() {
        
        ServletRequestAttributes servletRequestAttributes
                = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletResponse response = servletRequestAttributes.getResponse();
        exportExcelService.exportExcel(response);
    }

 
    
    
}

service中

package com.qhy.test;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;

/**
 * @author qiuhongyu
 * @date 2022/3/24 14:13
 */
@Service
public class ExportExcelService {

    @Value("{export_excel_template}")
    private String exportExcelTemplate;

    public void exportExcel(HttpServletResponse response) {
        //获取导出的模板
        ClassPathResource classPathResource = new ClassPathResource(exportExcelTemplate);
        try (InputStream inputStream = classPathResource.getInputStream();
             ServletOutputStream outputStream = response.getOutputStream()) {
            //获取工作簿
            Workbook workbook = new HSSFWorkbook(inputStream);
            //获取工作表
            Sheet sheet = workbook.getSheet("sheetTest");

            //TODO (从数据库中查出要导出的数据)此处将相关数据写入到excel(在这还可以设置单元格的格式,背景颜色等)


             //设置导出的excel的文件名
            String excelName = java.net.URLEncoder.encode("demo导出Excel", "UTF-8");
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            //如果是xlsx格式的,那么ContenType就设置成下面的这种
            //  response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + excelName + ".xls");
            workbook.write(outputStream);

        }catch (Exception e) {

        }


    }
}

工具类

package com.qhy.test;

import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFColor;

/**
 * @author qiuhongyu
 * @date 2022/3/24 14:22
 */
public class ExportExcelUtil {

    /**
     * 获取列
     *
     * @param row
     * @param index
     * @return
     */
    public static Cell createOrGetCell(Row row, int index) {
        Cell cell = row.getCell(index);
        if (cell == null) {
            cell = row.createCell(index);
        }
        return cell;
    }

    /**
     * 获取行
     *
     * @param sheet
     * @param index
     * @return
     */
    public static Row createOrGetRow(Sheet sheet, int index) {
        Row row = sheet.getRow(index);
        if (row == null) {
            row = sheet.createRow(index);
        }
        return row;
    }

    /**
     * 设置单元格样式-百分比
     *
     * @param book
     * @return
     */
    public static CellStyle revertPercent(Workbook book) {
        CellStyle style = book.createCellStyle();
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setDataFormat(book.createDataFormat().getFormat("0.0%"));
        return style;
    }

    /**
     * 设置单元格样式-小数
     *
     * @param book
     * @return
     */
    public static CellStyle keepPoint(Workbook book) {
        CellStyle style = book.createCellStyle();
        style.setDataFormat(book.createDataFormat().getFormat("#0.000"));
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        return style;
    }

    /**
     * 设置单元格样式-整数
     *
     * @param book
     * @return
     */
    public static CellStyle keepInteger(Workbook book) {
        CellStyle style = book.createCellStyle();
        style.setDataFormat(book.createDataFormat().getFormat("###0"));
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        return style;
    }

    /**
     * 设置单元格样式-字符串,数字科学计数法
     *
     * @param book
     * @return
     */
    public static CellStyle strStyle(Workbook book) {
        CellStyle style = book.createCellStyle();
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setDataFormat(book.createDataFormat().getFormat("#,##0"));
        return style;
    }

    /**
     * 设置单元格的样式(字体,背景颜色等)
     * @param book
     * @param red
     * @param green
     * @param blue
     * @param horizontalAlignment
     * @param fontName
     * @param boldOrNOt
     * @param cellStyle
     * @return
     */
    public static CellStyle cellStyleForntColor(HSSFWorkbook book,
                                                int red,
                                                int green,
                                                int blue,
                                                HorizontalAlignment horizontalAlignment,
                                                String fontName,
                                                Boolean boldOrNOt,
                                                CellStyle cellStyle) {
        CellStyle style;
        if (cellStyle != null) {
            style = cellStyle;
        } else {
            style = book.createCellStyle();
        }
        style.setAlignment(horizontalAlignment);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        Font font = book.createFont();
        font.setFontName(fontName);
        font.setFontHeightInPoints((short) 10);
        font.setBold(boldOrNOt);
        style.setFont(font);
        HSSFPalette palette = book.getCustomPalette();
//        String color = "#C9DBFF";
//        String r = color.substring(1, 3);
//        String g = color.substring(3, 5);
//        String b = color.substring(5, 7);
//        int rc = Integer.parseInt(r, 16);
//        int gc = Integer.parseInt(g, 16);
//        int bc = Integer.parseInt(b, 16);
//        HSSFColor hssfColor = palette.findSimilarColor(201, 219, 255);
        HSSFColor hssfColor = palette.findSimilarColor(red, green, blue);
        style.setFillForegroundColor(hssfColor.getIndex());
        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        return style;
    }


    public static CellStyle xssfCellStyleForntColor(Workbook book,
                                                    int red,
                                                    int green,
                                                    int blue,
                                                    HorizontalAlignment horizontalAlignment,
                                                    String fontName,
                                                    Boolean boldOrNOt,
                                                    XSSFCellStyle cellStyle) {
        XSSFCellStyle style;
        if (cellStyle != null) {
            style = cellStyle;
        } else {
            style = (XSSFCellStyle) book.createCellStyle();
        }
        style.setAlignment(horizontalAlignment);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        Font font = book.createFont();
        font.setFontName(fontName);
        font.setFontHeightInPoints((short) 10);
        font.setBold(boldOrNOt);
        style.setFont(font);
//        1.行背景色
//        style.setFillForegroundColor(IndexedColors.BLUE.getIndex());
        //自定义
        style.setFillForegroundColor(new XSSFColor(new java.awt.Color(red, green, blue)));
        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        return style;
    }

    // 自适应宽度(中文支持)
    public static void setSizeColumn(HSSFSheet sheet, int size) {
        for (int columnNum = 0; columnNum < size; columnNum++) {
            int columnWidth = sheet.getColumnWidth(columnNum) / 256;
            for (int rowNum = 0; rowNum < sheet.getLastRowNum(); rowNum++) {
                HSSFRow currentRow;
                //当前行未被使用过
                if (sheet.getRow(rowNum) == null) {
                    currentRow = sheet.createRow(rowNum);
                } else {
                    currentRow = sheet.getRow(rowNum);
                }

                if (currentRow.getCell(columnNum) != null) {
                    HSSFCell currentCell = currentRow.getCell(columnNum);
                    if (currentCell.getCellType() == XSSFCell.CELL_TYPE_STRING) {
                        int length = currentCell.getStringCellValue().getBytes().length;
                        if (columnWidth < length) {
                            columnWidth = length;
                        }
                    }
                }
            }
            sheet.setColumnWidth(columnNum, columnWidth * 256);
        }
    }

}



POI实战-读的操作:

获取列的值的时候,每个单元格都有不同的类型,所以我们在获取的时候,根据类型取获取里面的值,不同类型的获取有不同的方法,如String类型获取的方法为getStringCellValue()。所以读取的时候一定要注意读取的类型,否则会读取失败。(读取不同的数据类型,下面有写,工作中这一块相对比较麻烦)
Java使用poi/easyexcel操作excel_第8张图片

03版本的读取

  @Test
    public void readExcel07() throws IOException {
        String path = "E:\\excel\\";
        //获取文件流
        FileInputStream inputStream = new FileInputStream(path + "07码农.xlsx");
        //获取一个工作簿
        Workbook workbook = new XSSFWorkbook(inputStream);
//        得到表
        Sheet sheet = workbook.getSheetAt(0);
        //得到行
        Row row = sheet.getRow(0);
//        得到列
        Cell cell = row.getCell(0);
        //getStringCellValue 获取的是字符串类型的
        String stringCellValue = cell.getStringCellValue();
        System.out.println(stringCellValue);
        inputStream.close();

    }

07版本的读取

 @Test
    public void readExcel07() throws IOException {
        String path = "E:\\excel\\";
        //获取文件流
        FileInputStream inputStream = new FileInputStream(path + "07码农.xlsx");
        //获取一个工作簿
        Workbook workbook = new XSSFWorkbook(inputStream);
//        得到表
        Sheet sheet = workbook.getSheetAt(0);
        //得到行
        Row row = sheet.getRow(0);
//        得到列
        Cell cell = row.getCell(0);
        //getStringCellValue 获取的是字符串类型的
        String stringCellValue = cell.getStringCellValue();
        System.out.println(stringCellValue);
        inputStream.close();

    }

读取不同的数据类型

如:excel中有葛总各样不同类型的数据,有字符串类型的,有时间类型的,有小数等
在这里插入图片描述
代码实现:不同的数据类型的读取都已经写好,有需要的直接拿来用即可

@Test
    public void testCellType() throws IOException {
        String path = "E:\\excel\\";
        //获取文件流
        FileInputStream inputStream = new FileInputStream(path + "03码农.xls");
        //获取一个工作簿
        Workbook workbook = new HSSFWorkbook(inputStream);
//        得到表
        Sheet sheet = workbook.getSheetAt(0);
        //得到行(获取标题:也就是第一行中的内容)
        Row rowTitle = sheet.getRow(0);
        //getPhysicalNumberOfCells()方法:获取这行中有多少个列
        int cellCount = rowTitle.getPhysicalNumberOfCells();
        for (int cellNum = 0; cellNum < cellCount; cellNum++) {
            //获取列
            Cell cell = rowTitle.getCell(cellNum);
            if (cell != null) {
                //获取类型
                CellStyle cellStyle = cell.getCellStyle();
            }

        }
        //获取表中内容

        //获取表的行数
        int rowCount = sheet.getPhysicalNumberOfRows();
        for (int rowNum = 0; rowNum < rowCount; rowNum++) {
            Row row = sheet.getRow(rowNum);
            if (row != null) {
//                读取列
                int cellCount2 = rowTitle.getPhysicalNumberOfCells();
                for (int cellNum = 0; cellNum < cellCount2; cellNum++) {
                    Cell cell = row.getCell(cellNum);
                    //匹配列的数据类型
                    if (cell != null) {
                        int cellType = cell.getCellType();
                        String cellValue = "";
                        switch (cellType) {
                            //字符串类型
                            case HSSFCell.CELL_TYPE_STRING:
                                cellValue = cell.getStringCellValue();
                                break;
                            //布尔类型
                            case HSSFCell.CELL_TYPE_BOOLEAN:
                                cellValue = String.valueOf(cell.getBooleanCellValue());
                                break;

                            //空类型
                            case HSSFCell.CELL_TYPE_BLANK:
                                //空就不需要读取了
                                break;
                            //数字类型(数字又分为 -日期数字,普通数字)
                            case HSSFCell.CELL_TYPE_NUMERIC:
                                //判断是不是日期类型
                                if (HSSFDateUtil.isCellDateFormatted(cell)) {
                                    //日期,就要转换成日期对应的格式
                                    Date dateCellValue = cell.getDateCellValue();
                                    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
                                    cellValue = simpleDateFormat.format(dateCellValue);
                                } else {
                                    //不是日期格式,防止数字过长,转换成科学计数法
                                    cell.setCellType(HSSFCell.CELL_TYPE_STRING);
                                    cellValue = cell.toString();
                                }
                                break;
                            //数据类型错误
                            case HSSFCell.CELL_TYPE_ERROR:
                                //错误也不需要写了
                                break;
                        }
                        System.out.println(cellValue);
                    }
                }
            }
        }
        inputStream.close();
    }

EasyExcel的使用

导入相关依赖(这里使用了比较新的版本3.0.5)

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>3.0.5</version>
        </dependency>
         
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.72</version>
        </dependency>

写数据

package com.qhy.easyexcel;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.excel.write.metadata.WriteSheet;
import org.junit.Test;

import java.util.Date;
import java.util.List;

/**
 * @author qiuhongyu
 * @date 2021/12/4 23:00
 */
public class EasyExcelTest {
    private List<DemoData> data() {
        List<DemoData> list = ListUtils.newArrayList();
        for (int i = 0; i < 10; i++) {
            DemoData data = new DemoData();
            data.setString("字符串" + i);
            data.setDate(new Date());
            data.setDoubleData(0.56);
            list.add(data);
        }
        return list;
    }

    @Test
    public void simpleWrite() {
        // 写法1 JDK8+
        // since: 3.0.0-beta1
        String   fileName ="D:\\easyexcel\\" + "码畜easyExcel" + ".xlsx";
        // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
        // 如果这里想使用03 则 传入excelType参数即可
        EasyExcel.write(fileName, DemoData.class)
                .sheet("模板")
                .doWrite(() -> {
                    // 分页查询数据
                    return data();
                });

        // 写法2
        fileName ="D:\\easyexcel\\" + "码畜easyExcel" + ".xlsx";
        // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
        // 如果这里想使用03 则 传入excelType参数即可
        EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());

        // 写法3
        fileName ="D:\\easyexcel\\" + "码畜easyExcel" + ".xlsx";
        // 这里 需要指定写用哪个class去写
        ExcelWriter excelWriter = null;
        try {
            excelWriter = EasyExcel.write(fileName, DemoData.class).build();
            WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
            excelWriter.write(data(), writeSheet);
        } finally {
            // 千万别忘记finish 会帮忙关闭流
            if (excelWriter != null) {
                excelWriter.finish();
            }
        }
    }
}

使用其中一种写法运行,结果
Java使用poi/easyexcel操作excel_第9张图片

读取数据

创建一个实体,用于接受读取的数据

@Getter
@Setter
@EqualsAndHashCode
public class DemoData {
    private String string;
    private Date date;
    private Double doubleData;
}

创建一个监听器

package com.qhy.easyexcel;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
@Slf4j
public class DemoDataListener implements ReadListener<DemoData> {

    /**
     * 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收
     */
    private static final int BATCH_COUNT = 100;
    /**
     * 缓存的数据
     */
    private List<DemoData> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
    /**
     * 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。
     */
    private DemoDAO demoDAO;

    public DemoDataListener() {
        // 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数
        demoDAO = new DemoDAO();
    }

    /**
     * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
     *
     * @param demoDAO
     */
    public DemoDataListener(DemoDAO demoDAO) {
        this.demoDAO = demoDAO;
    }

    /**
     * 这个每一条数据解析都会来调用(即:核心方法,读取数据会调用invoke方法)
     * DemoData 读取的类型
     * AnalysisContext 分析上下文
     */
    @Override
    public void invoke(DemoData data, AnalysisContext context) {
        System.out.printf( JSON.toJSONString(data));
        cachedDataList.add(data);
        /* 达到BATCH_COUNT了,需条要去存储一次数据库,防止数据几万数据在内存,容易OOM
        即:如果数据>=5条就会保存到数据库(这一步是将读取出来的内容保存到数据库,如果没有这样的需求就不用做持久化的操作)
         */
        if (cachedDataList.size() >= BATCH_COUNT) {
            saveData();
            // 存储完成清理 list
            cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
        }
    }

    /**
     * 所有数据解析完成了 都会来调用
     *
     * @param context
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 这里也要保存数据,确保最后遗留的数据也存储到数据库
        saveData();
        log.info("所有数据解析完成!");
    }

    /**
     * 加上存储数据库
     */
    private void saveData() {
        log.info("{}条数据,开始存储数据库!", cachedDataList.size());
        demoDAO.save(cachedDataList);
        log.info("存储数据库成功!");
    }
}

编写一个测试方法进行读取的操作

 /**
     * 最简单的读 (个人推荐写法3,一行代码搞定)
     * 

* 1. 创建excel对应的实体对象 参照{@link DemoData} *

* 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener} *

* 3. 直接读即可 */ Logger log = LoggerFactory.getLogger(EasyExcelTest.class); @Test public void simpleRead() { // 写法1:JDK8+ ,不用额外写一个DemoDataListener // since: 3.0.0-beta1 String fileName ="D:\\easyexcel\\" + "码畜easyExcel" + ".xlsx"; // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭 // 这里每次会读取3000条数据 然后返回过来 直接调用使用数据就行 EasyExcel.read(fileName, DemoData.class, new PageReadListener<DemoData>(dataList -> { for (DemoData demoData : dataList) { log.info("读取到一条数据{}", JSON.toJSONString(demoData)); } })).sheet().doRead(); // 写法2: // 匿名内部类 不用额外写一个DemoDataListener fileName ="D:\\easyexcel\\" + "码畜easyExcel" + ".xlsx"; // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭 EasyExcel.read(fileName, DemoData.class, new ReadListener<DemoData>() { /** * 单次缓存的数据量 */ public static final int BATCH_COUNT = 100; /** *临时存储 */ private List<DemoData> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT); @Override public void invoke(DemoData data, AnalysisContext context) { cachedDataList.add(data); if (cachedDataList.size() >= BATCH_COUNT) { saveData(); // 存储完成清理 list cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT); } } @Override public void doAfterAllAnalysed(AnalysisContext context) { saveData(); } /** * 加上存储数据库 */ private void saveData() { log.info("{}条数据,开始存储数据库!", cachedDataList.size()); log.info("存储数据库成功!"); } }).sheet().doRead(); // 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去 // 写法3: fileName ="D:\\easyexcel\\" + "码畜easyExcel" + ".xlsx"; // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭 EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead(); // 写法4: fileName ="D:\\easyexcel\\" + "码畜easyExcel" + ".xlsx"; // 一个文件一个reader ExcelReader excelReader = null; try { excelReader = EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).build(); // 构建一个sheet 这里可以指定名字或者no ReadSheet readSheet = EasyExcel.readSheet(0).build(); // 读取一个sheet excelReader.read(readSheet); } finally { if (excelReader != null) { // 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的 excelReader.finish(); } } }

运行读取的方法3后输出的数据(个人推荐使用方法3,一行代码就可以很优雅的搞定),这段输出语句是在监听器里面所写的
Java使用poi/easyexcel操作excel_第10张图片

你可能感兴趣的:(java)