欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

【Apache POI】Excel操作:Excel工具类的封装(最全版)

程序员文章站 2022-03-22 11:02:34
Excel工具类的封装,让你极大的简化对Excel的操作!!!时间飞逝,关于Apache POI对于Excel的操作就告一段落。下期博客将给大家带来Alibaba提供的工具EasyExcel,使用起来更加的方便,给大家打开新世界的大门,敬请期待哦!!!...
恋爱最珍贵的纪念品,从来就不是那些你送我的手表和项链,甚至也不是那些甜蜜的短信和合照。是你留在我身上的,如同河流留给山川的,那些你对我造成的改变。

前言

在我的 《Excel读写》 专栏的往期关于excel如何读取和写入的系列博客中,分别给大家介绍了如何运用实体类集合生成一张excel表格如何在本地导出excel表格如何在浏览器端导出excel表格以及如何将excel表格中的数据读取成实体类集合

但是,缺点在于代码量比较多。今天我们来统一将重复的逻辑抽成一个工具类方法,争取将以前几十行代码实现的功能几行来实现!!!

代码开整

环境准备

所需依赖:

	<!-- 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>joda-time</groupId>
		<artifactId>joda-time</artifactId>
		<version>2.10.1</version>
	</dependency>

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

所需实体类:

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

/**
 * @ClassName BookList
 * @Description 书单实体类
 * @Author 古阙月
 * @Date 2020/11/23 22:11
 * @Version 1.0
 */
//lombok插件的注解
@Data // 若未使用lombok插件,请自行生成getter、setter以及toString方法
@AllArgsConstructor // 若未使用lombok插件,请自行生成有参构造方法
@NoArgsConstructor // 若未使用lombok插件,请自行生成无参构造方法
@Accessors(chain = true) // 开启链式编程
public class Book {

    /**
     * 书名
     */
    private String bookName;

    /**
     * 作者
     */
    private String author;

    /**
     * 时间
     */
    private String dateTime;

}

生成实体类集合的方法:

	/**
     * 数据部分
     */
    private List<Book> getData() {

        List<Book> list = new ArrayList<Book>();
        for (int i = 0; i < 10; i++) {
            Book book = new Book();
            book.setAuthor("路遥")
                    .setBookName("平凡的世界" + (i+1))
                    .setDateTime(new DateTime().toString("yyyy-MM-dd HH:mm:ss"));
            list.add(book);
        }

        return list;
    }

生成excel表格的列名数组:

	/**
     * 列名部分
     */
    private static final String[] rowNameArray = {"书名", "作者", "时间"};

用于写入和读取excel文件的路径:

	/**
     * 需要写入excel的路径
     */
    private static final String PATH = "D:\\IdeaProjects\\my_study_demo\\src\\main\\java\\excel\\all";

用于写入和读取excel文件的名称:

	/**
     * 需要写入excel的文件名称
     */
    private static final String FILENAME = "古阙月的书单03.xls";

正式开整

实体类集合本地导出excel

在这期博客【Apache POI】Excel操作(二):Excel本地写入基本操作的实现(进阶版)中已经很详细的介绍了如何运用实体类集合在本地导出excel文件,但可惜用了五十多行代码。

我们试着来用一下工具类方法:

	 /**
     * 用实体类集合生成Excel
     */
    @Test
    public void writeExcelTest() throws Exception {

        // 生成一张工作簿
        Workbook workbook = ExcelUtil.getWorkBook(new HSSFWorkbook(), FILENAME, rowNameArray, getData());
        // 生成
        ExcelUtil.exportExcelLocal(workbook, PATH, FILENAME);
        System.out.println(FILENAME + "生成完毕!!!");
    }

运行得:
【Apache POI】Excel操作:Excel工具类的封装(最全版)
成功生成:
【Apache POI】Excel操作:Excel工具类的封装(最全版)
将几十行代码简化成几行代码,这就是造*的魅力!!!

完整的工具方法代码在最后!!!

实体类集合浏览器导出excel

在这期博客【Apache POI】Excel操作(三):Excel在浏览器端即Web端写入操作的实现中已经很详细的介绍了如何运用实体类集合在浏览器端导出excel文件,但是代码量也比较多竟然用了六七十行代码!!!

我们也来使用一下工具方法:

	 /**
      * 在浏览器导出excel
     */
    @GetMapping("/exportExcel")
    public void exportExcelTest(HttpServletResponse response) {

        try {
            // 生成一张工作簿
            Workbook workbook = ExcelUtil.getWorkBook(new HSSFWorkbook(), FILENAME, rowNameArray, getData());
            // 导出
            ExcelUtil.exportExcelWeb(response, workbook, FILENAME);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

浏览器访问:
【Apache POI】Excel操作:Excel工具类的封装(最全版)
点开得:
【Apache POI】Excel操作:Excel工具类的封装(最全版)
如此的简洁,是不是很舒服?

当然,Web工程环境的搭建可以参照我这篇博客:
【Apache POI】Excel操作(一):Excel本地写入基本操作的实现
中<前期准备>章节给出的博客链接,此处就不多加赘述!

完整的工具方法代码在最后!!!

将excel读取成实体类集合

在这期博客【Apache POI】Excel操作(七):Excel数据的读取(进阶版)中已经很详细的介绍了如何将excel文件读取陈实体类集合,但是竟然用了八十多行代码,要是以后每次读取都用个八十多行代码还得了!

同样的,我们来使用一下工具方法:

	/**
     * 读取excel成实体类集合
     */
    @Test
    public void readExcelTest() throws Exception {

        /**
         * 获取excel工作簿
         */
        FileInputStream fileInputStream = new FileInputStream(PATH + File.separator + FILENAME);
        Workbook workbook = new HSSFWorkbook(fileInputStream);

        // 得到实体类集合
        List<Object> entityListFromExcel = ExcelUtil.getEntityListFromExcel(new Book(), workbook);
        // 输出实体类集合
        entityListFromExcel.forEach(book -> {
            System.out.println(book);
        });
    }

运行:
【Apache POI】Excel操作:Excel工具类的封装(最全版)读取成功,同样的八十多行代码竟用短短的几行代码就完成了!!!

完整的工具方法代码在最后!!!

完整工具类代码

此处免费给出完整的工具类代码:

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.joda.time.DateTime;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @ClassName ExcelUtil
 * @Description Excel工具类
 * @Author 古阙月
 * @Date 2020/11/20
 * @Version 1.0
 */
public class ExcelUtil {

    /**
     * 生成一张Excel工作簿 - 注意列名数组和实体类集合中实体类的属性名称顺序一一对应
     * @param workbook 用以返回的Excel工作簿对象
     * @param sheetName 工作表名称
     * @param columnNameArray 列名数组
     * @param entityList 实体类集合
     * @return
     */
    public static Workbook getWorkBook(Workbook workbook, String sheetName, String[] columnNameArray, List<?> entityList) throws Exception {

        // 创建工作表
        Sheet sheet = workbook.createSheet(sheetName);

        if (sheet != null) {
            /**
             * 列名部分
             */
            Row columnNameRow = sheet.createRow(0); // 生成列名的这一行,也就是第一行
            if (columnNameRow != null) {
                for (int i = 0; i < columnNameArray.length; i++) {
                    // 按顺序依次填值
                    Cell cell = columnNameRow.createCell(i);
                    if (cell != null) {
                        cell.setCellValue(columnNameArray[i]);
                    }
                }
            }

            /**
             * 数据部分
             */
            for (int i = 0; i < entityList.size(); i++) {
                // 生成第 i+2 行,因为第一行是列名,所以是i+1,而不是i
                Row row = sheet.createRow(i + 1);

                if (row != null) {
                    // 获取当前遍历得到的实体类
                    Object entity = entityList.get(i);
                    // 获取实体类的所有属性集合
                    Field[] fields = entity.getClass().getDeclaredFields();
                    // 遍历属性集合
                    for (int j = 0; j < fields.length; j++) {

                        // 私有属性访问授权
                        fields[j].setAccessible(true);

                        //填值
                        Cell cell = row.createCell(j);
                        if (cell != null) {
                            cell.setCellValue(((String)fields[j].get(entity)));
                        }
                    }
                }

            }
        }
        return workbook;
    }

    /**
     * 本地根据路径和名称导出excel
     * @param workbook excel工作簿对象
     * @param path 路径
     * @param fileName 文件名
     */
    public static void exportExcelLocal(Workbook workbook, String path, String fileName) throws Exception {

        FileOutputStream outputStream = new FileOutputStream(path + File.separator + fileName);
        workbook.write(outputStream);
        // 关流
        outputStream.close();
    }

    /**
     * 在浏览器端导出excel
     * @param response
     * @param workbook
     * @param fileName
     */
    public static void exportExcelWeb(HttpServletResponse response, Workbook workbook, String fileName) {

        response.reset();
        response.setContentType("application/ms-excel;charset=UTF-8");
        try {
            response.addHeader("Content-Disposition", "attachment;filename=\""
                    + new String((fileName).getBytes("GBK"),
                    "ISO8859_1") + "\"");
            OutputStream out = response.getOutputStream();
            // 写入
            workbook.write(out);
            out.flush();
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 读取excel获取到相应的实体类集合
     * @param object 需要转化成的对象
     * @param workbook 工作簿对象
     * @return
     */
    public static List<Object> getEntityListFromExcel(Object object, Workbook workbook) throws Exception {

        // 用于返回数据的实体类集合
        List<Object> entityList = new ArrayList<>();
        // 获取反射对象
        Class<?> clazz = object.getClass();
        if (workbook != null) {
            // 获取工作表
            Sheet sheet = workbook.getSheetAt(0);

            if (sheet != null) {

                // 获取行数
                int rowNum = sheet.getPhysicalNumberOfRows();
                if (rowNum > 1) { // 第一行是列名
                    for (int i = 1; i < rowNum; i++) { // 从第二行,也就是数据部分开始
                        // 获取行
                        Row row = sheet.getRow(i);

                        if (row != null) {
                            // 获取列数
                            int cellNum = row.getPhysicalNumberOfCells();

                            // 生成对象
                            Object obj = clazz.newInstance();
                            // 获取属性集合
                            Field[] fields = clazz.getDeclaredFields();
                            for (int j = 0; j < cellNum; j++) {
                                // 获取列
                                Cell cell = row.getCell(j);

                                String cellValue = "";
                                // 获取列对应的数据类型
                                int cellType = cell.getCellType();
                                switch (cellType) {
                                    case HSSFCell.CELL_TYPE_STRING: // 字符串类型
                                        cellValue = cell.getStringCellValue();
                                        break;
                                    case HSSFCell.CELL_TYPE_BLANK: // 空
                                        break;
                                    case HSSFCell.CELL_TYPE_BOOLEAN: // 布尔类型
                                        cellValue = String.valueOf(cell.getBooleanCellValue());
                                        break;
                                    case HSSFCell.CELL_TYPE_NUMERIC: // 数字
                                        if (HSSFDateUtil.isCellDateFormatted(cell)) { // 日期类型
                                            Date dateCellValue = cell.getDateCellValue();
                                            cellValue = new DateTime(dateCellValue).toString("yyyy-MM-dd HH:mm:ss");
//                                            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//                                            cellValue = format.format(dateCellValue);
                                        }else { // 普通数字
                                            // 转化成字符串,防止数字过长无法显示
                                            cell.setCellType(HSSFCell.CELL_TYPE_STRING);
                                            cellValue = String.valueOf(cell);
//                                            cellValue = cell.getNumericCellValue();
                                        }
                                        break;
                                    case HSSFCell.CELL_TYPE_ERROR: // 类型错误
                                        throw new RuntimeException("类型错误!");
                                }

                                // 私有属性访问授权
                                fields[j].setAccessible(true);
                                // 往对象中放值
                                fields[j].set(obj, cellValue);
                            }

                            // 添加
                            entityList.add(obj);
                        }
                    }
                }

            }
        }
        return entityList;
    }
}

时间飞逝,关于Apache POI对于Excel的操作就告一段落。下期博客将给大家带来Alibaba提供的工具EasyExcel,使用起来更加的方便,给大家打开新世界的大门,敬请期待哦!!!

往期回顾

以下是往期Excel操作的回顾:

【Apache POI】Excel操作(一):Excel本地写入基本操作的实现

【Apache POI】Excel操作(二):Excel本地写入基本操作的实现(进阶版)

【Apache POI】Excel操作(三):Excel在浏览器端即Web端写入操作的实现

【Apache POI】Excel操作(四):Excel大数据量的写入

【Apache POI】Excel操作(五):Excel数据的读取

【Apache POI】Excel操作(六):Excel计算公式的读取和使用

【Apache POI】Excel操作(七):Excel数据的读取(进阶版)

本文地址:https://blog.csdn.net/Qizhi_Hu/article/details/110100300