使用POI实现Excel导出导入 详细解释

前景:java中操作图形化API难免有些困难,这时就会有大神来封装这些API

目前热门:收费iText,免费apache-poi

使用办公文档的核心理想:把办公软件中的元素封装成java类,程序员只需要操作这些类就能够实现操作文档

pom依赖:

这里使用的是springboot进行整合

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

文档元素对应的java类 

Excel                 java类

文件    ==》  HSSFWorkbook

页       ==》  HSSFSheet

列       ==》  HSSFRow

行       ==》  HSSFCell

样式   ==》  HSSFCellStyle

导出

测试  

public static void main(String[] args) throws IOException {
    // 先获取到文件对象 HSSFWorkbook
    HSSFWorkbook workbook = new HSSFWorkbook();
    // 使用workbook创建页 HSSFSheet
    HSSFSheet sheet = workbook.createSheet("学生管理");// 当前页民称
    // 使用sheet创建行 HSSFRow
    HSSFRow row = sheet.createRow(0);// 第n行
    // 使用row创建HSSFCell
    HSSFCell cell = row.createCell(0); // 第n列
    // 在当前第0行第0列的表格中填写数据
    cell.setCellValue("姓名");
    // 在当前第0行第1列的表格中填写数据
    cell = row.createCell(1);
    cell.setCellValue("性别");
    // 创建输出流 文件夹必须存在 文件会自动创建		
    FileOutputStream os = new FileOutputStream("E:\\upload\\student.xls");
    workbook.write(os);
    // 关闭资源
    os.close();
    workbook.close();
}

 

模拟数据库导出 + 简化代码

public static void main(String[] args) throws IOException { 
    // 准备一个数组存储元素
    String[] data = {"1","张三","男","16"};
    // 准备一个数组作为标题
    String[] title = {"id","姓名","性别","年龄"};
    // 先获取到文件对象 HSSFWorkbook
    HSSFWorkbook workbook = new HSSFWorkbook();
    // 使用workbook创建页 HSSFSheet
    HSSFSheet sheet = workbook.createSheet("学生管理");// 当前页民称
    // 使用sheet创建行 HSSFRow
    HSSFRow row = sheet.createRow(0);// 下标从0开始 代表第一行[第一行存放标题]
    for (int i = 0; i < title.length; i++) {
        // 循环一次就创建一列
        HSSFCell cell = row.createCell(i); // 使用下标作为当前列
        cell.setCellValue(title[i]); // 存放数组中的每条数据
    }
    // 创建5行数据
    for (int i = 1; i <= 5; i++) { // 第一行是标题 从第二行开始
        HSSFRow sheetRow = sheet.createRow(i); // 循环一次创建一行
        for (int j = 0; j < data.length; j++) {
            HSSFCell cell = sheetRow.createCell(j);
            cell.setCellValue(data[j]);
        }
    }
    // 创建输出流 文件夹必须存在 文件会自动创建
    FileOutputStream os = new FileOutputStream("E:\\upload\\student.xls");
    workbook.write(os);
    // 关闭资源
    os.close();
    workbook.close();
}

 

将文件下载到客户端

注意:使用同步请求

测试页面:

<script>
    function filedownload(){
        location.href='/fileDownLoadTest'
    }
</script>
<input type="button" value="下载" onclick="filedownload()">
@RequestMapping("/fileDownLoadTest")
public void fileDownLoadTest(HttpServletResponse response) throws IOException {
    // 设置响应格式
    response.setContentType("application/octet-stream;charset=UTF-8");
    response.addHeader("Content-Disposition","attachment;filename=student.xls");
    // 获取输入流
    ServletOutputStream out = response.getOutputStream();
    // 创建输入流进行读取
    FileInputStream fis = new FileInputStream("E:\\upload\\student.xls");
    byte[] bytes = new byte[1024];
    int i = 0;
    while ((i=fis.read(bytes))!=-1){ // 读
        out.write(bytes,0,i); // 写
    }
    // 关闭资源
    fis.close();
    out.flush();
    // Tomcat会自动关闭资源
    // out.close();
}

优化:

代码流程:

操作磁盘会影响效率,所以可以去操作内存,不去再写入磁盘

将数据写入Excel后,用创建好的HSSFWorkbook对象直接去写输出流对象

HSSFWorkbook wb = new HSSFWorkbook();
// ...... 此过程省略 包含【导出】【响应格式】
ServletOutputStream out = response.getOutputStream();
wb.write(out);
out.flush();
wb.close();

导入

首先对于文件的上传需要满足三个条件:

  1. 表单组件标签必须使用:<input type="file"/>
  2. 请求方式必须是POST:因为文件上传是以二级制的方式传递,只有POST请求可以解析二进制数据;而且使用POST请求,对于参数的长度是没有限制的。
  3. 表单的编码格式必须是multipart/form-data:根据HTTP协议规定,浏览器每次向服务器提交参数时,都会对参数进行统一编码,默认采用的编码格式为urlencoded,这种编码格式只支持文本数据。浏览器向服务端提交数据时,首先会把参数统一转换成字符串,然后在对这些数据进行统一urlencoded编码

测试文件上传

页面:

<form action="/fileUpload" method="post" enctype="multipart/form-data">
  <input type="file" name="myFile">
  <input type="submit" value="提交">
</form>

如果使用ajax发送请求:

const file = document.getElementById('activityFile')
// 获取到文件
const fileElement = file.files[0];
const formData = new FormData(); // 可以提交二级制数据
formData.append('activityFile',fileElement) // key要和后端形参一直
$.ajax({
    url : '/activity/saveActivityList',
    data : formData,
    dataType : 'json',
    processData : false, // 设置ajax提交参数之前 是否将参数统一转换成字符串 默认是true
    contentType : false, // 设置ajax提交参数之前 是否将参数统一按urlencoded编码 默认是true
    type : 'post',
    success(data){
        // 回调逻辑
    }
})

 后端接收参数时,类型需要使用MultipartFile

注意:

如果项目使用的是SSM,需要在spring-mvc.xml文件中配置文件解析器

<!-- 配置上传文件工具 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!-- 规范上传文件的信息(编码) -->
    <property name="defaultEncoding" value="UTF-8"></property>
    <!-- 限制上传文件的大小 b-->
    <property name="maxUploadSize" value="10240000"></property>
</bean>

如果项目使用的springboot,不需要配置

后端:

@RequestMapping("/fileUpload")
@ResponseBody
public String fileUpload(MultipartFile myFile) throws IOException {
    // 获取源文件名
    String filename = myFile.getOriginalFilename();
    // 上传到那个路径
    File file = new File("E:\\upload\\"+filename);
    // 上传
    myFile.transferTo(file);
    return "ok";
}

测试文件导入:

注意:

  1. 在判断类型的时候,如果使用的是别的pom依赖,需要使用HSSFCell.xxx

  2. 如果使用的是博主的,使用CellType.xxx

public static void main(String[] args) throws IOException {
    // 指定导入的文件
    InputStream is = new FileInputStream("E:\\upload\\student.xls");
    // 创建HSSFWorkbook
    HSSFWorkbook wb = new HSSFWorkbook(is);
    // 通过wb对象获取HSSFSheet
    HSSFSheet sheet = wb.getSheetAt(0); // 通过下标获取,从0开始
    // 获取该页的最后一行下标,所以对于长度需要+1
    int lastRowNum = sheet.getLastRowNum();
    // 通过sheet对象获取HSSFRow
    for (int i = 0; i < lastRowNum+1; i++) {
        HSSFRow row = sheet.getRow(i);
        // 获取该行最好一列【最后一列是下标+1 对于长度不需要+1】
        int lastCellNum = row.getLastCellNum();
        // 通过row对象获取HSSFCell
        for (int j = 0; j < lastCellNum; j++) {
            HSSFCell cell = row.getCell(j);
            /*
                因为获取每一列数据时需要选择类型
                一个类型对应一个数字,数字不好记 但是常量好记
                HSSFCell封装了这些常量 这些常量对应着一些数字
             */
            if (cell.getCellType() == CellType.NUMERIC){ // 数值
                System.out.print(cell.getNumericCellValue()+" ");
            }else if (cell.getCellType() == CellType.STRING){ // 字符串
                System.out.print(cell.getStringCellValue()+" ");
            }else if (cell.getCellType() == CellType.BOOLEAN){ // 布尔
                System.out.print(cell.getBooleanCellValue()+" ");
            }else if (cell.getCellType() == CellType.FORMULA){ // 空白
                System.out.print(cell.getCellFormula()+" ");
            }else{
                System.out.println(""+" ");
            }
        }
        // 换行
        System.out.println();
    }
}

效果:

添加到数据库

在Excel中,数值后面都会有"xxx.0" , 如果数据库字段类型是数值类型,需要将".0"截取掉,否则会出现类型转换异常    

// 获取源文件名
String filename = activityFile.getOriginalFilename();
// 上传路径
File file = new File("E:\\upload\\"+filename);
// 上传
activityFile.transferTo(file);
// 读取
InputStream is = new FileInputStream(file);
// 创建HSSFWorkbook对象
HSSFWorkbook wb = new HSSFWorkbook(is);
HSSFSheet sheet = wb.getSheetAt(0);
int lastRowNum = sheet.getLastRowNum();
// 准备一个集合 
List<TblActivity> list = new ArrayList<>();
for (int i = 1; i < lastRowNum+1; i++) {
    HSSFRow row = sheet.getRow(i);
    int lastCellNum = row.getLastCellNum();
    for (int j = 0; j < lastCellNum; j++) {
        HSSFCell cell = row.getCell(j);
        String str = "";
        if (cell.getCellType() == CellType.NUMERIC){ // 数值
            str = cell.getNumericCellValue()+"";
        }else if (cell.getCellType() == CellType.STRING){ // 字符串
            str = cell.getStringCellValue()+" ";
        }else if (cell.getCellType() == CellType.BOOLEAN){ // 布尔
            str = cell.getBooleanCellValue()+" ";
        }else if (cell.getCellType() == CellType.FORMULA){ // 空白
            str = cell.getCellFormula()+" ";
        }else{
            str = ""+" ";
        }
        // 根据业务自行添加
        if (j == 0){
            activity.setName(str);
        }else if (j == 1){
            activity.setStartDate(str);
        }else if (j == 2){
            activity.setEndDate(str);
        }else if (j == 3){
            activity.setCost(str);
        }else if (j == 4){
            activity.setDescription(str);
        }
    }
    // 遍历完一个对象就添加到集合中
    list.add(activity);
}
// 将集合传入mapper
int i = activityService.saveActivityByList(list);

mapper接口:

int insertActivityByList(List<实体类> list);

mapper xml:

<insert id="insertActivityByList" parameterType="实体类全路径">
  insert into tbl_activity(id, owner, name, start_date, end_date, cost, description, create_time, create_by)
  values
  <foreach collection="list" item="a" separator=",">
    (#{a.id},#{a.owner},#{a.name},#{a.startDate},#{a.endDate},#{a.cost},#{a.description},#{a.createTime},#{a.createBy})
  </foreach>
</insert>

优化:

/*String filename = activityFile.getOriginalFilename();
File file = new File("E:\\upload\\"+filename);
activityFile.transferTo(file);
InputStream is = new FileInputStream(file);
HSSFWorkbook wb = new HSSFWorkbook(is);*/
InputStream is = activityFile.getInputStream();
HSSFWorkbook wb = new HSSFWorkbook(is);

想轻松实现导出导入:

 使用hutool工具类快速实现导出导入

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值