项目中,时常会需要导入导出Excel的需求,因此我专门花时间设计了工具类。

所需依赖

        <!-- 处理xls或xlsx格式的Excel表格导入导出的依赖 --><dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>3.17</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>3.17</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml-schemas</artifactId><version>3.17</version></dependency><dependency><groupId>org.apache.xmlbeans</groupId><artifactId>xmlbeans</artifactId><version>2.6.0</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-collections4</artifactId><version>4.4</version></dependency>

ExcelUtils.java

import org.apache.log4j.Logger;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.*;import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** Excel工具类*/
public class ExcelUtils {// 导出时excel的扩展名public static final String EXTENSION_NAME = ".xlsx";// 03版excel扩展名private static final String XLS = ".xls";// 07版excel扩展名private static final String XLSX = ".xlsx";private static Logger logger = Logger.getLogger(ExcelUtils.class);/*** 导入Excel到数据库** @param filePath 导入的excel文件所在的绝对路径* @param startRow 开始解析的行数* @param startCol 开始解析的列数* @param sheetNum 开始解析的sheet序号,如果不指定,默认传值为-1,则会解析所有sheet* @return*/public static List<List<Map<String, Object>>> importExcel(String filePath, int startRow, int startCol, int sheetNum) {logger.info("========================= ExcelUtils.java ->> importExcel()从Excel表格中获取数据 ->> 开始 =========================");// 用于存储最终整个Excel表格的数据List<List<Map<String, Object>>> resultList = new ArrayList<>();// 得到指定路径的文件File对象File file = new File(filePath);// 如果不存在if (!file.exists()) {logger.info("ExcelUtils.java ->> importExcel() ->> 错误操作:要读取Excel文件在指定路径(" + filePath + ")下找不到");throw new RuntimeException("错误操作:要读取Excel文件在指定路径(" + filePath + ")下找不到");}InputStream input = null;Workbook workbook = null;try {// 得到文件的资源输入流input = new FileInputStream(file);// 得到处理excel的Workbook对象workbook = ExcelUtils.getWorkbookByExtensionName(input, filePath);// 创建一个公式计算器,用于计算并得到Excel中的公式结果FormulaEvaluator formulaEvaluator = workbook.getCreationHelper().createFormulaEvaluator();// 得到Excel表格中sheet的数量int totalSheetNum = workbook.getNumberOfSheets();logger.info("ExcelUtils.java ->> importExcel() ->> 用户指定解析的Sheet表格序号sheetNum = " + sheetNum);Sheet sheet = null;if (sheetNum == -1) {// 循环遍历sheetfor (int m = 0; m < totalSheetNum; m++) {logger.info("ExcelUtils.java ->> importExcel() ->> 开始解析第" + (m + 1) + "个Sheet表格");// 获取每一个sheetsheet = workbook.getSheetAt(m);// 保存Sheet中的数据到List集合中List<Map<String, Object>> sheetList = ExcelUtils.getDataBySheet(sheet, startRow, startCol, formulaEvaluator);// 保存存储有每个sheet数据的List到结果集List中去resultList.add(sheetList);}} else if (sheetNum > 0 && (sheetNum - 1) < totalSheetNum) {logger.info("ExcelUtils.java ->> importExcel() ->> 开始解析第" + sheetNum + "个Sheet表格");// 获取指定sheet序号的sheet表格sheet = workbook.getSheetAt((sheetNum - 1));// 保存Sheet中的数据到List集合中List<Map<String, Object>> sheetList = ExcelUtils.getDataBySheet(sheet, startRow, startCol, formulaEvaluator);resultList.add(sheetList);} else {logger.info("ExcelUtils.java ->> importExcel() ->> 该Excel表格只有" + totalSheetNum + "个Sheet表,而用户指定解析的Sheet表序号为" + sheetNum + ",不在范围内");throw new RuntimeException("异常信息:该Excel表格只有" + totalSheetNum + "个Sheet表,而用户指定解析的Sheet表序号为" + sheetNum + ",不在范围内");}} catch (Exception e) {logger.info("ExcelUtils.java ->> importExcel() ->> 异常信息:" + e);throw new RuntimeException(e);} finally {try {if (workbook != null) {workbook.close();logger.info("ExcelUtils.java ->> importExcel() ->> 关闭Workbook资源");}if (input != null) {input.close();logger.info("ExcelUtils.java ->> importExcel() ->> 关闭InputStream资源");}} catch (Exception e) {e.printStackTrace();}logger.info("========================= ExcelUtils.java ->> importExcel()从Excel表格中获取数据 ->> 结束 =========================");}return resultList;}/*** 根据文件扩展名(.xls或.xlsx)获取对应的Workbook类型(HSSFWorkbook或XSSFWorkbook)** @param input    关联excel文件的资源输入流* @param filePath 文件路径* @return* @throws Exception*/private static Workbook getWorkbookByExtensionName(InputStream input, String filePath) throws Exception {logger.info("========================= ExcelUtils.java ->> getWorkbookByExtensionName()根据excel文件后缀(.xls或.xlsx)获取Workbook的方法 ->> 开始 =========================");if (filePath == null || "".equals(filePath) || filePath.trim().isEmpty()) {logger.info("ExcelUtils.java ->> getWorkbookByExtensionName() ->> 异常信息:excel文件路径不能为空");throw new RuntimeException("异常信息:excel文件路径不能为空");}int index = filePath.lastIndexOf(".");if (index == -1) {logger.info("ExcelUtils.java ->> getWorkbookByExtensionName() ->> 异常信息:filePath指定的文件不带有扩展名,不属于文件类型");throw new RuntimeException("异常信息:filePath指定的文件不带有扩展名,不属于文件类型");}Workbook wk = null;String suffix = filePath.substring(index);logger.info("ExcelUtils.java ->> getWorkbookByExtensionName() ->> filePath指定的文件扩展名为 = " + suffix);if (ExcelUtils.XLS.equals(suffix)) {wk = new HSSFWorkbook(input);} else if (ExcelUtils.XLSX.equals(suffix)) {wk = new XSSFWorkbook(input);} else {logger.info("ExcelUtils.java ->> getWorkbookByExtensionName() ->> 异常信息:filePath指定的文件扩展名不是excel文件格式(只能是.xls和.xlsx格式)");throw new RuntimeException("异常信息:filePath指定的文件扩展名不是excel文件格式(只能是.xls和.xlsx格式)");}logger.info("========================= ExcelUtils.java ->> getWorkbookByExtensionName()根据excel文件后缀(.xls或.xlsx)获取Workbook的方法 ->> 结束 =========================");return wk;}/*** 获取sheet中的数据并返回一个List集合** @param sheet            Sheet对象* @param startRow         开始解析的行数* @param startCol         开始解析的列数* @param formulaEvaluator 公式计算器实例* @return* @throws Exception*/private static List<Map<String, Object>> getDataBySheet(Sheet sheet, int startRow, int startCol, FormulaEvaluator formulaEvaluator) throws Exception {logger.info("========================= ExcelUtils.java ->> getDataBySheet()从Sheet表格中获取数据 ->> 开始 =========================");List<Map<String, Object>> sheetList = new ArrayList<>();/*Sheet中的getPhysicalNumberOfRows()和getLastRowNum()区别:> getPhysicalNumberOfRows():获取的是物理行数,即会跳过空行的情况。> getLastRowNum():获取的是最后一行的行编号(编号从0开始)。*/// 得到表格中总共的行数,会比实际的行数小1int totalRowNum = sheet.getLastRowNum() + 1;logger.info("ExcelUtils.java ->> getDataBySheet() ->> 当前Sheet表格中总行数totalRowNum = " + totalRowNum);// 循环当前表格中所有行for (int i = (startRow - 1); i < totalRowNum; i++) {// 得到Row行对象Row row = sheet.getRow(i);if (row == null || row.toString().trim().isEmpty()|| "".equals(row.toString()) || "null".equals(row.toString())) {logger.info("ExcelUtils.java ->> getDataBySheet() ->> 第" + (i + 1) + "行的内容为空,因此解析下一行");continue;}/*Row中的getPhysicalNumberOfCells()和getLastCellNum()区别:> getPhysicalNumberOfCells():获取的是物理列数,即会跳过空列的情况。> getLastCellNum():获取的是最后一列的列编号(编号从0开始)。*/// 得到当前行中所有的单元格数量int totalCellNum = row.getLastCellNum();logger.info("ExcelUtils.java ->> getDataBySheet() ->> 第" + (i + 1) + "行的总列数totalCellNum = " + totalCellNum);// 创建Map集合用于存储当前行中所有的单元格数据Map<String, Object> rowMap = new HashMap<>();// 循环当前行中所有单元格for (int j = (startCol - 1); j < totalCellNum; j++) {// 得到Cell列对象Cell cell = row.getCell(j);// 如果等于空if (cell == null || cell.toString().trim().isEmpty()|| "".equals(cell.toString()) || "null".equals(cell.toString())) {rowMap.put("Row" + (i + 1) + "-Col" + (j + 1), "");logger.info("ExcelUtils.java ->> getDataBySheet() ->> 第" + (i + 1) + "行的第" + (j + 1) + "列" + "的单元格的内容为空,因此解析下一个单元格");continue;}// 进行公式解析,最后只存在Boolean、Numeric和String三种数据类型,此外就是Error了// 其余数据类型,根据官方文档,完全可以忽略:http://poi.apache.org/spreadsheet/eval.htmlCellValue cellValue = formulaEvaluator.evaluate(cell);// 得到对应单元格的内容String result = ExcelUtils.getCellResultByCellType(cell, cellValue, formulaEvaluator);logger.info("ExcelUtils.java ->> getDataBySheet() ->> 第" + (i + 1) + "行的第" + (j + 1) + "列的单元格内容 = " + result);// 保存到Map集合rowMap.put("Row" + (i + 1) + "-Col" + (j + 1), result);}// 将每个行对象保存到List中sheetList.add(rowMap);}logger.info("========================= ExcelUtils.java ->> getDataBySheet()从Sheet表格中获取数据 ->> 结束 =========================");return sheetList;}/*** 根据单元格数据类型获取单元格的值** @param cell      Cell单元格类型* @param cellValue CellValue单元格值类型* @param formulaEvaluator 公式计算器* @return*/private static String getCellResultByCellType(Cell cell, CellValue cellValue, FormulaEvaluator formulaEvaluator) {String result = null;CellType cellTypeEnum = cellValue.getCellTypeEnum();if (cellTypeEnum == CellType.NUMERIC) {// 判断当前单元格是否为日期格式if (DateUtil.isCellDateFormatted(cell)) {logger.info("ExcelUtils.java ->> getCellResultByCellType() ->> 当前单元格类型为数值型中的日期类型");SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");result = sdf.format(cell.getDateCellValue());} else {logger.info("ExcelUtils.java ->> getCellResultByCellType() ->> 当前单元格类型为数值型中的整数型");DataFormatter dataFormatter = new DataFormatter();result = dataFormatter.formatCellValue(cell, formulaEvaluator);}} else if (cellTypeEnum == CellType.STRING) {logger.info("ExcelUtils.java ->> getCellResultByCellType() ->> 当前单元格类型为字符串");result = cellValue.getStringValue();} else if (cellTypeEnum == CellType.BOOLEAN) {logger.info("ExcelUtils.java ->> getCellResultByCellType() ->> 当前单元格类型为布尔类型");result = String.valueOf(cellValue.getBooleanValue());}return result;}/** 上面是Excel导入功能* ====================================================================================================================================* 下面是Excel导出功能*//*** 导出数据到Excel** @param title    Excel表格中sheet的名称以及大标题行的标题* @param rowName  小标题行的标题* @param dataList 主体数据* @param out      输出流* @throws Exception*/public static void exportExcel(String title, String[] rowName, List<Object[]> dataList, OutputStream out) {logger.info("========================= ExcelUtils.java ->> exportExcel()导出数据到Excel中 ->> 开始 =========================");XSSFWorkbook workbook = null;try {/*1,创建工作簿对象,然后创建大标题行,并设置标题*/// 创建工作簿对象workbook = new XSSFWorkbook();// 创建一个表格对象XSSFSheet sheet = workbook.createSheet("Sheet1");String mark = "title";// 定义大标题行的样式XSSFCellStyle titleCellStyle = ExcelUtils.getCellStyle(workbook, mark);// 如果参数title不等空,则设置Sheet表格的大标题if (!"null".equals(title) && title != null&& !"".equals(title) && !title.trim().isEmpty()) {// 创建表格大标题行XSSFRow titleRow = sheet.createRow(0);// 创建表格大标题行的第一个单元格XSSFCell titleCell = titleRow.createCell(0);// 定义大标题行的宽度和高度(合并单元格)sheet.addMergedRegion(new CellRangeAddress(0, 1, 0, (rowName.length - 1)));// 设置大标题行的单元格样式titleCell.setCellStyle(titleCellStyle);// 设置大标题行的单元格名称titleCell.setCellValue(title);logger.info("ExcelUtils.java ->> exportExcel() ->> 导出到Excel中Sheet表格的标题title = " + title);}/*2,创建小标题行并设置标题*/// 定义所需列数 = 参数数组长度int columnNum = rowName.length;logger.info("ExcelUtils.java ->> exportExcel() ->> 导出到Excel中Sheet表格的标题列数columnNum = " + columnNum);// 创建小标题行,由于0行和1行用作大标题行,所以小标题行从2开始XSSFRow subTitleRow = sheet.createRow(2);// 将列头设置到sheet的单元格中for (int i = 0; i < columnNum; i++) {// 创建小标题行的单元格XSSFCell subTitleCell = subTitleRow.createCell(i);// 设置单元格的单元格类型subTitleCell.setCellType(CellType.STRING);// 使用数组中的数据作为单元格的文本来创建小标题XSSFRichTextString text = new XSSFRichTextString(rowName[i]);// 设置小标题单元格的样式subTitleCell.setCellStyle(titleCellStyle);// 设置文本到小标题单元格中subTitleCell.setCellValue(text);logger.info("ExcelUtils.java ->> exportExcel() ->> 设置小标题行的第" + (i + 1) + "列的标题为 = " + text);}/*3,开始循环主体数据,并设置到sheet表格中*/logger.info("ExcelUtils.java ->> exportExcel() ->> 要导入到Excel表格中的数据行数 = " + dataList.size());mark = "";// 定义普通行的样式XSSFCellStyle style = ExcelUtils.getCellStyle(workbook, mark);// 循环遍历参数主体数据for (int i = 0; i < dataList.size(); i++) {// 遍历每个Object数组Object[] objArr = dataList.get(i);// 创建当前要填充数据的行对象XSSFRow currentRow = sheet.createRow(i + 3);// 循环遍历Object数组for (int j = 0; j < objArr.length; j++) {XSSFCell cell = null;// 如果是每行的第一个单元格if (j == 0) {// 创建单元格,且设置单元格类型为数值型cell = currentRow.createCell(j, CellType.NUMERIC);cell.setCellValue(i + 1);// 设置单元格的样式cell.setCellStyle(titleCellStyle);logger.info("ExcelUtils.java ->> exportExcel() ->> 每行的第一个单元格作为行序号标记,当前序号为 = " + (i + 1));} else {// 创建单元格,且设置单元格类型为字符串型cell = currentRow.createCell(j, CellType.STRING);// 如果数组中的内容不为空if (objArr[j] != null && !"".equals(objArr[j])) {// 设置到单元格中cell.setCellValue(objArr[j].toString());}// 设置单元格的样式cell.setCellStyle(style);logger.info("ExcelUtils.java ->> exportExcel() ->> 第" + (i + 1) + "行的第" + (j + 1) + "个单元格的内容为 = " + (i + 1));}}}// 让列宽随着导出的列长自动适应for (int colNum = 0; colNum < columnNum; colNum++) {//int columnWidth = sheet.getColumnWidth(colNum) / 256;for (int rowNum = 0; rowNum < sheet.getLastRowNum(); rowNum++) {XSSFRow currentRow;if (sheet.getRow(rowNum) == null) {currentRow = sheet.createRow(rowNum);} else {currentRow = sheet.getRow(rowNum);}if (currentRow.getCell(colNum) != null) {XSSFCell currentCell = currentRow.getCell(colNum);if (currentCell.getCellTypeEnum() == CellType.STRING) {int length = currentCell.getStringCellValue().getBytes().length;if (columnWidth < length) {columnWidth = length;}}}}// 设置列宽if (colNum == 0) { // 如果是首列sheet.setColumnWidth(colNum, (columnWidth - 2) * 256);} else { // 否则sheet.setColumnWidth(colNum, (columnWidth + 4) * 256);}}workbook.write(out);} catch (Exception e) {logger.info("ExcelUtils.java ->> exportExcel() ->> 异常信息:" + e);throw new RuntimeException(e);} finally {try {if (workbook != null) {workbook.close();logger.info("ExcelUtils.java ->> exportExcel() ->> 关闭Workbook资源");}} catch (Exception e) {e.printStackTrace();}logger.info("========================= ExcelUtils.java ->> exportExcel()导出数据到Excel中 ->> 结束 =========================");}}/*** 得到单元格样式** @param workbook XSSFWorkbook类型对象* @param mark     标记,当且仅当为title时获取标题行的样式,否则为普通单元格样式* @return*/private static XSSFCellStyle getCellStyle(XSSFWorkbook workbook, String mark) {// 创建字体对象XSSFFont font = workbook.createFont();// 创建单元格样式对象XSSFCellStyle cellStyle = workbook.createCellStyle();if ("title".equals(mark)) {// 设置字体的大小font.setFontHeightInPoints((short) 11);// 设置字体加粗font.setBold(true);// 设置字体高度
//            font.setFontHeight((short) 240);} else {// 设置字体的大小font.setFontHeightInPoints((short) 10);// 设置字体加粗font.setBold(false);// 设置单元格左边框cellStyle.setBorderLeft(BorderStyle.THIN);// 设置单元格左边框颜色cellStyle.setLeftBorderColor(new XSSFColor());}// 设置单元格的边框样式ExcelUtils.setCellCommonStyle(cellStyle, font);return cellStyle;}/*** 设置单元格的边框样式** @param cellStyle XSSFCellStyle单元格样式对象* @param font      XSSFFont字体对象*/private static void setCellCommonStyle(XSSFCellStyle cellStyle, XSSFFont font) {// 设置字体的格式font.setFontName("等线");// 设置单元格上边框cellStyle.setBorderTop(BorderStyle.THIN);// 设置单元格上边框颜色cellStyle.setTopBorderColor(new XSSFColor());// 设置单元格右边框cellStyle.setBorderRight(BorderStyle.THIN);// 设置单元格右边框颜色cellStyle.setRightBorderColor(new XSSFColor());// 设置单元格底边框cellStyle.setBorderBottom(BorderStyle.THIN);// 设置单元格底边框颜色cellStyle.setBottomBorderColor(new XSSFColor());// 在单元格样式用应用设置的字体cellStyle.setFont(font);// 设置是否自动换行cellStyle.setWrapText(false);// 设置水平对齐的样式为居中对齐cellStyle.setAlignment(HorizontalAlignment.CENTER);// 设置垂直对齐的样式为居中对齐cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);}}

操作Excel工具类:ExcelUtils.java相关推荐

  1. Java操作Excel工具类

    Excel工具类 要说的话 长期作为一个c/v工程师,搞了很久但是感觉还是比较空虚,正好最近又在弄Excel相关的东西,然后就基于POI封装了一个比较简单易用的工具类.在这之前,本人水平一般般,还希望 ...

  2. 自己封装的poi操作Excel工具类

    在上一篇文章<使用poi读写Excel>中分享了一下poi操作Excel的简单示例,这次要分享一下我封装的一个Excel操作的工具类. 该工具类主要完成的功能是:读取Excel.汇总Exc ...

  3. 读取Excel工具类ExcelUtils

    依赖包 <!-- https://mvnrepository.com/artifact/org.apache.poi/poi --> <dependency><group ...

  4. java 兼容excel_Java解析Excel工具类(兼容xls和xlsx)

    依赖jar org.apache.poi poi-ooxml 4.0.1 ExcelUtils.java package javax.utils; import java.io.File; impor ...

  5. Excel工具类--下载

    1.使用Excel工具类ExcelUtils,导包 2.前端代码,一个普通a标签 3.后端代码 ToolUtil.getExcelTitle 是额外提供的工具类,来处理不同浏览器下的乱码问题 Exce ...

  6. Java解析Excel工具类(兼容xls和xlsx)

    依赖jar <dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml< ...

  7. Java导入Excel工具类使用教程

    前言: 本工具类提供了Excel导入功能,通过反射机制将Excel中数据映射到实体类中,从而获取Excel数据,工具类依赖org.apache.poi包.支持RESTful API,支持Spring ...

  8. ExcelUtils工具类(Java,poi)

    Excel工具类代码 package util;import java.io.File; import java.io.FileInputStream; import java.io.FileNotF ...

  9. 【Apache POI】Excel操作(八):Excel工具类的封装(终极版)

    恋爱最珍贵的纪念品,从来就不是那些你送我的手表和项链,甚至也不是那些甜蜜的短信和合照.是你留在我身上的,如同河流留给山川的,那些你对我造成的改变. 有目录,不迷路 前言 代码开整 环境准备 正式开整 ...

最新文章

  1. 设计模式之建造者模式(生成器模式、Builder)摘录
  2. Dos下cd不起作用详解...
  3. 百一测评mysql数据库答案_MySQL练习题,百炼成神~
  4. 【java】 ssm+ssh原生态框架(仅供参考)
  5. SVN“验证位置时发生错误”的解决办法
  6. 互联网晚报 | 9月11日 星期六 | 魅蓝宣布正式回归;黑石集团终止收购SOHO中国;“小酒馆第一股”海伦司正式登陆港交所...
  7. 阿里工程师是如何系统化地总结缓存相关知识的
  8. 很不错的python 机器学习博客
  9. ionic打包中的那些坑
  10. apktool 反编译 java_APK文件使用ApkTool解包反编译和重新打包及签名
  11. zabbix使用ICMP ping监控网络状态
  12. 小米路由3刷华硕潘多拉固件教程及软件相关
  13. Lightbox插件
  14. 京苍穹土地利用规划建库工具软件_北京苍穹土地利用规划建库工具软件V10使用手册.doc...
  15. java如何进行word文档的合并
  16. linux 同一个交换机 不通,同一个交换机 局域网内 内网IP ping不通为什么 没关闭windows防火墙...
  17. Quick-Cocos2d-x初学者游戏教程1
  18. Lwip协议详解(基于Lwip 2.1.0)-ICMP协议 (未完待续)
  19. 二进制文件、文本文件
  20. 【Web API系列教程】1.3 — 实战:用ASP.NET Web API和Angular.js创建单页面应用程序(上)

热门文章

  1. html文件右键没有打开方式,一个文件打不开,点右键,怎么在打开方式中加入Word,Excel的打开方式,打开方式中有Word的打开方式?...
  2. clickonce程序部署后,启动不成功的问题
  3. python视频换脸下载_Faceswap拍照换脸软件电脑版(faceswap gui视频换脸)1.2官方版
  4. 「macOS无法验证此APP不包含恶意软件」的处理方式
  5. Java面试宝典2013版
  6. .bat文件打开闪退
  7. Synopsys逻辑综合及DesignCompiler的使用
  8. win10清理C盘好用的办法
  9. 用友php漏洞,用友GRP-u8 注入-RCE漏洞复现
  10. 数量金融学(8):Markowitz均值-方差模型(2)