Spring Boot 文件上传与下载(图片 / Excel)
在Spring Boot纯接口开发熟练掌握后,文件操作便成为进阶必备技能——无论是日常开发中的图片上传、Excel导入导出,还是各类小工具的核心功能,都离不开文件的上传与解析。本文承接纯接口开发的基础,手把手实战本地文件上传、图片上传与回显、Excel文件上传解析(兼顾POI与EasyExcel两种主流方式),全程贴合实际开发场景,帮你快速掌握文件操作核心,为后续开发小工具筑牢基础。
一、前置准备:环境搭建与核心配置
文件操作核心依赖为文件上传组件、Excel解析组件(POI/EasyExcel),同时需配置文件存储路径、上传大小限制,避免出现上传失败、文件过大等问题。
1.1 Maven 核心依赖
按需引入依赖,其中EasyExcel相比POI更轻量、内存占用更低,适合大数据量Excel解析;POI兼容性更强,适合复杂Excel操作,可根据需求选择:
<!-- Spring Boot Web 核心依赖(文件上传依赖已集成) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 图片处理依赖(可选,用于图片压缩、格式转换) -->
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>0.4.19</version>
</dependency>
<!-- POI 依赖(Excel解析,兼容复杂Excel) -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
</dependency>
<!-- EasyExcel 依赖(Excel解析,轻量高效,推荐) -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.3.2</version>
</dependency>
<!-- lombok 简化代码 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- commons-io 工具类(简化文件操作) -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
1.2 核心配置(application.yml)
配置文件上传大小限制、本地存储路径、图片访问路径,集中管理,便于后续修改和维护:
spring:
# 文件上传配置
servlet:
multipart:
enabled: true # 开启文件上传
max-file-size: 10MB # 单个文件最大大小(根据需求调整,如Excel可设为50MB)
max-request-size: 100MB # 单次请求最大文件大小
# 自定义文件存储配置
file:
# 本地存储根路径(建议使用绝对路径,避免部署时路径混乱)
upload-path: D:/springboot-file/upload/
# 图片访问路径前缀(用于图片回显,与下面的静态资源配置对应)
image-access-path: /upload/images/
# Excel存储路径(单独划分,便于管理)
excel-upload-path: ${file.upload-path}excel/
# 普通文件存储路径
common-upload-path: ${file.upload-path}common/
# Spring MVC 静态资源配置(关键:让前端能访问本地上传的图片)
spring:
mvc:
static-path-pattern: /upload/**
web:
resources:
static-locations: file:${file.upload-path}
关键说明:1. 存储路径建议使用绝对路径,Windows系统如D:/springboot-file/upload/,Linux系统如/root/springboot-file/upload/;2. 静态资源配置必须正确,否则前端无法通过URL回显图片;3. 上传大小限制需根据业务调整,避免过小导致无法上传大文件。
1.3 工具类准备(文件操作通用工具)
封装通用文件操作方法(创建目录、生成唯一文件名、删除文件),避免重复代码,提升开发效率:
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
/**
* 文件操作通用工具类
*/
@Component
public class FileUtil {
// 注入配置文件中的存储路径
@Value("${file.upload-path}")
private String uploadRootPath;
@Value("${file.image-access-path}")
private String imageAccessPath;
@Value("${file.excel-upload-path}")
private String excelUploadPath;
@Value("${file.common-upload-path}")
private String commonUploadPath;
/**
* 生成唯一文件名(避免文件名重复,覆盖文件)
* @param originalFilename 原始文件名
* @return 唯一文件名(UUID + 后缀名)
*/
public String generateUniqueFileName(String originalFilename) {
// 获取文件后缀名(如.jpg、.xlsx)
String suffix = FilenameUtils.getExtension(originalFilename);
// 生成UUID(唯一标识),拼接后缀名
return UUID.randomUUID().toString() + "." + suffix;
}
/**
* 创建目录(若目录不存在则创建)
* @param filePath 目录路径
*/
public void createDirectory(String filePath) {
File file = new File(filePath);
if (!file.exists()) {
// 递归创建目录(包括父目录)
file.mkdirs();
}
}
/**
* 上传文件到指定目录
* @param file 上传的文件(MultipartFile)
* @param targetDir 目标存储目录(如图片、Excel目录)
* @return 完整的文件存储路径(物理路径)
*/
public String uploadFile(MultipartFile file, String targetDir) throws IOException {
// 1. 校验文件是否为空
if (file.isEmpty()) {
throw new IOException("上传文件不能为空");
}
// 2. 创建目标目录(若不存在)
createDirectory(targetDir);
// 3. 生成唯一文件名
String uniqueFileName = generateUniqueFileName(file.getOriginalFilename());
// 4. 拼接完整物理路径
String physicalPath = targetDir + File.separator + uniqueFileName;
// 5. 上传文件(将MultipartFile转换为本地文件)
file.transferTo(new File(physicalPath));
// 6. 返回物理路径
return physicalPath;
}
/**
* 获取图片访问URL(用于前端回显)
* @param uniqueFileName 唯一文件名
* @return 图片访问URL(如:http://localhost:8080/upload/images/xxx.jpg)
*/
public String getImageAccessUrl(String uniqueFileName) {
return imageAccessPath + uniqueFileName;
}
// 以下为getter方法,供外部获取路径
public String getExcelUploadPath() {
return excelUploadPath;
}
public String getCommonUploadPath() {
return commonUploadPath;
}
}
二、核心实战一:本地文件上传(通用版)
本地文件上传是基础,核心逻辑:接收前端传入的MultipartFile文件 → 校验文件合法性(大小、格式) → 生成唯一文件名 → 上传到指定本地目录 → 返回文件存储路径或访问URL。适用于所有类型文件(文档、压缩包等)。
2.1 接口设计(Controller)
提供通用文件上传接口,支持单个文件上传,可通过参数指定文件类型(用于区分存储目录):
import com.example.demo.util.FileUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* 通用文件上传控制器
*/
@RestController
@RequestMapping("/file")
public class FileUploadController {
@Autowired
private FileUtil fileUtil;
/**
* 本地文件上传(通用版)
* @param file 上传的文件
* @param fileType 文件类型(common:普通文件,excel:Excel文件,image:图片文件)
* @return 上传结果(存储路径、访问URL等)
*/
@PostMapping("/upload")
public ResponseEntity<Map<String, Object>> uploadFile(
@RequestParam("file") MultipartFile file,
@RequestParam("fileType") String fileType) {
Map<String, Object> result = new HashMap<>();
try {
// 1. 校验文件类型参数
String targetDir = getTargetDirByFileType(fileType);
// 2. 上传文件,获取物理存储路径
String physicalPath = fileUtil.uploadFile(file, targetDir);
// 3. 拼接返回结果
result.put("code", 200);
result.put("message", "文件上传成功");
result.put("physicalPath", physicalPath); // 本地物理路径
result.put("fileName", file.getOriginalFilename()); // 原始文件名
// 图片文件额外返回访问URL
if ("image".equals(fileType)) {
String uniqueFileName = physicalPath.substring(physicalPath.lastIndexOf(File.separator) + 1);
result.put("accessUrl", fileUtil.getImageAccessUrl(uniqueFileName));
}
return ResponseEntity.ok(result);
} catch (IOException e) {
result.put("code", 500);
result.put("message", "文件上传失败:" + e.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result);
}
}
/**
* 根据文件类型获取目标存储目录
*/
private String getTargetDirByFileType(String fileType) {
switch (fileType) {
case "excel":
return fileUtil.getExcelUploadPath();
case "image":
return fileUtil.getCommonUploadPath() + "images/";
default:
return fileUtil.getCommonUploadPath();
}
}
}
2.2 接口测试(Postman)
-
请求方式:POST,接口地址:http://localhost:8080/file/upload
-
请求参数:
-
file:选择要上传的文件(如文档、压缩包)
-
fileType:传入common(普通文件)
-
-
响应结果(成功):
{
"code": 200,
"message": "文件上传成功",
"physicalPath": "D:/springboot-file/upload/common/xxx.jpg",
"fileName": "test.jpg"
}
验证:打开配置的本地存储目录,可看到上传的文件(文件名已转为UUID格式,避免重复)。
三、核心实战二:图片上传与回显
图片上传是最常用的场景(如头像、商品图片),相比普通文件,核心多了「图片格式校验」「图片回显」两个关键点,可选做图片压缩(优化存储大小)。
3.1 图片上传优化(新增图片校验与压缩)
在通用工具类基础上,新增图片专属方法,校验图片格式(仅允许jpg、png、jpeg),并通过thumbnailator实现图片压缩:
// 在FileUtil类中新增以下方法
import net.coobird.thumbnailator.Thumbnails;
/**
* 校验图片格式(仅允许jpg、png、jpeg)
* @param originalFilename 原始文件名
* @throws IOException 格式不合法时抛出异常
*/
public void validateImageFormat(String originalFilename) throws IOException {
String suffix = FilenameUtils.getExtension(originalFilename).toLowerCase();
if (!"jpg".equals(suffix) && !"png".equals(suffix) && !"jpeg".equals(suffix)) {
throw new IOException("图片格式不合法,仅支持jpg、png、jpeg格式");
}
}
/**
* 图片上传(带格式校验+压缩)
* @param file 图片文件
* @param width 压缩后宽度(0表示不限制宽度,按比例缩放)
* @param height 压缩后高度(0表示不限制高度,按比例缩放)
* @return 图片存储路径+访问URL
*/
public Map<String, String> uploadImage(MultipartFile file, int width, int height) throws IOException {
// 1. 校验图片格式
validateImageFormat(file.getOriginalFilename());
// 2. 校验文件大小(可额外添加,如限制图片不超过5MB)
long fileSize = file.getSize();
if (fileSize > 5 * 1024 * 1024) {
throw new IOException("图片大小不能超过5MB");
}
// 3. 生成唯一文件名
String uniqueFileName = generateUniqueFileName(file.getOriginalFilename());
// 4. 目标存储目录(单独划分图片目录)
String imageDir = commonUploadPath + "images/";
createDirectory(imageDir);
// 5. 图片压缩并上传
String physicalPath = imageDir + File.separator + uniqueFileName;
Thumbnails.of(file.getInputStream())
.size(width, height) // 压缩尺寸,0表示按比例缩放
.outputQuality(0.8) // 压缩质量(0.0-1.0),0.8表示保留80%质量
.toFile(physicalPath);
// 6. 组装结果(存储路径+访问URL)
Map<String, String> result = new HashMap<>();
result.put("physicalPath", physicalPath);
result.put("accessUrl", getImageAccessUrl(uniqueFileName));
return result;
}
3.2 图片上传接口(Controller)
新增图片专属上传接口,支持压缩参数配置,方便前端根据需求调整图片尺寸:
// 在FileUploadController中新增接口
/**
* 图片上传(带格式校验+压缩)
* @param file 图片文件
* @param width 压缩后宽度(默认0,按比例缩放)
* @param height 压缩后高度(默认0,按比例缩放)
* @return 上传结果
*/
@PostMapping("/upload/image")
public ResponseEntity<Map<String, Object>> uploadImage(
@RequestParam("file") MultipartFile file,
@RequestParam(defaultValue = "0") int width,
@RequestParam(defaultValue = "0") int height) {
Map<String, Object> result = new HashMap<>();
try {
// 调用图片上传方法
Map<String, String> imageInfo = fileUtil.uploadImage(file, width, height);
result.put("code", 200);
result.put("message", "图片上传成功");
result.put("imageInfo", imageInfo);
return ResponseEntity.ok(result);
} catch (IOException e) {
result.put("code", 500);
result.put("message", "图片上传失败:" + e.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result);
}
}
3.3 图片回显实现
核心依赖前面application.yml中的静态资源配置,无需额外编写接口,直接通过返回的accessUrl即可访问图片。
-
上传图片后,获取响应中的accessUrl(如:/upload/images/xxx.jpg);
-
拼接完整访问地址:http://localhost:8080 + accessUrl(如:http://localhost:8080/upload/images/xxx.jpg);
-
在浏览器或前端页面直接访问该URL,即可回显图片。
注意:若回显失败,检查3点:① 静态资源配置是否正确(static-locations是否指向本地存储路径);② 图片物理路径是否正确生成;③ 访问URL是否拼接完整(端口、路径是否正确)。
四、核心实战三:Excel 文件上传解析(POI + EasyExcel)
Excel上传解析是小工具开发的核心(如数据导入),本文分别实现POI和EasyExcel两种方式,POI适合复杂Excel(合并单元格、公式),EasyExcel适合大数据量、简单Excel,按需选择。
先准备测试Excel:创建user.xlsx,表头为「用户名、手机号、角色」,填入几条测试数据。
4.1 基础准备:Excel 实体类(DTO)
定义与Excel表头对应的实体类,用于接收解析后的数据:
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
/**
* Excel解析实体类(与Excel表头对应)
* 注解说明:@ExcelProperty用于EasyExcel,value对应表头名称,index对应列索引
*/
@Data
public class ExcelUserDTO {
@ExcelProperty(value = "用户名", index = 0)
private String username;
@ExcelProperty(value = "手机号", index = 1)
private String phone;
@ExcelProperty(value = "角色", index = 2)
private String role;
}
4.2 方式一:POI 实现 Excel 上传解析
POI是Apache的开源组件,兼容性强,可处理复杂Excel,但内存占用较高,适合小数据量Excel解析。
4.2.1 POI 解析工具类
import com.example.demo.dto.ExcelUserDTO;
import org.apache.poi.ss.usermodel.*;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
/**
* POI Excel解析工具类
*/
@Component
public class PoiExcelUtil {
/**
* 解析Excel文件(.xlsx、.xls)
* @param file Excel文件
* @return 解析后的用户列表
*/
public List<ExcelUserDTO> parseExcel(MultipartFile file) throws IOException {
List<ExcelUserDTO> userList = new ArrayList<>();
// 1. 获取文件输入流
try (InputStream inputStream = file.getInputStream()) {
// 2. 根据文件后缀创建Workbook(.xlsx用XSSFWorkbook,.xls用HSSFWorkbook)
Workbook workbook = WorkbookFactory.create(inputStream);
// 3. 获取第一个工作表(默认读取第一个sheet)
Sheet sheet = workbook.getSheetAt(0);
if (sheet == null) {
throw new IOException("Excel文件中无工作表");
}
// 4. 跳过表头(第0行是表头,从第1行开始读取数据)
int rowNum = sheet.getLastRowNum(); // 最后一行的索引(从0开始)
for (int i = 1; i <= rowNum; i++) {
Row row = sheet.getRow(i);
if (row == null) {
continue; // 跳过空行
}
// 5. 读取每一列数据,封装到DTO
ExcelUserDTO userDTO = new ExcelUserDTO();
// 用户名(第0列)
Cell usernameCell = row.getCell(0);
userDTO.setUsername(getCellValue(usernameCell));
// 手机号(第1列)
Cell phoneCell = row.getCell(1);
userDTO.setPhone(getCellValue(phoneCell));
// 角色(第2列)
Cell roleCell = row.getCell(2);
userDTO.setRole(getCellValue(roleCell));
// 6. 添加到列表
userList.add(userDTO);
}
// 7. 关闭资源
workbook.close();
}
return userList;
}
/**
* 获取单元格的值(兼容不同单元格类型:字符串、数字等)
*/
private String getCellValue(Cell cell) {
if (cell == null) {
return "";
}
// 设置单元格类型为字符串,避免数字自动转为科学计数法
cell.setCellType(CellType.STRING);
return cell.getStringCellValue().trim();
}
}
4.2.2 POI 解析接口(Controller)
// 在FileUploadController中新增接口
@Autowired
private PoiExcelUtil poiExcelUtil;
/**
* POI 解析Excel文件
* @param file Excel文件(.xlsx、.xls)
* @return 解析结果
*/
@PostMapping("/upload/excel/poi")
public ResponseEntity<Map<String, Object>> parseExcelByPoi(@RequestParam("file") MultipartFile file) {
Map<String, Object> result = new HashMap<>();
try {
// 1. 校验文件格式(仅允许xlsx、xls)
String suffix = FilenameUtils.getExtension(file.getOriginalFilename()).toLowerCase();
if (!"xlsx".equals(suffix) && !"xls".equals(suffix)) {
result.put("code", 400);
result.put("message", "文件格式不合法,仅支持.xlsx、.xls格式");
return ResponseEntity.badRequest().body(result);
}
// 2. 上传Excel文件(先存储到本地,可选)
String physicalPath = fileUtil.uploadFile(file, fileUtil.getExcelUploadPath());
// 3. 解析Excel
List<ExcelUserDTO> userList = poiExcelUtil.parseExcel(file);
// 4. 组装结果(可后续将解析的数据存入数据库)
result.put("code", 200);
result.put("message", "Excel解析成功");
result.put("filePath", physicalPath);
result.put("dataCount", userList.size());
result.put("data", userList);
return ResponseEntity.ok(result);
} catch (IOException e) {
result.put("code", 500);
result.put("message", "Excel解析失败:" + e.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result);
}
}
4.3 方式二:EasyExcel 实现 Excel 上传解析
EasyExcel是阿里巴巴开源的Excel解析工具,内存占用极低(避免OOM),API简洁,适合大数据量Excel解析,推荐使用。
4.3.1 EasyExcel 监听器(核心)
EasyExcel采用监听器模式解析Excel,需自定义监听器,处理解析后的每一行数据:
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.example.demo.dto.ExcelUserDTO;
import lombok.Getter;
import java.util.ArrayList;
import java.util.List;
/**
* EasyExcel 解析监听器(监听每一行数据的解析)
*/
@Getter // 提供getter方法,获取解析后的列表
public class ExcelUserListener extends AnalysisEventListener<ExcelUserDTO> {
// 存储解析后的用户数据
private List<ExcelUserDTO> userList = new ArrayList<>();
/**
* 每解析一行数据,就会调用该方法
* @param data 解析后的一行数据(与ExcelUserDTO对应)
* @param context 解析上下文
*/
@Override
public void invoke(ExcelUserDTO data, AnalysisContext context) {
// 校验数据(可选,如非空校验)
if (data.getUsername() == null || data.getUsername().trim().isEmpty()) {
throw new RuntimeException("第" + (context.readRowHolder().getRowIndex() + 1) + "行,用户名为空");
}
// 将数据添加到列表
userList.add(data);
}
/**
* 解析完成后,调用该方法(可做后续处理,如存入数据库)
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
System.out.println("Excel解析完成,共解析" + userList.size() + "条数据");
}
}
4.3.2 EasyExcel 解析接口(Controller)
// 在FileUploadController中新增接口
import com.alibaba.excel.EasyExcel;
/**
* EasyExcel 解析Excel文件(推荐,轻量高效)
* @param file Excel文件(.xlsx、.xls)
* @return 解析结果
*/
@PostMapping("/upload/excel/easyexcel")
public ResponseEntity<Map<String, Object>> parseExcelByEasyExcel(@RequestParam("file") MultipartFile file) {
Map<String, Object> result = new HashMap<>();
try {
// 1. 校验文件格式
String suffix = FilenameUtils.getExtension(file.getOriginalFilename()).toLowerCase();
if (!"xlsx".equals(suffix) && !"xls".equals(suffix)) {
result.put("code", 400);
result.put("message", "文件格式不合法,仅支持.xlsx、.xls格式");
return ResponseEntity.badRequest().body(result);
}
// 2. 上传Excel文件(可选)
String physicalPath = fileUtil.uploadFile(file, fileUtil.getExcelUploadPath());
// 3. 初始化监听器
ExcelUserListener listener = new ExcelUserListener();
// 4. 解析Excel(无需创建Workbook,EasyExcel自动处理)
EasyExcel.read(file.getInputStream(), ExcelUserDTO.class, listener)
.sheet() // 读取第一个sheet
.headRowNumber(1) // 表头行数(1表示第0行是表头,从第1行开始读取数据)
.doRead();
// 5. 获取解析后的数据
List<ExcelUserDTO> userList = listener.getUserList();
// 6. 组装结果
result.put("code", 200);
result.put("message", "Excel解析成功");
result.put("filePath", physicalPath);
result.put("dataCount", userList.size());
result.put("data", userList);
return ResponseEntity.ok(result);
} catch (Exception e) {
result.put("code", 500);
result.put("message", "Excel解析失败:" + e.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result);
}
}
4.4 POI 与 EasyExcel 对比(选型建议)
| 对比维度 | POI | EasyExcel |
|---|---|---|
| 内存占用 | 较高,容易OOM(大数据量时) | 极低,基于Sax解析,无内存压力 |
| API复杂度 | 较复杂,需手动处理Workbook、Sheet、Row、Cell | 简洁,通过监听器+注解即可完成解析 |
| 复杂Excel支持 | 支持(合并单元格、公式、图表等) | 支持基础复杂场景,高级场景需额外处理 |
| 适用场景 | 小数据量、复杂Excel解析 | 大数据量、简单Excel解析(推荐日常开发) |
五、常见问题与解决方案
-
文件上传失败,提示“文件过大”?
解决方案:修改application.yml中spring.servlet.multipart.max-file-size和max-request-size的值,单位支持MB、KB,如10MB、50MB。 -
图片回显404?
解决方案:① 检查静态资源配置(static-locations是否正确指向本地存储路径,如file:D:/xxx/);② 确认图片物理路径是否正确生成,文件是否存在;③ 访问URL是否拼接完整(如端口是否正确)。 -
Excel解析时,数字自动转为科学计数法?
解决方案:POI中通过cell.setCellType(CellType.STRING)将单元格转为字符串类型;EasyExcel中在实体类字段添加@ExcelProperty(converter = StringConverter.class),自定义转换器。 -
EasyExcel解析时,表头与实体类不匹配?
解决方案:确保@ExcelProperty的value与Excel表头完全一致(大小写、空格都要匹配),或通过index指定列索引(更稳妥)。 -
文件上传路径中文乱码?
解决方案:存储路径尽量使用英文路径,避免中文;若必须使用中文,需在配置文件中对路径进行编码,或在代码中处理编码问题。
六、总结
本文承接纯接口开发的基础,完整实战了Spring Boot文件操作的核心场景——本地文件上传、图片上传与回显、Excel上传解析(POI+EasyExcel),覆盖小工具开发的核心需求,核心要点:
-
本地文件上传:核心是生成唯一文件名、创建存储目录、校验文件合法性,通用适配所有文件类型。
-
图片上传:额外增加格式校验、图片压缩,通过静态资源配置实现图片回显,贴合实际开发场景。
-
Excel解析:POI适合复杂场景,EasyExcel适合大数据量,按需选择,核心是将Excel数据映射为实体类,便于后续业务处理。
掌握本文内容后,可轻松实现图片上传、Excel导入等小工具核心功能,后续可进一步扩展:文件下载、文件删除、云存储(如阿里云OSS)集成等,让文件操作功能更完善,适配更多实际开发需求。
2595

被折叠的 条评论
为什么被折叠?



