NPOI入门指南:轻松操作Excel文件的.NET库
目录
引言
一、NPOI概述
二、NPOI的主要用途
三、安装NPOI库
四、NPOI基本使用
六、性能优化和内存管理
七、常见问题与解决方案
八、结论
附录
引言
Excel文件作为数据处理的重要工具,广泛应用于各种场景。然而,在没有安装Microsoft Office的环境下,如何高效地操作Excel文件成为了一个挑战。NPOI库的出现,为我们提供了一个强大的解决方案。本文将详细介绍NPOI库的基本使用方法和高级特性,帮助读者轻松操作Excel文件。
一、NPOI概述
NPOI是一个开源的.NET库,它允许开发者在无需安装Microsoft Office的情况下读写Excel文件。NPOI构建在Apache POI项目之上,并提供了丰富的API来操作Excel文件。NPOI支持xls(Excel 97-2003)和xlsx(Excel 2007及更高版本)两种文件格式,并且兼容大部分Excel的特性,如单元格样式、数据格式、公式等。
与其他类似库相比,NPOI具有以下优势:
- 无需安装Office:NPOI不依赖于Microsoft Office,可以在没有Office的环境下运行。
- 支持多种文件格式:除了xls和xlsx外,NPOI还支持docx文件格式的读写。
- 丰富的Excel特性支持:NPOI包含了大部分Excel的特性,如单元格样式、数据格式、公式等。
二、NPOI的主要用途
- Excel文件的读写:NPOI允许开发者在不需要安装Microsoft Office的情况下,对Excel文件进行读写操作。这对于需要在没有Office环境的服务器上进行数据处理的应用非常有用。
- 支持多种文件格式:除了Excel文件(xls、xlsx)外,NPOI还支持Word文件(docx)的读写。
- 丰富的Excel特性支持:NPOI包含了大部分Excel的特性,如单元格样式、数据格式、公式等,使得开发者能够更灵活地操作Excel文件。
三、安装NPOI库
安装NPOI库非常简单,只需要通过NuGet包管理器即可。在Visual Studio中,右键点击项目 -> 选择“管理NuGet程序包” -> 在“浏览”选项卡中搜索“NPOI” -> 点击“安装”按钮即可。
四、NPOI基本使用
-
文件内容示例
- 代码示例
/// <summary>
/// 简单读取文件内容
/// </summary>
static void SimpleRead()
{//文件路径string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "01.xlsx");//判断文件路径,存在则继续if (File.Exists(filePath)){//文件流FileStream fs = null;//Excel工作簿操作对象IWorkbook workbook = null;//开启异常捕捉try{StringBuilder sb = new StringBuilder();//定义文件流打开fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);//定义工作簿workbook = new XSSFWorkbook(fs);//读取工作表数量var numberOfSheets = workbook.NumberOfSheets;//判断工作表数量,大于零则继续if (numberOfSheets > 0){//获取第一个工作表var sheet0 = workbook.GetSheetAt(0);sb.AppendLine($"工作表名称:{sheet0.SheetName}");sb.AppendLine($"行数量:{sheet0.LastRowNum + 1}");if (sheet0.LastRowNum >= 0){//读取每一行信息for (int i = 0; i <= sheet0.LastRowNum; i++){var row = sheet0.GetRow(i);if (row != null){sb.Append($"第{i + 1}行数据:");//获取最后一列var lastCellNum = row.LastCellNum;for (int j = 0; j < lastCellNum; j++){//获取单元格var cell = row.GetCell(j);object cellValue = null;if (cell != null){#region 根据不同单元格格式提取内容switch (cell.CellType){case CellType.Boolean: cellValue = cell.BooleanCellValue; break;case CellType.Numeric: cellValue = cell.NumericCellValue; break;case CellType.Formula:var cachedCellType = cell.GetCachedFormulaResultTypeEnum();switch (cachedCellType){case CellType.Boolean: cellValue = cell.BooleanCellValue; break;case CellType.Numeric: cellValue = cell.NumericCellValue; break;default: cellValue = cell.StringCellValue; break;}break;default: cellValue = cell.StringCellValue; break;}#endregion}sb.Append($"\t{cellValue}");}sb.AppendLine();}}}Console.WriteLine(sb.ToString());}//关闭相关资源workbook.Close();workbook = null;//关闭相关资源fs.Close();fs = null;}catch (Exception ex){//显示异常信息Console.WriteLine($"发生异常:{ex.Message}");}finally{//关闭工作簿if (workbook != null){workbook.Close();}//关闭文件流if (fs != null){fs.Close();}}}
}
-
运行结果
简单文件写入
代码示例
/// <summary>
/// 简单写文件内容
/// </summary>
static void SimpleWrite()
{//文件路径string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "02.xlsx");//文件流FileStream fs = null;//Excel工作簿操作对象IWorkbook workbook = null;//开启异常捕捉try{#region 判断或创建文件var dir = Path.GetDirectoryName(filePath);if (!Directory.Exists(dir)){Directory.CreateDirectory(dir);}if (!File.Exists(filePath)){using (FileStream stream = new FileStream(filePath, FileMode.Create, FileAccess.Write))using (var wb = new XSSFWorkbook()){wb.Write(stream);wb.Close();stream.Close();}}#endregion//定义工作簿workbook = new XSSFWorkbook();#region 预防性处理工作表ISheet sheet = workbook.CreateSheet("数据");#region 第一行,标题:时间,内容var row1 = sheet.CreateRow(0);row1.CreateCell(0).SetCellValue("时间");row1.CreateCell(1).SetCellValue("内容");#endregion#region 增加几行数据int rowIndex = 1;for (int i = 0; i < 10; i++){var row = sheet.CreateRow(rowIndex++);row.CreateCell(0).SetCellValue(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));row.CreateCell(1).SetCellValue(Guid.NewGuid().ToString().ToUpper());}#endregion//自适应sheet.AutoSizeColumn(0);sheet.AutoSizeColumn(1);#endregion#region 保存using (fs = new FileStream(filePath, FileMode.Create, FileAccess.Write)){workbook.Write(fs);}#endregion//关闭相关资源workbook.Close();workbook = null;//关闭相关资源fs.Close();fs = null;}catch (Exception ex){//显示异常信息Console.WriteLine($"发生异常:{ex.Message}");}finally{//关闭工作簿if (workbook != null){workbook.Close();}//关闭文件流if (fs != null){fs.Close();}}
}
运行结果
定义单元格格式
代码示例
/// <summary>
/// 11 加粗 格式
/// </summary>
/// <param name="workbook"></param>
/// <returns></returns>
static ICellStyle GetHeaderStyle(IWorkbook workbook)
{var style = GetStyle(workbook, true);style.FillPattern = FillPattern.SolidForeground;style.FillForegroundColor = NPOI.HSSF.Util.HSSFColor.Grey25Percent.Index;return style;
}
/// <summary>
/// 红色背景 格式
/// </summary>
/// <param name="workbook"></param>
/// <returns></returns>
static ICellStyle GetRedBackNormalStyle(IWorkbook workbook)
{var style = GetStyle(workbook);style.FillPattern = FillPattern.SolidForeground;style.FillForegroundColor = NPOI.HSSF.Util.HSSFColor.Red.Index;return style;
}
/// <summary>
/// 红色字体 格式
/// </summary>
/// <param name="workbook"></param>
/// <returns></returns>
static ICellStyle GetRedNormalStyle(IWorkbook workbook)
{IFont font = workbook.CreateFont();font.Color = IndexedColors.Red.Index;font.FontHeightInPoints = 11;return GetStyle(workbook, font);
}
/// <summary>
/// 常规 格式
/// </summary>
/// <param name="workbook"></param>
/// <returns></returns>
static ICellStyle GetNormalStyle(IWorkbook workbook)
{return GetStyle(workbook);
}
/// <summary>
/// 时间 格式
/// </summary>
/// <param name="workbook"></param>
/// <returns></returns>
static ICellStyle GetDateTimeStyle(IWorkbook workbook)
{return GetStyle(workbook, false, 11, "yyyy-mm-dd hh:mm:ss");
}
/// <summary>
/// 数字 格式
/// </summary>
/// <param name="workbook"></param>
/// <returns></returns>
static ICellStyle GetIntStyle(IWorkbook workbook)
{return GetStyle(workbook, false, 11, "0");
}/// <summary>
/// 浮点数 格式
/// </summary>
/// <param name="workbook"></param>
/// <returns></returns>
static ICellStyle GetFloatStyle(IWorkbook workbook)
{return GetStyle(workbook, false, 11, "0.00");
}/// <summary>
/// 设定格式
/// </summary>
/// <param name="workbook">工作簿</param>
/// <param name="isBold">是否粗体,默认非粗体</param>
/// <param name="fontHeightInPoints">字高度(理解为字大小)</param>
/// <param name="dataFormat">自定义格式</param>
/// <param name="isWrapText">是否自动换行,默认是</param>
/// <returns></returns>
static ICellStyle GetStyle(IWorkbook workbook,bool isBold = false,double fontHeightInPoints = 11,string dataFormat = "",bool isWrapText = true)
{IFont font = workbook.CreateFont();font.IsBold = isBold;font.FontHeightInPoints = fontHeightInPoints;return GetStyle(workbook, font, dataFormat, isWrapText);
}
/// <summary>
/// 设定格式
/// </summary>
/// <param name="workbook">工作簿</param>
/// <param name="dataFormat">自定义格式</param>
/// <param name="isWrapText">是否自动换行,默认是</param>
/// <returns></returns>
static ICellStyle GetStyle(IWorkbook workbook,IFont font,string dataFormat = "",bool isWrapText = true)
{ICellStyle style = workbook.CreateCellStyle();style.Alignment = NPOI.SS.UserModel.HorizontalAlignment.Center;style.VerticalAlignment = NPOI.SS.UserModel.VerticalAlignment.Center;style.BorderBottom = NPOI.SS.UserModel.BorderStyle.Thin;style.BorderLeft = NPOI.SS.UserModel.BorderStyle.Thin;style.BorderTop = NPOI.SS.UserModel.BorderStyle.Thin;style.BorderRight = NPOI.SS.UserModel.BorderStyle.Thin;if (!string.IsNullOrWhiteSpace(dataFormat)){style.DataFormat = HSSFDataFormat.GetBuiltinFormat(dataFormat);if (style.DataFormat == -1) {IDataFormat format = workbook.CreateDataFormat();style.DataFormat = format.GetFormat(dataFormat);}}style.SetFont(font);style.WrapText = isWrapText;return style;
}
日常使用1
-
代码示例
/// <summary>/// 日常应用/// </summary>static void CommonApplicaiton(){//文件路径string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "03.xlsx");//文件流FileStream fs = null;//Excel工作簿操作对象IWorkbook workbook = null;//开启异常捕捉try{#region 判断或创建文件var dir = Path.GetDirectoryName(filePath);if (!Directory.Exists(dir)){Directory.CreateDirectory(dir);}if (!File.Exists(filePath)){using (FileStream stream = new FileStream(filePath, FileMode.Create, FileAccess.Write))using (var wb = new XSSFWorkbook()){wb.Write(stream);wb.Close();stream.Close();}}#endregion//定义工作簿workbook = new XSSFWorkbook();//整数格式单元格样式var intStyle = GetIntStyle(workbook);//时间格式单元格样式var dateTimeStyle = GetDateTimeStyle(workbook);//普通单元格样式var normalStyle = GetNormalStyle(workbook);//标题样式var headerStyle = GetHeaderStyle(workbook);#region 创建工作表ISheet sheet = workbook.CreateSheet("数据");#region 第一行,标题:序号,时间,整数随机数var row1 = sheet.CreateRow(0);var orderCell = row1.CreateCell(0);orderCell.CellStyle = headerStyle;orderCell.SetCellValue("序号");sheet.SetColumnWidth(0, 3 * 512);var timeCell = row1.CreateCell(1);timeCell.CellStyle = headerStyle;timeCell.SetCellValue("时间");sheet.SetColumnWidth(1, 10 * 512);var randomCell = row1.CreateCell(2);randomCell.CellStyle = headerStyle;randomCell.SetCellValue("整数随机数");sheet.SetColumnWidth(2, 10 * 512);#endregion#region 增加几行数据Random random = new Random();int rowIndex = 1;for (int i = 0; i < 10; i++){var row = sheet.CreateRow(rowIndex++);//序号,直接用公式var cell1 = row.CreateCell(0);cell1.CellStyle = normalStyle;cell1.CellFormula = "ROW()-1";var cell2 = row.CreateCell(1);cell2.SetCellValue(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));cell2.CellStyle = normalStyle; var cell3 = row.CreateCell(2);cell3.CellStyle = intStyle;cell3.SetCellValue(random.Next());}#endregion#endregion#region 保存using (fs = new FileStream(filePath, FileMode.Create, FileAccess.Write)){workbook.Write(fs);}#endregion//关闭相关资源workbook.Close();workbook = null;//关闭相关资源fs.Close();fs = null;}catch (Exception ex){//显示异常信息Console.WriteLine($"发生异常:{ex.Message}");}finally{//关闭工作簿if (workbook != null){workbook.Close();}//关闭文件流if (fs != null){fs.Close();}}}
运行结果
五、高级特性应用
- 数据验证
NPOI支持在Excel单元格中设置数据验证规则,例如限制输入的数据类型、范围等。
- 条件格式化
使用NPOI可以创建条件格式化规则,根据单元格的值改变其外观(如颜色、字体等)。
- 图表
NPOI支持创建和编辑Excel图表,包括柱状图、折线图、饼图等。
六、性能优化和内存管理
- 使用流(Stream)来读写文件
使用FileStream
而不是将整个文件加载到内存中,以提高性能和减少内存使用。
- 及时释放资源
在操作完Excel文件后,确保释放所有相关的资源,如FileStream
、IWorkbook
等。
七、常见问题与解决方案
- 无法打开xlsx文件
确保已正确安装NPOI库,并且使用了正确的文件路径和文件名。
- 单元格样式不生效
检查是否已正确创建和应用了单元格样式。
八、结论
NPOI库为.NET环境下的Excel文件操作提供了强大的支持。通过本文的介绍,相信读者已经掌握了NPOI库的基本使用方法和高级特性。鼓励大家尝试使用NPOI来处理Excel文件,并分享自己的使用经验和技巧。
附录
-
更多内容请参考以下网址https://github.com/nissl-lab/npoi
- NPOI官方文档链接:NPOI官方网站
- 相关资源下载地址:[NPOI NuGet包](NuGet Gallery | NPOI 2.7.0
相关文章:

NPOI入门指南:轻松操作Excel文件的.NET库
目录 引言 一、NPOI概述 二、NPOI的主要用途 三、安装NPOI库 四、NPOI基本使用 六、性能优化和内存管理 七、常见问题与解决方案 八、结论 附录 引言 Excel文件作为数据处理的重要工具,广泛应用于各种场景。然而,在没有安装Microsoft Office的…...

【高性能服务器】服务器概述
🔥博客主页: 我要成为C领域大神🎥系列专栏:【C核心编程】 【计算机网络】 【Linux编程】 【操作系统】 ❤️感谢大家点赞👍收藏⭐评论✍️ 本博客致力于知识分享,与更多的人进行学习交流 服务器概述 服…...
003 SSM框架整合
文章目录 整合web.xmlapplicationContext-dao.xmlapplicationContext-service.xmlspringmvc.xmldb.propertieslog4j.propertiespom.xml 测试sqlItemController.javaItemMapper.javaItem.javaItemExample.javaItemService.javaItemServiceImpl.javaItemMapper.xml 整合 将工程的…...

web刷题记录(7)
[HDCTF 2023]SearchMaster 打开环境,首先的提示信息就是告诉我们,可以用post传参的方式来传入参数data 首先考虑的还是rce,但是这里发现,不管输入那种命令,它都会直接显示在中间的那一小行里面,而实际的命令…...

【单片机毕业设计选题24037】-基于STM32的电力系统电力参数无线监控系统
系统功能: 系统上电后,OLED显示“欢迎使用电力监控系统请稍后”,两秒后显示“Waiting..”等待ESP8266初始化完成, ESP8266初始化成功后进入正常页面显示, 第一行显示电压值(单位V) 第二行显示电流值&am…...
Python使用彩虹表来尝试对MD5哈希进行破解
MD5是一种散列算法,它是不可逆的,无法直接解密。它的主要作用是将输入数据进行散列,生成一个固定长度的唯一哈希值。 然而,可以使用预先计算好的MD5哈希值的彩虹表(Rainbow Table)来尝试对MD5进行破解。彩…...

数据恢复篇: 如何在数据丢失后恢复照片
数据丢失的情况并不少见。如果您曾经遇到过图像丢失的情况,您可能想过照片恢复工具是如何工作的?可能会丢失多少数据图像?即使是断电也可能导致照片和媒体文件丢失。 话虽如此,如果你认为删除的照片无法恢复,那你就错…...
c++ 引用第三方库
文章目录 背景编写cmake代码里引用测试 背景 遇到一个c项目,想跑一些示例。了解下如何直接引用第三方库。 编写cmake 项目结构 myprojectincludexx.hmain.cppCMakeLists.txt CMakeLists.txt cmake_minimum_required(VERSION 3.28) project(velox_demo)set(CM…...

[数据集][目标检测]猪只状态吃喝睡站检测数据集VOC+YOLO格式530张4类别
数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):530 标注数量(xml文件个数):530 标注数量(txt文件个数):530 标注类别…...
Redis中设置验证码
限制一分钟内最多发送5次,且每次有效时间是5分钟! String 发送验证码(phoneNumber) {key "shortMsg:limit:" phoneNumber;// 设置过期时间为 1 分钟(60 秒)// 使⽤ NX,只在不存在 key 时才能设置成功bool…...
使用hadoop进行数据分析
Hadoop是一个开源框架,它允许分布式处理大数据集群上的大量数据。Hadoop由两个主要部分组成:HDFS(Hadoop分布式文件系统)和MapReduce。以下是使用Hadoop进行数据分析的基本步骤: 数据准备: 将数据存储在HDF…...

架构师篇-7、企业安全架构设计及实践
摘要: 认识企业安全架构企业安全案例分析及实践 内容: 为什么做企业安全架构怎么做好安全架构设计案例实践分析&随堂练 为什么要做企业安全架构 安全是麻烦制造者? 整天提安全需求增加开发工作增加运维要求增加不确定性延后业务上线…...
递归算法~快速排序、归并排序
递归排序是一种基于分治法的排序算法,最典型的例子就是快速排序和归并排序。这两种算法都利用递归将问题分解成更小的子问题,然后将子问题的解合并以得到原始问题的解。 1、快速排序(Quick Sort) 快速排序的基本思想是选择一个基…...

DarkGPT:基于GPT-4-200k设计的人工智能OSINT助手
关于DarkGPT DarkGPT是一款功能强大的人工智能安全助手,该工具基于GPT-4-200k设计并实现其功能,可以帮助广大研究人员针对泄露数据库进行安全分析和数据查询相关的OSINT操作。 工具要求 openai1.13.3 requests python-dotenv pydantic1.10.12 工具安装 …...

RAG 检索增强生成有效评估
我们将介绍RAG(检索增强生成)的评估工作流程 RAG工作流程的部分 数据集 这里是我们将要使用的LCEL (LangChain Expression Language)相关问题的数据集。 这个数据集是在LangSmith UI中使用csv上传创建的: https://smith.langchain.com/public/730d833b-74da-43e2-a614-4e2ca…...

Day38:LeedCode 1049. 最后一块石头的重量 II 494. 目标和 474.一和零
1049. 最后一块石头的重量 II 有一堆石头,用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。 每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为 x 和 y,且 x < y。那么粉碎的可能结果…...
sqlalchemy分页查询
sqlalchemy分页查询 在SQLAlchemy中,可以使用limit和offset方法实现分页查询 from sqlalchemy.orm import sessionmaker from sqlalchemy import create_engine from models import MyModel # 假设MyModel是你定义的模型# 连接数据库 engine = create_engine(sqlite:///myd…...

Java--常用类APl(复习总结)
前言: Java是一种强大而灵活的编程语言,具有广泛的应用范围,从桌面应用程序到企业级应用程序都能够使用Java进行开发。在Java的编程过程中,使用标准类库是非常重要的,因为标准类库提供了丰富的类和API,可以简化开发过…...

【股指期权投教】一手股指期权大概多少钱?
一手股指期权的权利金大概在几千人民币左右,如果是作为期权卖方还需要另外缴纳保证金的。国内的股指期权有三种,沪深300、上证50、中证1000股指期权,每点合约人民币100 元。 期权合约的价值计算可以通过此公式得出:权利金的支付或…...

mmap()函数和munmap()函数的例子
代码: #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/mman.h> #include <string.h> #include <stdio.h> #include <unistd.h>#define FILELENGTH 80 int main(void) {int fd-1;char …...

家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...
C++八股 —— 单例模式
文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全(Thread Safety) 线程安全是指在多线程环境下,某个函数、类或代码片段能够被多个线程同时调用时,仍能保证数据的一致性和逻辑的正确性…...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...

脑机新手指南(七):OpenBCI_GUI:从环境搭建到数据可视化(上)
一、OpenBCI_GUI 项目概述 (一)项目背景与目标 OpenBCI 是一个开源的脑电信号采集硬件平台,其配套的 OpenBCI_GUI 则是专为该硬件设计的图形化界面工具。对于研究人员、开发者和学生而言,首次接触 OpenBCI 设备时,往…...

关于easyexcel动态下拉选问题处理
前些日子突然碰到一个问题,说是客户的导入文件模版想支持部分导入内容的下拉选,于是我就找了easyexcel官网寻找解决方案,并没有找到合适的方案,没办法只能自己动手并分享出来,针对Java生成Excel下拉菜单时因选项过多导…...

wpf在image控件上快速显示内存图像
wpf在image控件上快速显示内存图像https://www.cnblogs.com/haodafeng/p/10431387.html 如果你在寻找能够快速在image控件刷新大图像(比如分辨率3000*3000的图像)的办法,尤其是想把内存中的裸数据(只有图像的数据,不包…...
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析 一、第一轮基础概念问题 1. Spring框架的核心容器是什么?它的作用是什么? Spring框架的核心容器是IoC(控制反转)容器。它的主要作用是管理对…...