热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

Java利用POI读取、写入Excel的方法指南

这篇文章主要给大家介绍了关于Java利用POI读取、写入Excel的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧

前言

Apache POI [1] 是用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程式对Microsoft Office格式档案读和写的功能。POI为“Poor Obfuscation Implementation”的首字母缩写,意为“简洁版的模糊实现”。

做项目时经常有通过程序读取Excel数据,或是创建新的Excel并写入数据的需求;

网上很多经验教程里使用的POI版本都比较老了,一些API在新版里已经废弃,这里基于最新的Apache POI 4.0.1版本来总结一下整个读取和写入Excel的过程,希望能帮助到需要的人 ^_^

1. 准备工作

1.1 在项目中引入Apache POI相关类库

引入 Apache POI 和 Apache POI-OOXML 这两个类库,Maven坐标如下:

 
 org.apache.poi
 poi
 4.0.1
 
 
 org.apache.poi
 poi-ooxml
 4.0.1
 

2. 读取或写入Excel数据

2.1 示例程序结构说明

简单说明一下示例程序的整体结构:

  • ExcelReader.java是实现读取Excel数据功能的类;
  • ExcelWriter.java是创建新的Excel并向其中写入数据的类;
  • ExcelDataVO.java封装了读取或写入时每一“行”的数据;
  • MainTest.java是示例程序的入口类,其中演示了读取和写入Excel数据的整个过程;

2.2 读取数据

示例程序需要从桌面读取 readExample.xlsx 内的数据,readExample.xlsx 的内容如下:

读取Excel时主要调用ExcelReader.java类来读取和解析Excel的具体内容,这里以读取系统文件的形式演示读取过程:(兼容 xls 和 xlsx)

2.2.1 主程序入口类代码:

/**
 * Author: Dreamer-1
 * Date: 2019-03-01
 * Time: 10:13
 * Description: 示例程序入口类
 */
public class MainTest {

 public static void main(String[] args) {
 // 设定Excel文件所在路径
 String excelFileName = "/Users/Dreamer-1/Desktop/myBlog/java解析Excel/readExample.xlsx";
 // 读取Excel文件内容
 List readResult = ExcelReader.readExcel(excelFileName);
 
 // todo 进行业务操作
 }

}

读取和写入时封装每一“行”数据的ExcelDataVO.java代码如下:

/**
 * Author: Dreamer-1
 * Date: 2019-03-01
 * Time: 11:33
 * Description: 读取Excel时,封装读取的每一行的数据
 */
public class ExcelDataVO {

 /**
 * 姓名
 */
 private String name;

 /**
 * 年龄
 */
 private Integer age;

 /**
 * 居住地
 */
 private String location;

 /**
 * 职业
 */
 private String job;

 public String getName() {
 return name;
 }

 public void setName(String name) {
 this.name = name;
 }

 public Integer getAge() {
 return age;
 }

 public void setAge(Integer age) {
 this.age = age;
 }

 public String getLocation() {
 return location;
 }

 public void setLocation(String location) {
 this.location = location;
 }

 public String getJob() {
 return job;
 }

 public void setJob(String job) {
 this.job = job;
 }
}

2.2.2 Excel解析类的代码:

/**
 * Author: Dreamer-1
 * Date: 2019-03-01
 * Time: 10:21
 * Description: 读取Excel内容
 */
public class ExcelReader {

 private static Logger logger = Logger.getLogger(ExcelReader.class.getName()); // 日志打印类

 private static final String XLS = "xls";
 private static final String XLSX = "xlsx";

 /**
 * 根据文件后缀名类型获取对应的工作簿对象
 * @param inputStream 读取文件的输入流
 * @param fileType 文件后缀名类型(xls或xlsx)
 * @return 包含文件数据的工作簿对象
 * @throws IOException
 */
 public static Workbook getWorkbook(InputStream inputStream, String fileType) throws IOException {
 Workbook workbook = null;
 if (fileType.equalsIgnoreCase(XLS)) {
  workbook = new HSSFWorkbook(inputStream);
 } else if (fileType.equalsIgnoreCase(XLSX)) {
  workbook = new XSSFWorkbook(inputStream);
 }
 return workbook;
 }

 /**
 * 读取Excel文件内容
 * @param fileName 要读取的Excel文件所在路径
 * @return 读取结果列表,读取失败时返回null
 */
 public static List readExcel(String fileName) {

 Workbook workbook = null;
 FileInputStream inputStream = null;

 try {
  // 获取Excel后缀名
  String fileType = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length());
  // 获取Excel文件
  File excelFile = new File(fileName);
  if (!excelFile.exists()) {
  logger.warning("指定的Excel文件不存在!");
  return null;
  }

  // 获取Excel工作簿
  inputStream = new FileInputStream(excelFile);
  workbook = getWorkbook(inputStream, fileType);

  // 读取excel中的数据
  List resultDataList = parseExcel(workbook);

  return resultDataList;
 } catch (Exception e) {
  logger.warning("解析Excel失败,文件名:" + fileName + " 错误信息:" + e.getMessage());
  return null;
 } finally {
  try {
  if (null != workbook) {
   workbook.close();
  }
  if (null != inputStream) {
   inputStream.close();
  }
  } catch (Exception e) {
  logger.warning("关闭数据流出错!错误信息:" + e.getMessage());
  return null;
  }
 }
 }

 /**
 * 解析Excel数据
 * @param workbook Excel工作簿对象
 * @return 解析结果
 */
 private static List parseExcel(Workbook workbook) {
 List resultDataList = new ArrayList<>();
 // 解析sheet
 for (int sheetNum = 0; sheetNum 

2.2.3 应用场景补充

一般我们会有这样的应用场景,即:在前台页面的文件上传入口上传本地的Excel文件到后台,后台收到Excel文件后进行解析并做对应的业务操作;

这里假设前台已经有了上传文件的入口,再简单贴一下后台的解析代码;

后台接收前台数据的Controller层代码示例:

 @PostMapping("/uploadExcel")
 public ResponseEntity<&#63;> uploadImage(MultipartFile file) {

  // 检查前台数据合法性
  if (null == file || file.isEmpty()) {
   logger.warning("上传的Excel商品数据文件为空!上传时间:" + new Date());
   return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
  }

  try {
   // 解析Excel
   List parsedResult = ExcelReader.readExcel(file);
   // todo 进行业务操作

   return new ResponseEntity<>(HttpStatus.OK);
  } catch (Exception e) {
   logger.warning("上传的Excel商品数据文件为空!上传时间:" + new Date());
   return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
  }

 }

ExcelReader.java中的 readExcel() 方法需要做一定的修改,代码如下:

 /**
  * 读取Excel文件内容
  * @param file 上传的Excel文件
  * @return 读取结果列表,读取失败时返回null
  */
 public static List readExcel(MultipartFile file) {

  Workbook workbook = null;

  try {
   // 获取Excel后缀名
   String fileName = file.getOriginalFilename();
   if (fileName == null || fileName.isEmpty() || fileName.lastIndexOf(".") <0) {
    logger.warning("解析Excel失败,因为获取到的Excel文件名非法!");
    return null;
   }
   String fileType = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length());

   // 获取Excel工作簿
   workbook = getWorkbook(file.getInputStream(), fileType);

   // 读取excel中的数据
   List resultDataList = parseExcel(workbook);

   return resultDataList;
  } catch (Exception e) {
   logger.warning("解析Excel失败,文件名:" + file.getOriginalFilename() + " 错误信息:" + e.getMessage());
   return null;
  } finally {
   try {
    if (null != workbook) {
     workbook.close();
    }
   } catch (Exception e) {
    logger.warning("关闭数据流出错!错误信息:" + e.getMessage());
    return null;
   }
  }
 }

2.3 写入数据

写入数据时主要调用ExcelWriter.java来创建Excel工作簿对象并写入数据,这里以写入系统文件数据为例演示写入的过程:

2.3.1 主程序入口类代码

/**
 * Author: Dreamer-1
 * Date: 2019-03-01
 * Time: 10:13
 * Description: 示例程序入口类
 */
public class MainTest {

 private static Logger logger = Logger.getLogger(MainTest.class.getName());

 public static void main(String[] args) {
  // 创建需要写入的数据列表
  List dataVOList = new ArrayList<>(2);
  ExcelDataVO dataVO = new ExcelDataVO();
  dataVO.setName("小明");
  dataVO.setAge(18);
  dataVO.setLocation("广州");
  dataVO.setJob("大学生");
  ExcelDataVO dataVO2 = new ExcelDataVO();
  dataVO2.setName("小花");
  dataVO2.setAge(19);
  dataVO2.setLocation("深圳");
  dataVO2.setJob("大学生");
  dataVOList.add(dataVO);
  dataVOList.add(dataVO2);

  // 写入数据到工作簿对象内
  Workbook workbook = ExcelWriter.exportData(dataVOList);

  // 以文件的形式输出工作簿对象
  FileOutputStream fileOut = null;
  try {
   String exportFilePath = "/Users/Dreamer-1/Desktop/myBlog/java解析Excel/writeExample.xlsx";
   File exportFile = new File(exportFilePath);
   if (!exportFile.exists()) {
    exportFile.createNewFile();
   }

   fileOut = new FileOutputStream(exportFilePath);
   workbook.write(fileOut);
   fileOut.flush();
  } catch (Exception e) {
   logger.warning("输出Excel时发生错误,错误原因:" + e.getMessage());
  } finally {
   try {
    if (null != fileOut) {
     fileOut.close();
    }
    if (null != workbook) {
     workbook.close();
    }
   } catch (IOException e) {
    logger.warning("关闭输出流时发生错误,错误原因:" + e.getMessage());
   }
  }

 }

}

2.3.2 写入Excel类的代码

ExcelWriter.java类中,你可以根据实际需要替换 CELL_HEADS 列头的信息,然后重写 convertDataToRow 方法,转换你自己的行数据;

/**
 * Author: Dreamer-1
 * Date: 2019-03-01
 * Time: 11:09
 * Description: 生成Excel并写入数据
 */
public class ExcelWriter {

 private static List CELL_HEADS; //列头

 static{
  // 类装载时就载入指定好的列头信息,如有需要,可以考虑做成动态生成的列头
  CELL_HEADS = new ArrayList<>();
  CELL_HEADS.add("姓名");
  CELL_HEADS.add("年龄");
  CELL_HEADS.add("居住城市");
  CELL_HEADS.add("职业");
 }

 /**
  * 生成Excel并写入数据信息
  * @param dataList 数据列表
  * @return 写入数据后的工作簿对象
  */
 public static Workbook exportData(List dataList){
  // 生成xlsx的Excel
  Workbook workbook = new SXSSFWorkbook();

  // 如需生成xls的Excel,请使用下面的工作簿对象,注意后续输出时文件后缀名也需更改为xls
  //Workbook workbook = new HSSFWorkbook();

  // 生成Sheet表,写入第一行的列头
  Sheet sheet = buildDataSheet(workbook);
  //构建每行的数据内容
  int rowNum = 1;
  for (Iterator it = dataList.iterator(); it.hasNext(); ) {
   ExcelDataVO data = it.next();
   if (data == null) {
    continue;
   }
   //输出行数据
   Row row = sheet.createRow(rowNum++);
   convertDataToRow(data, row);
  }
  return workbook;
 }

 /**
  * 生成sheet表,并写入第一行数据(列头)
  * @param workbook 工作簿对象
  * @return 已经写入列头的Sheet
  */
 private static Sheet buildDataSheet(Workbook workbook) {
  Sheet sheet = workbook.createSheet();
  // 设置列头宽度
  for (int i=0; i

示例程序运行后将会在指定的系统路径下生成 writeExample.xlsx文件,其内容如下:

2.3.3 应用场景补充

一般写入Excel时会有这样的场景:前台页面上有一个导出按钮,点击后将后台某张表里的数据以Excel的形式导出,导出的Excel文件通过浏览器下载到用户系统中;

这里默认前台页面已经有相应的按钮功能,给出对应的Controller层代码供参考:

 @GetMapping("/exportExcel")
 public void exportExcel(HttpServletRequest request, HttpServletResponse response) {
  Workbook workbook = null;
  OutputStream out = null;
  try {
   // todo 根据业务需求获取需要写入Excel的数据列表 dataList

   // 生成Excel工作簿对象并写入数据
   workbook = ExcelWriter.exportData(dataList);

   // 写入Excel文件到前端
   if(null != workbook){
    String excelName = "示例Excel导出";
    String fileName = excelName + DateUtil.format(new Date(), DateUtil.SHORT_DATE) + ".xlsx";
    fileName = new String(fileName.getBytes("UTF-8"),"iso8859-1");
    response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
    response.setContentType("application/x-download");
    response.setCharacterEncoding("UTF-8");
    response.addHeader("Pargam", "no-cache");
    response.addHeader("Cache-Control", "no-cache");
    response.flushBuffer();
    out = response.getOutputStream();
    workbook.write(out);
    out.flush();
   }
  } catch (Exception e) {
   logger.WARNING("写入Excel过程出错!错误原因:" + e.getMessage());
  } finally {
   try {
    if (null != workbook) {
     workbook.close();
    }
    if (null != out) {
     out.close();
    }
   } catch (IOException e) {
    logger.WARNING("关闭workbook或outputStream出错!");
   }
  }
 }
// 前台页面发送请求到后台Controller时的JS代码可参考:

var url = "/exportExcel";
window.location=url;

3. 源码下载

点我哦.

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。


推荐阅读
  • 本文详细介绍如何利用已搭建的LAMP(Linux、Apache、MySQL、PHP)环境,快速创建一个基于WordPress的内容管理系统(CMS)。WordPress是一款流行的开源博客平台,适用于个人或小型团队使用。 ... [详细]
  • 本文介绍了如何利用 Spring Boot 和 Groovy 构建一个灵活且可扩展的动态计算引擎,以满足钱包应用中类似余额宝功能的推广需求。我们将探讨不同的设计方案,并最终选择最适合的技术栈来实现这一目标。 ... [详细]
  • 在当前众多持久层框架中,MyBatis(前身为iBatis)凭借其轻量级、易用性和对SQL的直接支持,成为许多开发者的首选。本文将详细探讨MyBatis的核心概念、设计理念及其优势。 ... [详细]
  • PHP 5.5.0rc1 发布:深入解析 Zend OPcache
    2013年5月9日,PHP官方发布了PHP 5.5.0rc1和PHP 5.4.15正式版,这两个版本均支持64位环境。本文将详细介绍Zend OPcache的功能及其在Windows环境下的配置与测试。 ... [详细]
  • 本文详细介绍了 Java 中 org.apache.xmlbeans.SchemaType 类的 getBaseEnumType() 方法,提供了多个代码示例,并解释了其在不同场景下的使用方法。 ... [详细]
  • 基于KVM的SRIOV直通配置及性能测试
    SRIOV介绍、VF直通配置,以及包转发率性能测试小慢哥的原创文章,欢迎转载目录?1.SRIOV介绍?2.环境说明?3.开启SRIOV?4.生成VF?5.VF ... [详细]
  • 本文探讨了在通过 API 端点调用时,使用猫鼬(Mongoose)的 findOne 方法总是返回 null 的问题,并提供了详细的解决方案和建议。 ... [详细]
  • 探讨如何真正掌握Java EE,包括所需技能、工具和实践经验。资深软件教学总监李刚分享了对毕业生简历中常见问题的看法,并提供了详尽的标准。 ... [详细]
  • 近期,谷歌公司的一名安全工程师Eduardo Vela在jQuery Mobile框架中发现了一项可能引发跨站脚本攻击(XSS)的安全漏洞。此漏洞使得使用jQuery Mobile的所有网站面临潜在的安全威胁。 ... [详细]
  • 本文档详细介绍了如何在Linux系统中安装JDK 1.7和Tomcat 7,包括安装包的获取、解压、环境配置以及验证安装成功的方法。 ... [详细]
  • 本文探讨了XSS攻击的基本原理及其防御方法,重点介绍了如何在前后端实施有效的安全措施来防止XSS攻击。 ... [详细]
  • KKCMS代码审计初探
    本文主要介绍了KKCMS的安装过程及其基本功能,重点分析了该系统中存在的验证码重用、SQL注入及XSS等安全问题。适合初学者作为入门指南。 ... [详细]
  • 本文是网络安全自学系列的一部分,旨在分享网络安全工具的使用技巧和实际操作案例。继之前讨论了XSS跨站脚本攻击的各个方面后,本文将重点介绍Powershell的基础知识及其在网络安全领域的应用。 ... [详细]
  • 如何在Windows 10的Bash中排除系统PATH
    探讨了在Windows 10的Bash环境中,如何通过调整注册表设置来避免调用Win32程序,确保使用的是Bash环境下的工具版本。 ... [详细]
  • 本文详细介绍了跨站脚本攻击(XSS)的基本概念、工作原理,并通过实际案例演示如何构建XSS漏洞的测试环境,以及探讨了XSS攻击的不同形式和防御策略。 ... [详细]
author-avatar
萝莉莲籽芯
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有