封装poi操作excel超实用的工具类

适用poi版本:5.2.2

1.行索引获取Row对象

可能sheet页对象没有创建这一行,可能为空,为空时先创建Row再返回

    public static Row safeRow(Sheet sheet,int i){Row row = sheet.getRow(i);if(row == null){row = sheet.createRow(i);}return row;}

2.列索引获取Cell对象

封装该方法的原因和上面一样,getCell可能为空

    public static Cell safeCell(Row row,int i){Cell cell = row.getCell(i);if(cell == null){cell = row.createCell(i);}return cell;}

3.读取单元格数据

excel中支持多种数据格式,分别对应java中的Double、String、Date、Boolean,根据单元格的getCellType()方法判断单元格类型,返回对应类型的数据

    private static final List<Integer> EXCEL_DATE_FORMAT_LIST = Arrays.asList(14,31,57,58);/*** 获得单元格数据*/public static Object getCellValue(Cell cell, FormulaEvaluator evaluator){if (cell == null){ return null;}if(Objects.equals(cell.getCellType(),CellType.STRING)){return cell.getStringCellValue();}else if(Objects.equals(cell.getCellType(),CellType.NUMERIC)){if(DateUtil.isCellDateFormatted(cell)){return cell.getDateCellValue();}else if (EXCEL_DATE_FORMAT_LIST.contains((int) cell.getCellStyle().getDataFormat())) {// 处理自定义日期格式:m月d日(通过判断单元格的格式id解决,id的值是14,31,57,58)double cellValue = cell.getNumericCellValue();return DateUtil.getJavaDate(cellValue);}else {return NumberToTextConverter.toText(cell.getNumericCellValue());}}else if(Objects.equals(cell.getCellType(),CellType.BLANK)){return "";}else if(Objects.equals(cell.getCellType(),CellType.FORMULA)){CellValue value = evaluator.evaluate(cell);if(value.getCellType() == CellType.NUMERIC){return NumberToTextConverter.toText(value.getNumberValue());}else if(value.getCellType() == CellType.BOOLEAN){return String.valueOf(value.getBooleanValue());}else{return value.getStringValue();}}else if(Objects.equals(cell.getCellType(),CellType.BOOLEAN)){return cell.getBooleanCellValue();}return "";}/*** 获得单元格数据*/public static String getCellStringValue(Cell cell, FormulaEvaluator evaluator){Object o = getCellValue(cell, evaluator);if(o instanceof Date){return TimeUtil.formatDate((Date) o,"yyyy-MM-dd");}return o == null ? "" : o.toString();}

4.判断Row是不是空白行

    public static boolean isBlankRow(Row row){if(row != null){for (int c = row.getFirstCellNum(); c < row.getLastCellNum(); c++) {Cell cell = row.getCell(c);if (cell != null && cell.getCellType() != CellType.BLANK){return false;}}}return true;}private static final DataFormatter DEFAULT_DATA_FORMATTER = new DataFormatter();private static boolean isEmptyRow(Row row) {if(row != null){for (int c = row.getFirstCellNum(); c < row.getLastCellNum(); c++) {Cell cell = row.getCell(c);if (cell != null && cell.getCellType() != CellType.BLANK) {String s = DEFAULT_DATA_FORMATTER.formatCellValue(cell);if(StringUtils.isNotBlank(s)){return false;}}}}return true;}

5.插入批注

一个单元格不能重复添加批注,否则会报错,另外大量创建批注时,性能会非常低

    public static void addXSSFComment(Cell cell,String value){Sheet sheet = cell.getSheet();ClientAnchor anchor = new XSSFClientAnchor();anchor.setDx1(0);anchor.setDx2(0);anchor.setDy1(0);anchor.setDy2(0);anchor.setCol1(cell.getColumnIndex());anchor.setRow1(cell.getRowIndex());anchor.setCol2(cell.getColumnIndex()+5);anchor.setRow2(cell.getRowIndex()+6);Comment comment = sheet.createDrawingPatriarch().createCellComment(anchor);// 输入批注信息comment.setString(new XSSFRichTextString(value));// 添加作者comment.setAuthor("Auther");// 将批注添加到单元格对象中cell.setCellComment(comment);}public static void addHSSFComment(Cell cell,String value){Sheet sheet = cell.getSheet();ClientAnchor anchor = new HSSFClientAnchor();anchor.setDx1(0);anchor.setDx2(0);anchor.setDy1(0);anchor.setDy2(0);anchor.setCol1(cell.getColumnIndex());anchor.setRow1(cell.getRowIndex());anchor.setCol2(cell.getColumnIndex()+5);anchor.setRow2(cell.getRowIndex()+6);Comment comment = sheet.createDrawingPatriarch().createCellComment(anchor);// 输入批注信息comment.setString(new HSSFRichTextString(value));// 添加作者comment.setAuthor("Auther");// 将批注添加到单元格对象中cell.setCellComment(comment);}public static void addComment(Cell cell,String value){if(cell != null && value != null && value.length() > 0){if(cell instanceof XSSFCell){addXSSFComment(cell,value);}else if(cell instanceof HSSFCell){addHSSFComment(cell,value);}}}

6.设置单元格下拉框格式

给单元格设置数据校验,只允许输入或选择下拉列表中的值

    /*** 给单元格添加下拉框校验*/public static void addDropDownList(Sheet sheet, Cell cell, Collection<String> arr){addDropDownList(sheet, cell.getRowIndex(), cell.getRowIndex(), cell.getColumnIndex(), cell.getColumnIndex(), arr);}/*** 给区域添加下拉框校验*/public static void addDropDownList(Sheet sheet, Integer startRow, Integer endRow, Integer startCol, Integer endCol, Collection<String> arr){DataValidationHelper helper = sheet.getDataValidationHelper();CellRangeAddressList range = new CellRangeAddressList(startRow,endRow,startCol,endCol);DataValidationConstraint xssConstraint = helper.createExplicitListConstraint(arr.toArray(new String[0]));DataValidation validation = helper.createValidation(xssConstraint,range);sheet.addValidationData(validation);}

7.重置表格区域范围

excel2007版本中可以插入表格区域,2003版本不支持!

程序可以往表格中填充数据,从表格区域开始行位置填充,填充过程中插入了新行,但表格区域不会自动变化,因此填充完成后要重新设置表格区域,即重新设置表格结束行

    public static void resetTableArea(XSSFTable table, Integer startRow, Integer endRow){CellReference s = new CellReference(startRow, table.getStartColIndex());CellReference e = new CellReference(endRow, table.getEndColIndex());AreaReference reference = new AreaReference(s, e, SpreadsheetVersion.EXCEL2007);table.setArea(reference);}

8.单元格坐标解析和转换

excel中的列号用A到Z进行表示,A代表的就是第一列,Z代表的就是第26列,AA表示的是第27列。

例如知道一个单元格的行索引和列索引,需要转换为A2、B2这种地址,或者反过来根据A2得到行索引和列索引

    /*** 將excel中列字母转化为索引*/public static int getCellColIndex(String s){int num;int result = 0;for(int i = 0; i < s.length(); i++) {char ch = s.charAt(s.length() - i - 1);num = ch - 'A' + 1;num *= Math.pow(26, i);result += num;}return result - 1;}/*** 列字母转数字索引* @param col   z=>25 AA => 26*/public static int excelToNum(String col) {if (col == null) {return -1;}// 转为大写字母组成的 char数组char[] chrs = col.toUpperCase(Locale.ENGLISH).toCharArray();int length = chrs.length;int ret = -1;for (int i = 0; i < length; i++) {// 当做26进制来算 AAA=111 26^2+26^1+26^0ret += (chrs[i] - 'A' + 1) * (int) Math.pow(26, length - i - 1);}// 702; 从0开始的下标return ret;}/*** 根据单元格求出坐标* @return A2*/public static String getCellLocation(Cell cell) {return getCellLocation(cell.getRowIndex(),cell.getColumnIndex());}/*** 根据单元格求出坐标* @return A2*/public static String getCellLocation(int rowIndex, int colIndex) {rowIndex++;String colStr;if (colIndex < 26) {colStr = (char) (colIndex + 65) + "";} else {char a = (char) (colIndex / 26 + 64);char b = (char) (colIndex % 26 + 65);colStr = a + "" + b;}return colStr + rowIndex;}/*** 根据单元格坐标得到行列* @Param pos A2*/public static int[] getCellLocation(String pos) {int rlt = 0;pos = pos.toUpperCase(Locale.ENGLISH);String[] sts = StringTool.replaceNum(pos).split("");int length = sts.length;for (int i = 0; i < length; i++) {String st = sts[i];char[] cs = st.toCharArray();int idx = (int)cs[0];// 如果字符不是 A-Z 之间的字符, 则抛错if (idx < 65 || idx > 90) {throw new Error("Characters["+ st +"] not between A and Z.");}idx -= 64;long num = (long) (idx * Math.pow( (double) 26, (double) (length - i - 1) ));rlt  += num;}int row = Integer.parseInt(filterNum(pos));return new int[]{--row, --rlt};}/*** 只保留字符串中的数字*/public static String filterNum(String str){byte[] st=str.getBytes();byte[] s=new byte[st.length];int i=0;for (byte aSt : st) {if (aSt >= 48 && aSt <= 57) {s[i++]=aSt;}}byte[] res=new byte[i];System.arraycopy(s, 0, res, 0, i);return new String(res);}/*** 去掉字符串中的数字,经过测试速度快于replaceAll("\\d","")*/public static String replaceNum(String str){byte[] st=str.getBytes();byte[] s=new byte[st.length];int i=0;for (byte aSt : st) {if (aSt < 48 || aSt > 57) {s[i++]=aSt;}}byte[] res=new byte[i];System.arraycopy(s, 0, res, 0, i);return new String(res);}

9.读取全部table区域

注意只有2007版本的excel才有table

    @SneakyThrowspublic static List<XSSFTable> readTables(XSSFWorkbook workbook){List<XSSFTable> tableList = new ArrayList<>(3);for (int i = 0; i < workbook.getNumberOfSheets(); i++) {XSSFSheet sheet = workbook.getSheetAt(i);List<XSSFTable> tables = sheet.getTables();tableList.addAll(tables);}return tableList;}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/47767.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【音视频 | HTTP协议】HTTP协议详细介绍(HTTP方法、报文格式、报文头部字段、状态码)

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

git实现多人协作开发同一个项目

Git 是一个非常流行的分布式版本控制系统&#xff0c;用于管理代码版本。在多人协作开发同一个项目时&#xff0c;Git 提供了一系列功能和工作流来帮助团队有效地协同工作。 1. 初始化 Git 仓库 首先&#xff0c;确保你的项目目录已经初始化为一个 Git 仓库。如果没有&#x…

推出全新的ZL3079x、ZL3069x、ZL3066x同步器,优化用于5G运输和无线基础设施设备

一、单通道、双通道和三通道IEEE1588/SyncE网络同步器 ZL3079x提供1个、2个和三个独立的组合硬件和软件平台定时通道&#xff0c;包括IEEE 1588-2008精确时间协议栈和同步算法。该设备使用miTimePLL定时技术&#xff0c;为5G传输和无线基础设施设备提供新的改进功能。该器件非…

正则表达式在Python中的高级应用:从HTML中提取数据

正则表达式在Python中的高级应用&#xff1a;从HTML中提取数据 作为一名资深的Python程序员&#xff0c;我深知正则表达式在文本处理中的重要性。尤其是在处理HTML文档时&#xff0c;正则表达式可以成为我们提取数据的强大工具。在本文中&#xff0c;我将通过一个实际的例子&a…

低代码前端框架Amis全面教程

什么是Amis&#xff1f; 1.1 Amis的基本概念 Amis是一个基于JSON配置的前端低代码框架&#xff0c;由百度开源。它允许开发者通过简单的JSON配置文件来生成复杂的后台管理页面&#xff0c;从而大大减少了前端开发的工作量。Amis的核心理念是通过配置而非编码来实现页面的构建…

阿里云ACP云计算高级攻城狮通用知识

&#x1f525;概述 阿里云云计算高级工程师ACP认证是面向使用阿里云云计算产品的架构、开发、运维类人员的专业技术认证&#xff0c;主要考核考生利用阿里云云计算技术服务体系设计稳定、安全、高性能、易扩展、低成本的企业云计算架构的能力。 前提&#xff1a;在写适用人群…

Spring后端框架复习总结

之前写的博客太杂,最近想把后端框架的知识点再系统的过一遍,主要是Spring Boot和Mybatis相关,带着自己的理解使用简短的话把一些问题总结一下,尤其是开发中和面试中的高频问题,基础知识点可以参考之前写java后端专栏,这篇不再赘述。 目录 Spring什么是AOP?底层原理?事务…

word的进阶

Word的基本操作 这里主要用到的软件是WPS软件。 一、创建一个文档 第一种&#xff1a;快捷键&#xff1a;ctrln第二种&#xff1a;通过界面鼠标点击 二、设置文档背景 更换过的背景如下&#xff1a; 三、章节、目录导航的设置 四、插入目录页 五、对历史文档进行管理 六、…

大数减法c++

这里写目录标题 key key 检查减数和被减数的大小&#xff0c;大的放前&#xff0c;小的放后确定结果是正数&#xff0c;还是负数&#xff0c;即符号位从低位开始减如果a[i]<b[i]&#xff0c;则向高位借1当10&#xff0c;a[i1]–;a[i]10 #include <iostream> #include…

Java_MyBatisPlus

MyBatisPlus属于是MyBatis的拓展&#xff0c;不影响原MyBatis框架下的代码运行&#xff0c;并对MyBatis框架进行拓展及优化。 使用步骤&#xff1a; 注意&#xff1a;继承BaseMapper时要填写泛型为要操作的实体类。 基本原理&#xff1a; MyBatisPlus通过扫描实体类&#xff…

【鸿蒙学习笔记】构建布局・选项卡 (Tabs)

官方文档&#xff1a;选项卡 (Tabs) 目录标题 底部导航顶部导航侧边导航限制导航栏的滑动切换固定导航栏・可滚动导航栏自定义导航栏切换至指定页签 底部导航 Entry Component struct Bujv_tabs {build() {Column() {Tabs({ barPosition: BarPosition.End }) {TabContent() {T…

怎么给PDF文件设置加密保护?有哪些方法?

pdf作为一种便携式文档&#xff0c;是展示内容的首选&#xff0c;目前也已广泛应用于交换和分享等&#xff0c;例如内部报告以及商业提案等。然而&#xff0c;在如今的数字化时代&#xff0c;随着越来越多的企业将其文档存储和在线分享&#xff0c;pdf文件也可能面临安全隐私泄…

深入理解ADB:Android调试桥详解与使用指南

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;Android ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 1. 什么是ADB&#xff1f; ADB的基本原理&#xff1a; 2. ADB的安装与配置 安装ADB工具集&#xff1a; 配置ADB环境变量&am…

人大金仓数据库驱动导入maven

1.去人大金仓官网去查找合适的驱动人大金仓-成为世界卓越的数据库产品与服务提供商 2.下载解压后 执行下面的代码 mvn install:install-file -DgroupIdkingbase -DartifactIdkingbase8 -Dversion8 -DfileF:\1foryou\foryou-report\kingbase8-8.6.0.jar -Dpackagingjar -Dgene…

FastAPI -- 第三弹(自定义响应、中间件、代理、WebSockets)

路径操作的高级配置 OpenAPI 的 operationId from fastapi import FastAPIapp FastAPI()# 通过 operation_id 参数设置 app.get("/items/", operation_id"some_specific_id_you_define") async def read_items():return [{"item_id": "F…

使用LVS+NGinx+Netty实现数据接入

数据接入 链接参考文档 LVSKeepalived项目 车辆数据上收&#xff0c;TBox通过TCP协议连接到TSP平台 建立连接后进行数据上传。也可借由该连接实现远程控制等操作。 通过搭建 LV—NGinx—Netty实现高并发数据接入 LVS&#xff1a;四层负载均衡&#xff08;位于内核层&#x…

Odoo17架构概述

多层架构 Odoo遵循多层架构&#xff0c;这意味着演示&#xff0c;业务逻辑和数据存储是分开的。更具体地说&#xff0c;它使用三层架构。 UI展示层 UI表示层是 HTML5、JavaScript 和 CSS 的组合。 应用程序的最顶层是用户界面。界面的主要功能是将任务和结果转换为用户可以理…

【数据结构】二叉树———Lesson2

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f4a5;&#x1f4a5;个人主页&#xff1a;奋斗的小羊 &#x1f4a5;&#x1f4a5;所属专栏&#xff1a;C语言 &#x1f680;本系列文章为个人学习…

Uniapp 组件 props 属性为 undefined

问题 props 里的属性值都是 undefined 代码 可能的原因 组件的名字要这样写&#xff0c;这个官方文档有说明

自动驾驶上的边缘计算的盒子的工作原理是什么?学习软件还要学习硬件是比较难的,但是学习硬件的再学习软件就是降维打击

边缘计算&#xff08;Edge Computing&#xff09;是一种分布式计算范式&#xff0c;它将数据处理和计算能力从集中式数据中心移至靠近数据源的边缘设备。这样可以显著减少延迟&#xff0c;提高响应速度&#xff0c;并减少带宽使用。下面是边缘计算的底层原理及其运行机制的详细…