使用Java导出Excel表格并由浏览器直接下载——基于POI框架

目录

背景描述

技术准备

导出Excel——尝鲜版

导出Excel——封装版(通过反射)

导出Excel——深度封装(设置下拉选项)

 扩展——多个列分别是不同的下拉选项怎么封装

2019-10-28  更新,必看!!!

2019-12-18更新,修复小概率的文件名乱码问题


背景描述

最近博主在做的Web项目中,有一个导出数据到Excel表格的需求,之前用纯JS实现过,这次打算用Java在后端实现,将数据通过response以IO流的方式传输给前端,使浏览器能直接下载。这里做一下记录、笔记。

技术准备

我的项目是基于Spring Boot的,这里只贴出POI框架需要依赖的两个包,其他的都无所谓,只要能提供Controller让浏览器访问即可

<dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.14</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.14</version>
        </dependency>

导出Excel——尝鲜版

这里为了让大家理解POI这个框架一系列的API,先以最low的方式去实现,稍后我们再进行封装,达到“编写一次、处处可用”。

我们只需要提供一个Controller接口:


    /**
     *  导出数据到Excel
     * @param response 响应体
     * 注意,我这里是基于Spring Boot的,全局有一个@RestController注解,所以没加@ResponseBody,
     * 如果你的不是,请加上@ResponseBody注解
     * */
    @GetMapping(value = "/out-excel-demo")
    public Object outExcelDemo(HttpServletResponse response) throws IOException {
        //创建HSSFWorkbook对象(excel的文档对象)
        HSSFWorkbook wb = new HSSFWorkbook();
        //创建sheet对象(excel的表单)
        HSSFSheet sheet=wb.createSheet("sheet1");

        //创建第一行,这里即是表头。行的最小值是0,代表每一行,上限没研究过,可参考官方的文档
        HSSFRow row1=sheet.createRow(0);
        //在这一行创建单元格,并且将这个单元格的内容设为“账号”,下面同理。
        //列的最小值标识也是0
        row1.createCell(0).setCellValue("账号");
        row1.createCell(1).setCellValue("用户名");
        row1.createCell(2).setCellValue("日期");
        row1.createCell(3).setCellValue("是否完成");

        //第二行
        HSSFRow row2=sheet.createRow(1);
        row2.createCell(0).setCellValue("123456");
        row2.createCell(1).setCellValue("张三");
        row2.createCell(2).setCellValue("2019-08-05");
        row2.createCell(3).setCellValue("是");

        //第三行
        HSSFRow row3=sheet.createRow(2);
        row3.createCell(0).setCellValue("5681464");
        row3.createCell(1).setCellValue("李四");
        row3.createCell(2).setCellValue("2019-08-01");
        row3.createCell(3).setCellValue("否");

        //输出Excel文件
        OutputStream output=response.getOutputStream();
        response.reset();
        response
                .setHeader("Content-disposition", "attachment; filename=demo.xls");
        response.setContentType("application/x-xls");
        wb.write(output);
        output.close();
        return null;
    }

然后你可以在页面上写一个按钮,点击的时候通过location.href指向上面的接口路径,我这里就省略了,看一下效果:

打开表格:

 到这里,相信大家对POI有认识了吧?

其实它就是以每个HSSFRow为一个主体,每一个HSSFRow代表一行记录,我们只需要通过这个对象的createCell方法去创建单元格、赋值就行,这样就很清晰了吧?

导出Excel——封装版(通过反射)

以上我们实现了简单的数据导出,但是实际的场景根本不是这样,我们都是从数据库里查出来数据,而且不可能这样一行一行的去设置。

你肯定想到了循环,没错,循环是肯定的,但是仅仅循环还不够灵活,为什么呢?

根据面向对象的思维,我们可以将所有的表头(即第一行)做成一个List集合参数,将所有的数据做成一个List集合参数,这个数据集合的泛型是我们的POJO实体类,然后我们两个循环就能省略一大段代码。

但是问题来了,我们例子中的导出表格,是“账号、用户名、日期、是否完成”这四个表头,实体类也是对应的四个属性。假如又来了一个导出需求呢?表头不一样了,所对应的实体类也不一样了,难道我们再封装成一个其他的方法?难道每个不同的Excel表结构都要封装一个新的方法吗?

做的时候博主立马就想到了反射机制,我们可以传入List集合,对泛型不做限制,遍历数据集合的时候,通过反射得到这个对象的字段,动态赋值。

但是这就有一个强制要求:在实体类声明字段的时候,顺序必须和表头的前后顺序一致,否则循环遍历的时候会出现数据不对应的现象

首先我们声明一个实体类,这也符合我们真正的开发环境:

package com.dosion.smart.future.api.entity.activity.json;

import lombok.Data;

/**
 *  导出报名情况的数据传输对象
 * @author 秋枫艳梦
 * @date 2019-08-05
 * */
@Data
public class SignOutExcelJSON {
    //用户账号
    private String account;
    //用户名
    private String username;
    //报名时间
    private String signDate;
    //是否完成
    private String finish;
}

然后封装一个工具类出来:

package com.dosion.smart.future.utils;

import com.dosion.smart.future.api.entity.activity.json.SignOutExcelJSON;
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.ss.util.CellRangeAddress;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 *  数据导出excel,工具类
 * @author 秋枫艳梦
 * @date 209-08-05
 * */
public class ExcelUtil {

    /**
     *  生成Excel表格
Java中,利用JPA(Java Persistence API)框架进行数据库操作,然后结合Apache POI库来处理Excel文件,可以实现数据数据导出Excel提供下载功能。以下是一个基本步骤: 1. **添加依赖**: - 引入Spring框架Spring Data JPA依赖,如`spring-boot-starter-data-jpa`。 - 对于Excel操作,需要`poi`, `poi-ooxml`以及`apache poi-excel-servlet`或`xlsxwriter`等。 ```groovy dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.apache.poi:poi' implementation 'org.apache.poi:poi-ooxml' // 如果是Servlet环境,可能还需要这个 runtimeOnly 'org.apache.poi:poi-ooxml-schemas' } ``` 2. **配置JPA**: 在`application.properties` 或 `application.yml` 中配置数据库连接信息,包括JDBC URL、用户名、密码等。 3. **实体类和Repository**: 定义一个`@Entity`注解的实体类表示数据库表,Repository则用于查询JPA。 4. **Service层**: 创建一个服务类,通过JpaRepository获取到数据将其转换成`XSSFWorkbook`或`POIFSFileSystem`对象(用于创建Excel工作簿)。 5. **导出逻辑**: 使用Apache POI API将数据写入Excel,比如创建一个新的`HSSFWorkbook`对象,遍历结果集,添加行到Excel的工作表中。 6. **响应下载**: 如果是在Web应用中,可以使用`ServletResponse`对象设置响应头为"Content-Disposition",指定为attachment下载。例如: ```java response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setHeader("Content-Disposition", "attachment; filename=report.xlsx"); // 写入Excel内容 outputStream.write(workbook.getBytes(StandardCharsets.UTF_8)); ```
评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值