POI的使用
创始人
2024-03-03 07:13:10
0

POI简介(Apache POI),Apache POI是Apache软件基金会的开放源码函式库,POI提供API给Java程序对Microsoft Office格式档案读和写的功能。
Apache POI官网

  • HSSF - 提供读写Microsoft Excel格式档案的功能。(.xls)
  • XSSF - 提供读写Microsoft Excel OOXML格式档案的功能。(.xlsx)
  • HWPF - 提供读写Microsoft Word格式档案的功能。
  • HSLF - 提供读写Microsoft PowerPoint格式档案的功能。
  • HDGF - 提供读写Microsoft Visio格式档案的功能。

环境准备

  • 创建普通Maven项目
  • 导入相关依赖
org.apache.poipoi4.1.2org.apache.poipoi-ooxml4.1.2joda-timejoda-time2.10.1junitjunit4.12

写Excel的功能

我们需要导出效果如下:
在这里插入图片描述
Excel的文件格式分为Excel2003【后缀名为xls】和Excel2007【后缀名为xlsx】两种,这两种的代码基本上一致的.

  • Excel2003写的功能
@Test
public void testWrite03() throws IOException {// 创建新的Excel 工作簿Workbook workbook = new HSSFWorkbook();// 在Excel工作簿中建一工作表,其名为默认名 Sheet0//Sheet sheet = workbook.createSheet();// 如要新建一名为"会员登录统计"的工作表,其语句为:Sheet sheet = workbook.createSheet("疫苗接种统计");// 创建行(row 1)Row row1 = sheet.createRow(0);// 创建单元格(col 1-1)第一行的第一列Cell cell11 = row1.createCell(0);//设置单元格中的内容cell11.setCellValue("今日人数");// 创建单元格(col 1-2)第一行的第二列Cell cell12 = row1.createCell(1);cell12.setCellValue(666);// 创建行(row 2)Row row2 = sheet.createRow(1);// 创建单元格(col 2-1)第二行的第一列Cell cell21 = row2.createCell(0);cell21.setCellValue("统计时间");//创建单元格(col 2-2)第二行的第二列Cell cell22 = row2.createCell(1);String dateTime = new DateTime().toString("yyyy-MM-dd HH:mm:ss");cell22.setCellValue(dateTime);// 新建一输出文件流(注意:要先创建文件夹)FileOutputStream out = new FileOutputStream("d:/test-write03.xls");// 把相应的Excel 工作簿存盘,如果是在修改该文件时,不能打开该文件,io正在占用导致无法写入workbook.write(out);// 操作结束,关闭流out.close();//关闭工作簿workbook.close();System.out.println("文件生成成功");
}
  • Excel2007写功能
@Test
public void testWrite07() throws IOException {// 创建新的Excel 工作簿Workbook workbook = new XSSFWorkbook();// 新建一输出文件流(注意:要先创建文件夹)FileOutputStream out = new FileOutputStream("d:/test-write07.xlsx");//和上面一样,只是用到的工作簿对象不一样和文件后缀名不一样
}

大文件写入

  • 使用HSSF【Excel2003】

缺点:最多只能处理65536行,否则会抛出异常

java.lang.IllegalArgumentException: Invalid row number (65536) outside allowable range (0…65535)

优点:过程中写入缓存,不会操作磁盘,最后一次性写入磁盘,速度快

@Test
public void testWrite03BigData() throws IOException {//记录开始时间long begin = System.currentTimeMillis();//创建一个HSSFWorkbookWorkbook workbook = new HSSFWorkbook();//创建一个sheetSheet sheet = workbook.createSheet();//xls文件最大支持65536行for (int rowNum = 0; rowNum < 65537; rowNum++) {//创建一个行Row row = sheet.createRow(rowNum);for (int cellNum = 0; cellNum < 10; cellNum++) {//创建单元格Cell cell = row.createCell(cellNum);cell.setCellValue(cellNum);}}System.out.println("done");FileOutputStream out = new FileOutputStream("d:/test-write03-bigdata.xls");workbook.write(out);// 操作结束,关闭文件out.close();//记录结束时间long end = System.currentTimeMillis();System.out.println((double)(end - begin)/1000);
}
  • 使用XSSF【Excel2007】

缺点:写数据时速度非常慢,非常耗内存,也会发生内存溢出,如100万条

优点:可以写较大的数据量,如20万条

@Test
public void testWrite07BigData() throws IOException {...//创建一个XSSFWorkbookWorkbook workbook = new XSSFWorkbook();...FileOutputStream out = new FileOutputStream("d:/test-write07-bigdata.xlsx");...
}
  • 使用SXSSF

优点:可以写非常大的数据量,如100万条甚至更多条,写数据速度快,占用更少的内存

注意:

过程中会产生临时文件,需要清理临时文件

默认由100条记录被保存在内存中,如果超过这数量,则最前面的数据被写入临时文件

如果想自定义内存中数据的数量,可以使用new SXSSFWorkbook(数量)

@Test
public void testWrite07BigDataFast() throws IOException {//记录开始时间long begin = System.currentTimeMillis();//时间戳毫秒数//创建一个SXSSFWorkbookWorkbook workbook = new SXSSFWorkbook();...FileOutputStream out = new FileOutputStream("d:/test-write07-bigdata-fast.xlsx");//写.....workbook.write(out);// 操作结束,关闭文件out.close();//强转真实类型,清除临时文件((SXSSFWorkbook)workbook).dispose();//记录结束时间long end = System.currentTimeMillis();System.out.println((double)(end - begin)/1000);
}

SXSSFWorkbook-来至官方的解释:实现“BigGridDemo”策略的流式XSSFWorkbook版本。这允许写入非常大的文件而不会耗尽内存,因为任何时候只有可配置的行 部分被保存在内存中。

请注意,仍然可能会消耗大量内存,这些内存基于您正在使用的功能,例如单元格合并区域,注释…仍然只存储在内存中,因此如果广泛使用,可能需要大量内存。

读Excel的功能

@Test
public void testRead03() throws Exception{//根据指定文件创建文件输入流InputStream is = new FileInputStream("d:/test-write03.xls");//创建工作簿对象Workbook workbook = new HSSFWorkbook(is);//获得第一张工作表Sheet sheet = workbook.getSheetAt(0);// 获得第一行Row row = sheet.getRow(0);// 读取第一行第一列Cell cell = row.getCell(0);// 输出单元内容,单元格内容不同,使用不同方法获取System.out.println(cell.getStringCellValue());// 操作结束,关闭文件is.close();
}
  • Excel2007读功能
@Test
public void testRead07() throws Exception{InputStream is = new FileInputStream("d:/test-write07.xlsx");Workbook workbook = new XSSFWorkbook(is);Sheet sheet = workbook.getSheetAt(0);//和上面操作一样is.close();
}
  • 读取不同类型的数据
    在这里插入图片描述
    内容类型不一样时该怎么读
@Test
public void testCellType() throws Exception {InputStream is = new FileInputStream("d:/商品信息表.xlsx");Workbook workbook =  new XSSFWorkbook(is);Sheet sheet = workbook.getSheetAt(0);Row rowTitle = sheet.getRow(0);// 读取这一行所有内容if (rowTitle != null) {// 行不为空// 读取这一行有多少列int cellCount = rowTitle.getPhysicalNumberOfCells();for (int cellNum = 0; cellNum < cellCount; cellNum++) {//获取这一行 cellNum列位置的单元格Cell cell = rowTitle.getCell(cellNum);//判空if (cell != null) {//读取内容并打印String cellValue = cell.getStringCellValue();System.out.print(cellValue + "|");}}System.out.println();}// 读取商品列表数据,获取最大行数int rowCount = sheet.getPhysicalNumberOfRows();for (int rowNum = 1; rowNum < rowCount; rowNum++) {//获取行Row rowData = sheet.getRow(rowNum);if (rowData != null) {// 行不为空// 获取这一行有多少列int cellCount = rowTitle.getPhysicalNumberOfCells();for (int cellNum = 0; cellNum < cellCount; cellNum++) {System.out.print("【" + (rowNum + 1) + "-" + (cellNum + 1) + "】");//获取这一行 cellNum列位置的单元格Cell cell = rowData.getCell(cellNum);if (cell != null) {//获取单元格类型CellType cellType = cell.getCellType();//定义字符串用于接收内容String cellValue = "";//判断单元格数据类型if(CellType.STRING.equals(cellType)){System.out.print("【STRING】");cellValue = cell.getStringCellValue();}else if(CellType.BOOLEAN.equals(cellType)){System.out.print("【BOOLEAN】");cellValue = String.valueOf(cell.getBooleanCellValue());}else if(CellType.NUMERIC.equals(cellType)){System.out.print("【NUMERIC】");//使用poi的工具类,判断是否是日期内容if(DateUtil.isCellDateFormatted(cell)){System.out.print("【日期】");Date date = cell.getDateCellValue();cellValue = new DateTime(date).toString("yyyy-MM-dd");}else{System.out.print("【转换成字符串】");cellValue = String.valueOf(cell.getNumericCellValue());}}else if(CellType.BLANK.equals(cellType)){//空白内容System.out.print("【BLANK】");}else{System.out.println(cellType);}//打印内容System.out.println(cellValue);}}}}is.close();
}

读取Excel大文件内存溢出解决

Web环境集成Excel

  • 添加POI依赖

导出表格

如导出权限表格
页面添加按钮和点击事件

 导出

function exportOP(){//点击响应函数//打开一个新窗口发起请求,如果响应的是一个二进制流文件则自动下载window.open("/permission/export")
}

后端代码

@RequestMapping("/export")
@ResponseBody
public void export(HttpServletResponse response) throws IOException {//设置响应内容为xlsx文件response.setHeader("Content-Disposition","attachment;filename=permissionData.xlsx");Workbook is = permissionService.export();//工作簿使用响应对象写出到浏览器is.write(response.getOutputStream());
}
@Override
public Workbook export() {//模拟查询到的数据List permissions = listAll();//创建工作簿Workbook workbook = new XSSFWorkbook();//创建工作表Sheet sheet = workbook.createSheet("权限列表");//创建行Row row = sheet.createRow(0);//创建列并设置内容row.createCell(0).setCellValue("编号");row.createCell(1).setCellValue("权限名称");row.createCell(2).setCellValue("权限表达式");Permission permission  = null;//取出权限内容for(int i=0;i//多少个权限对象,就有多少行内容row = sheet.createRow(i+1);//取出一个权限信息permission = permissions.get(i);//设置这一行的权限内容row.createCell(0).setCellValue(permission.getId());row.createCell(1).setCellValue(permission.getName());row.createCell(2).setCellValue(permission.getExpression());}//返回这个工作薄return workbook;
}

导入表格

添加按钮

 导入

添加模态框,
因为导入的表格不能让人乱填数据,所有必须提供模板文件下载,让用户按照模板文件填写

<#-- 模态框 -->

导入

添加点击事件

function importOP(){//点击弹出模态框$("#importModal").modal("show");
}
function downloadTemplateOP(){//打开窗口,访问静态资源下载模板文件,如配置了静态资源访问路径则加上window.open("/Template.xlsx")
}
function importSave(){//点击保存,使用异步提交,不用等待保存var $file1 = $("#uploadFile").val();//用户文件内容(文件)// 判断文件是否为空if ($file1 == "") {Swal.fire({text: "请选择上传的目标文件! ",icon: 'warning',})return false;}var formData = new FormData();//这里需要实例化一个FormData来进行文件上传,这是一个二进制流表单参数封装对象formData.append("file",$("#uploadFile")[0].files[0]);//文件名 , //选中文件标签,[0]表示获取原生的html标签,files[0]表示获取这个标签中的第一个文件(用户在选择时可以选择多个文件)$.ajax({type : "post",url : "/permission/importExcel",data : formData,processData : false,//异步表单提交时,如果使用formData携带流参数时需要配置的属性,表明不携带其他参数contentType : false,success : function(data){if (data.success) {Swal.fire({text: data.msg,icon: 'success',})//隐藏模态框$("#importModal").modal("hide");//刷新权限表格标签$('#table').bootstrapTable('refresh');}else{Swal.fire({text: "请选择上传的目标文件! ",icon: 'warning',})}}});
}

后端代码

按上面模板文件下载路径,提供一个模板文件放在static/目录下,   注意要对应文件名

导入接口

@RequestMapping("/importExcel")
@ResponseBody
public JsonResult importExcel(MultipartFile file){try{int count = permissionService.importExcel(file);return new JsonResult(true,"成功导入:"+count+"条记录");}catch(Exception ex){return new JsonResult(false,"导入数据失败");}
}
@Override
public int importExcel(MultipartFile file) throws IOException {//文件获得输入流放入工作簿中Workbook workbook = new XSSFWorkbook(file.getInputStream());Sheet sheet = workbook.getSheetAt(0);//获取最后一行的索引int rowNum = sheet.getLastRowNum();int insertCount = 0;Row row = null;Cell c1 = null;Cell c2 = null;//跳过第一行for(int i=1;irow = sheet.getRow(i);c1 = row.getCell(0);c2 = row.getCell(1);//判断单元格为空就不处理if(c1!=null && c2!=null){String name = c1.getStringCellValue();String expression = c2.getStringCellValue();//判断是否有内容if(StringUtils.hasText(name) && StringUtils.hasText(expression)){//判断表达式是否已经存在int count = permissionMapper.getCountByExpression(expression);if(count==0){//不存在该权限Permission p = new Permission();p.setName(name);p.setExpression(expression);permissionMapper.insert(p);insertCount++;}}}}//返回保存多少条权限return insertCount;
}

相关内容

热门资讯

AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWR报告解读 WORKLOAD REPOSITORY PDB report (PDB snapshots) AW...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
群晖外网访问终极解决方法:IP... 写在前面的话 受够了群晖的quickconnet的小水管了,急需一个新的解决方法&#x...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
Azure构建流程(Power... 这可能是由于配置错误导致的问题。请检查构建流程任务中的“发布构建制品”步骤,确保正确配置了“Arti...