Apache POI 使用Java处理Excel数据 进阶

1.POI入门教程链接

http://t.csdnimg.cn/Axn4Picon-default.png?t=N7T8http://t.csdnimg.cn/Axn4P建议:从入门看起会更好理解POI对Excel数据的使用和处理

记得引入依赖:

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

2.POI对单元格样式处理

// JUnit的@Test注解表示这是一个测试方法@Testvoid testExcel() throws IOException {// 创建一个新的XSSFWorkbook对象,这是操作Excel文件的核心类XSSFWorkbook workbook = new XSSFWorkbook();// 在工作簿中创建一个名为"sheet1"的工作表XSSFSheet sheet = workbook.createSheet("sheet1");// 在工作表中创建第三行(行索引从0开始)Row row = sheet.createRow(2);// 在该行中创建第三个单元格(列索引从0开始)Cell cell = row.createCell(2);// 设置单元格的值为"Hello World 2024"cell.setCellValue("Hello World 2024");// 创建一个单元格样式CellStyle cellStyle = workbook.createCellStyle();// 设置单元格的上下左右边框为细线cellStyle.setBorderTop(BorderStyle.THIN);cellStyle.setBorderBottom(BorderStyle.THIN);cellStyle.setBorderLeft(BorderStyle.THIN);cellStyle.setBorderRight(BorderStyle.THIN);// 创建一个字体对象Font font = workbook.createFont();// 设置字体为"宋体"font.setFontName("宋体");// 设置字体大小为32磅font.setFontHeightInPoints((short) 32);// 将字体应用到单元格样式中cellStyle.setFont(font);// 设置行高为50磅row.setHeightInPoints((short) 50);// 设置第三列的宽度为100 * 365(单位是1/256个字符宽度)sheet.setColumnWidth(2, 100 * 365);// 将单元格样式应用到单元格上cell.setCellStyle(cellStyle);// 创建一个文件输出流,用于将Excel文件写入磁盘FileOutputStream out = new FileOutputStream("D:\\Desktop\\JavaCode\\poi-demo\\src\\main\\resources\\test.xlsx");// 将工作簿写入输出流workbook.write(out);// 关闭输出流out.close();}

3.将图片写入Excel表格中

  // JUnit的@Test注解表示这是一个测试方法@Testvoid testDrawExcel() throws IOException {// 创建一个新的XSSFWorkbook对象,这是操作Excel文件的核心类XSSFWorkbook workbook = new XSSFWorkbook();// 在工作簿中创建一个名为"sheet1"的工作表XSSFSheet sheet = workbook.createSheet("sheet1");// 创建一个文件输入流,用于读取图片文件FileInputStream in = new FileInputStream("D:\\Desktop\\test.jpg");// 创建一个字节数组,长度为图片文件的大小byte[] bytes = new byte[in.available()];// 读取图片文件到字节数组in.read(bytes);// 关闭输入流in.close();// 将图片添加到工作簿,并返回图片的索引int index = workbook.addPicture(bytes, Workbook.PICTURE_TYPE_JPEG);// 获取创建助手,用于创建绘图对象CreationHelper helper = workbook.getCreationHelper();// 创建绘图对象,用于在工作表中绘制图片XSSFDrawing drawing = sheet.createDrawingPatriarch();// 创建客户端锚点,用于指定图片的位置ClientAnchor anchor = helper.createClientAnchor();// 设置图片的起始行anchor.setRow1(0);// 设置图片的起始列anchor.setCol1(1);// 创建图片对象,并将其插入到工作表中XSSFPicture picture = drawing.createPicture(anchor, index);// 调整图片大小以适应单元格picture.resize();// 创建一个文件输出流,用于将Excel文件写入磁盘FileOutputStream out = new FileOutputStream("D:\\Desktop\\JavaCode\\poi-demo\\src\\main\\resources\\test.xlsx");// 将工作簿写入输出流workbook.write(out);// 关闭输出流out.close();}

4.使用模版Excel

如何想根据模版进行创建Excel表格。而不是直接覆盖创建新的Excel表格的方式:

// JUnit的@Test注解表示这是一个测试方法@Testvoid testDrawExcel() throws IOException {// 使用Spring的ClassPathResource来加载类路径下的资源文件Resource resource = new ClassPathResource("test.xlsx");// 获取资源文件的FileInputStreamFileInputStream resourceIn = new FileInputStream(resource.getFile());// 使用FileInputStream加载现有工作簿XSSFWorkbook workbook = new XSSFWorkbook(resourceIn);// 获取工作簿中的第一个工作表XSSFSheet sheet = workbook.getSheetAt(0);// 创建一个文件输入流,用于读取图片文件FileInputStream in = new FileInputStream("D:\\Desktop\\test.jpg");// 创建一个字节数组,长度为图片文件的大小byte[] bytes = new byte[in.available()];// 读取图片文件到字节数组in.read(bytes);// 关闭输入流in.close();// 将图片添加到工作簿,并返回图片的索引int index = workbook.addPicture(bytes, Workbook.PICTURE_TYPE_JPEG);// 获取创建助手,用于创建绘图对象CreationHelper helper = workbook.getCreationHelper();// 获取工作表中的绘图对象,如果没有则创建Drawing<?> drawing = sheet.createDrawingPatriarch();// 创建客户端锚点,用于指定图片的位置ClientAnchor anchor = helper.createClientAnchor();// 设置图片的起始行为第11行(行索引从0开始)anchor.setRow1(10);// 设置图片的起始列为第2列(列索引从0开始)anchor.setCol1(1);// 创建图片对象,并将其插入到工作表中Picture picture = drawing.createPicture(anchor, index);// 调整图片大小以适应单元格picture.resize();// 创建一个文件输出流,用于将Excel文件写入磁盘FileOutputStream out = new FileOutputStream("D:\\Desktop\\JavaCode\\poi-demo\\src\\main\\resources\\test.xlsx");// 将工作簿写入输出流workbook.write(out);// 关闭输出流out.close();}

5.自定义Excel工具类

(1)自定义注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ExcelAttribute {/** 对应的列名称 */String name() default "";/** 列序号 */int sort();/** 字段类型对应的格式 */String format() default "";}

(2) 导出工具类:

public class ExcelExportUtil<T> {private int rowIndex;private int styleIndex;private String templatePath;private Class clazz;private  Field fields[];public ExcelExportUtil(Class clazz,int rowIndex,int styleIndex) {this.clazz = clazz;this.rowIndex = rowIndex;this.styleIndex = styleIndex;fields = clazz.getDeclaredFields();}/*** 基于注解导出*/public void export(HttpServletResponse response,InputStream is, List<T> objs,String 
fileName) throws Exception {XSSFWorkbook workbook = new XSSFWorkbook(is);Sheet sheet = workbook.getSheetAt(0);CellStyle[] styles = getTemplateStyles(sheet.getRow(styleIndex));AtomicInteger datasAi = new AtomicInteger(rowIndex);for (T t : objs) {Row row = sheet.createRow(datasAi.getAndIncrement());for(int i=0;i<styles.length;i++) {Cell cell = row.createCell(i);cell.setCellStyle(styles[i]);for (Field field : fields) {if(field.isAnnotationPresent(ExcelAttribute.class)){field.setAccessible(true);ExcelAttribute ea = field.getAnnotation(ExcelAttribute.class);if(i == ea.sort()) {cell.setCellValue(field.get(t).toString());}}}}}fileName = URLEncoder.encode(fileName, "UTF-8");response.setContentType("application/octet-stream");response.setHeader("content-disposition", "attachment;filename=" + new 
String(fileName.getBytes("ISO8859-1")));response.setHeader("filename", fileName);workbook.write(response.getOutputStream());}public CellStyle[] getTemplateStyles(Row row) {CellStyle [] styles = new CellStyle[row.getLastCellNum()];for(int i=0;i<row.getLastCellNum();i++) {styles[i] = row.getCell(i).getCellStyle();}return styles;}
}

(3)导入工具类:

public class ExcelImportUtil<T> {private Class clazz;private  Field fields[];public ExcelImportUtil(Class clazz) {this.clazz = clazz;fields = clazz.getDeclaredFields();}/*** 基于注解读取excel*/public List<T> readExcel(InputStream is, int rowIndex,int cellIndex) {List<T> list = new ArrayList<T>();T entity = null;try {XSSFWorkbook workbook = new XSSFWorkbook(is);Sheet sheet = workbook.getSheetAt(0);// 不准确int rowLength = sheet.getLastRowNum();System.out.println(sheet.getLastRowNum());for (int rowNum = rowIndex; rowNum <= sheet.getLastRowNum(); rowNum++) {Row row = sheet.getRow(rowNum);entity = (T) clazz.newInstance();System.out.println(row.getLastCellNum());for (int j = cellIndex; j < row.getLastCellNum(); j++) {Cell cell = row.getCell(j);for (Field field : fields) {if(field.isAnnotationPresent(ExcelAttribute.class)){field.setAccessible(true);ExcelAttribute ea = 
field.getAnnotation(ExcelAttribute.class);if(j == ea.sort()) {field.set(entity, covertAttrType(field, cell));}}}}list.add(entity);}} catch (Exception e) {e.printStackTrace();}return list;}/*** 类型转换 将cell 单元格格式转为 字段类型
*/private Object covertAttrType(Field field, Cell cell) throws Exception {String fieldType = field.getType().getSimpleName();if ("String".equals(fieldType)) {return getValue(cell);}else if ("Date".equals(fieldType)) {return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse(getValue(cell)) ;}else if ("int".equals(fieldType) || "Integer".equals(fieldType)) {return Integer.parseInt(getValue(cell));}else if ("double".equals(fieldType) || "Double".equals(fieldType)) {return Double.parseDouble(getValue(cell));}else {return null;}}/*** 格式转为String* @param cell* @return*/public String getValue(Cell cell) {if (cell == null) {return "";}switch (cell.getCellType()) {case STRING:return cell.getRichStringCellValue().getString().trim();case NUMERIC:if (DateUtil.isCellDateFormatted(cell)) {Date dt = DateUtil.getJavaDate(cell.getNumericCellValue());return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(dt);} else {// 防止数值变成科学计数法String strCell = "";Double num = cell.getNumericCellValue();BigDecimal bd = new BigDecimal(num.toString());if (bd != null) {strCell = bd.toPlainString();}// 去除 浮点型 自动加的 .0if (strCell.endsWith(".0")) {strCell = strCell.substring(0, strCell.indexOf("."));}return strCell;}case BOOLEAN:return String.valueOf(cell.getBooleanCellValue());default:return "";}}

(4)工具类的使用

在User实体上对导出的字段名加上自定义注解@ExcelAttribute(序列号)

导入数据:

List<User> list = new ExcelImportUtil(User.class).readExcel(is, 1, 2);

导出数据:

@GetMapping("/export/{month}")public void export(@PathVariable(name = "month") String month) throws Exception {//1.构造数据List<EmployeeReportResult> list = 
userCompanyPersonalService.findByReport(companyId,month+"%");//2.加载模板流数据Resource resource = new ClassPathResource("excel-template/hr-demo.xlsx");FileInputStream fis = new FileInputStream(resource.getFile());new ExcelExportUtil(EmployeeReportResult.class,2,2).export(response,fis,list,"人事报表.xlsx");}

6.处理大量数据的文件(SXSSF)

(1)SXSSF和XSSF的区别

SXSSF和XSSF都是Apache POI库中用于处理Excel文件的API,它们属于POI项目中用于操作Excel 2007 OOXML (.xlsx)文件的组件。以下是SXSSF和XSSF的主要区别:

  1. 内存使用

    • XSSF:为处理大型Excel文件提供了完整的API支持,但它会将整个工作簿加载到内存中。这意味着对于非常大的Excel文件,它可能会消耗大量的Java堆内存。
    • SXSSF:是XSSF的流式扩展,目的是减少内存消耗。它不会将整个工作簿保留在内存中,而是仅保持一定数量的行在内存中,其余的行将被写入磁盘上的临时文件中。
  2. 性能

    • 使用XSSF处理非常大的Excel文件时,可能会遇到性能瓶颈,因为它需要更多的内存资源。
    • SXSSF在处理大型文件时性能更优,因为它使用了更少的内存,并且它的写入操作是流式的。
  3. 功能限制

    • XSSF提供了完整的Excel文件处理能力,但由于其内存占用较大,处理大型文件时可能会出现问题。
    • SXSSF由于使用了流式处理,因此有一些限制。例如,它不支持获取或设置单元格样式,也不支持插入或删除行。
  4. 使用场景

    • 如果您的应用程序需要处理中等大小的Excel文件,并且需要完整的Excel功能,XSSF是一个不错的选择。
    • 如果您需要处理大型Excel文件,并且可以接受SXSSF的一些限制,那么SXSSF可能是更好的选择。

(2)代码实现:

自定义处理器

/自定义Sheet基于Sax的解析处理器
public class SheetHandler implements XSSFSheetXMLHandler.SheetContentsHandler {//封装实体对象private PoiEntity entity;/*** 解析行开始*/@Overridepublic void startRow(int rowNum) {if (rowNum >0 ) {entity = new PoiEntity();}}/* * 解析每一个单元格*/@Overridepublic void cell(String cellReference, String formattedValue, XSSFComment comment) {if(entity != null) {switch (cellReference.substring(0, 1)) {case "A":entity.setId(formattedValue);break;case "B":entity.setBreast(formattedValue);break;case "C":entity.setAdipocytes(formattedValue);break;case "D":entity.setNegative(formattedValue);break;case "E":entity.setStaining(formattedValue);break;case "F":entity.setSupportive(formattedValue);break;default:break;}}}/*** 解析行结束*/public void endRow(int rowNum) {System.out.println(entity);}//处理头尾public void headerFooter(String text, boolean isHeader, String tagName) {}
}

自定义解析器

/*** 自定义Excel解析器*/
public class ExcelParser {public void parse (String path) throws Exception {//1.根据Excel获取OPCPackage对象OPCPackage pkg = OPCPackage.open(path, PackageAccess.READ);try {//2.创建XSSFReader对象XSSFReader reader = new XSSFReader(pkg);//3.获取SharedStringsTable对象SharedStringsTable sst = reader.getSharedStringsTable();//4.获取StylesTable对象StylesTable styles = reader.getStylesTable();//5.创建Sax的XmlReader对象XMLReader parser = XMLReaderFactory.createXMLReader();//6.设置处理器parser.setContentHandler(new XSSFSheetXMLHandler(styles,sst, new 
SheetHandler(), false));XSSFReader.SheetIterator sheets = (XSSFReader.SheetIterator) 
reader.getSheetsData();//7.逐行读取while (sheets.hasNext()) {InputStream sheetstream = sheets.next();InputSource sheetSource = new InputSource(sheetstream);try {parser.parse(sheetSource);} finally {sheetstream.close();}}} finally {pkg.close();}}
}

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

MongoDB教程(十):Python集成mongoDB

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; 文章目录 引言一、环境准…

golang单元测试性能测试常见用法

关于go test的一些说明 golang安装后可以使用go test工具进行单元测试 代码片段对比的性能测试,使用起来还是比较方便,下面是一些应用场景 平时自己想做一些简单函数的单元测试&#xff0c;不用每次都新建一个main.go 然后go run main.go相对某个功能做下性能测试 看下cpu/内存…

WEB前端05-JavaScrip基本对象

JavaScript对象 1.Function对象 函数的创建 //方法一&#xff1a;自定义函数 function 函数名([参数]) {函数体[return 表达式] }//方法二&#xff1a;匿名函数 (function([参数]) {函数体[return 表达式] }); **使用场景一&#xff1a;定义后直接调用使用(只使用一次) (fun…

RISC-V在线反汇编工具

RISC-V在线反汇编工具&#xff1a; https://luplab.gitlab.io/rvcodecjs/#q34179073&abifalse&isaAUTO 不过&#xff0c;似乎&#xff0c;只支持RV32I、RV64I、RV128I指令集&#xff1a;

Linux·基本指令(下)

1. mv 指令 (move) 语法&#xff1a;mv[选项] 源文件或目录 目标文件或目录 功能&#xff1a;将源文件或目录剪贴到一个新位置&#xff0c;或给源文件或目录改名但不会改变其内容 常用选项&#xff1a; -f &#xff1a;force 强制&#xff0c;如果目标文件已经存在&#xff0c;…

力扣622.设计循环队列

力扣622.设计循环队列 通过数组索引构建一个虚拟的首尾相连的环当front rear时 队列为空当front rear 1时 队列为满 (最后一位不存) class MyCircularQueue {int front;int rear;int capacity;vector<int> elements;public:MyCircularQueue(int k) {//最后一位不存…

vscode+SSH连接Ubuntu

目录 问题引入 基本思路 Permission denied, please try again 修改用户名与密码 新建用户 最终成功方案 问题引入 ssh 用户名ip地址。用户名是远端服务器的用户名&#xff0c;ip地址也是远端服务器的地址。linux虚拟机的ip地址与windous主体不一样&#xff0c;所以还需要…

微信小程序与本地MySQL数据库通信

微信小程序与本地MySQL数据库通信 因为本地MySQL服务器没有域名&#xff0c;也没有进行相应的请求操作封装&#xff0c;因此微信小程序没办法和数据库通信。 但是对于开发人员来说&#xff0c;没有数据库&#xff0c;那还能干撒&#xff1f;虽然我尝试过用json-server&#x…

【C++】类和对象·this指针

C中的类与C语言中的结构体有很多的相似的地方&#xff0c;可以说本质上除了结构体只能定义成员变量&#xff0c;以及结构体默认的访问控制权限是public之外与class没啥区别。但是结构体变量每次调用函数的时候需要指针&#xff0c;而类中的成员函数明明被保存在公共代码段&…

Redis之哈希类型

目录 一.命令 二.内部编码 1.压缩列表&#xff08;ziplist&#xff09; 2. 哈希表&#xff08;Hashtable&#xff09; 自动转换策略 三.作为缓存 Redis的学习专栏&#xff1a;http://t.csdnimg.cn/a8cvV 一.命令 HSET命令 设置hash中指定的字段&#xff08;field)的值,时…

Ubuntu22.04安装OMNeT++

一、官网地址及安装指南 官网地址&#xff1a;OMNeT Discrete Event Simulator 官网安装指南&#xff08;V6.0.3&#xff09;&#xff1a;https://doc.omnetpp.org/omnetpp/InstallGuide.pdf 官网下载地址&#xff1a;OMNeT Downloads 旧版本下载地址&#xff1a;OMNeT Old…

OAI 5G-NR源码架构

OAI 5G-NR源码架构 1 特性范围 目前gNB和5G-NRUE支持如下的配置&#xff1a; 工作模式&#xff1a;TDDCP长度&#xff1a;Normal CP子载波间隔&#xff1a; 30kHz信道带宽&#xff1a;40MHz(106PRB)、80MHz(217PRB)、100MHz(237PRB)天线端口&#xff1a;单波束时隙格式&…

Redis-应用

目录 应用 缓存雪崩、击穿、穿透和解决办法? 布隆过滤器是怎么工作的? 缓存的数据一致性怎么保证 Redis和Mysql消息一致性 业务一致性要求高怎么办? 数据库与缓存的一致性问题 数据库和缓存的一致性如何保证 如何保证本地缓存和分布式缓存的一致&#xff1f; 如果在…

solidity基础语法(以太坊solidity合约)

solidity基础语法&#xff08;以太坊solidity合约&#xff09; 1-值类型和取值范围2-引用类型3-引用类型高阶4-固定数组和动态数组 1-值类型和取值范围 https://learnblockchain.cn/docs/solidity/introduction-to-smart-contracts.html#subcurrency https://learnblockchain…

WEB前端06-DOM对象

BOM浏览器对象模型 浏览器对象模型&#xff1a;将浏览器的各个组成部分封装成对象。是用于描述浏览器中对象与对象之间层次关系的模型&#xff0c;提供了独立于页面内容、并能够与浏览器窗口进行交互的对象结构。 组成部分 Window&#xff1a;浏览器窗口对象 Navigator&…

Hadoop3:HDFS存储优化之小文件归档

一、情景说明 我们知道&#xff0c;NameNode存储一个文件元数据&#xff0c;默认是150byte大小的内存空间。 那么&#xff0c;如果出现很多的小文件&#xff0c;就会导致NameNode的内存占用。 但注意&#xff0c;存储小文件所需要的磁盘容量和数据块的大小无关。 例如&#x…

电脑压缩视频文件 电脑压缩视频大小的方法

在数字化时代&#xff0c;视频已成为我们记录生活、分享快乐的重要工具。然而&#xff0c;大尺寸的视频文件常常让分享和存储变得棘手。如何在保持视频画质的前提下&#xff0c;轻松减小视频文件大小&#xff1f;今天&#xff0c;就让我们一起探索苹果电脑上的几种高效视频压缩…

iPhone手机怎么识别藏文?藏语翻译通App功能介绍:藏文OCR识别提取文字

在工作学习的过程中&#xff0c;遇到不会的藏文&#xff0c;也不知道怎么把文字打出来&#xff0c;这个时候可以试试《藏语翻译通》App的图片识别功能&#xff0c;支持拍照识别和图片识别&#xff0c;拍一拍就能提取藏文文字&#xff0c;并支持一键翻译和复制分享。 跟着小编的…

数据结构之双向链表(赋源码)

数据结构之双向链表(源码) 线性表 双向链表是线性表链式存储结构的一种&#xff0c;若对链式存储结构进行分类可以分为八种。 带头、不带头&#xff1a;指的是该连链表有无头节点&#xff0c;头节点不存放任何内容&#xff0c;它不一定是链表必备的元素&#xff0c;而一个链…

十五、【机器学习】【监督学习】- 神经网络回归

系列文章目录 第一章 【机器学习】初识机器学习 第二章 【机器学习】【监督学习】- 逻辑回归算法 (Logistic Regression) 第三章 【机器学习】【监督学习】- 支持向量机 (SVM) 第四章【机器学习】【监督学习】- K-近邻算法 (K-NN) 第五章【机器学习】【监督学习】- 决策树…