图片上传的util
package com.ruoyi.web.controller.common.utils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
public class LocalUploadImageUtils{
/**
* 上传图片到本地服务器,文件名自定义
* @param file 图片文件
* @param fileName 自定义文件名
* @return 文件访问路径
*/
public static String uploadFile(MultipartFile file, String fileName) {
String finalPath = ConfigFileMessageUtils.IMAGE_ALL_DIR + fileName;
String url = "http://"
+ ConfigFileMessageUtils.LOCAL_IP+ ":"
+ ConfigFileMessageUtils.SERVER_PORT + "/"
+ ConfigFileMessageUtils.IMAGE_DIR_NAME + "/"
+ fileName;
boolean flag = upload(file, finalPath);
if (!flag) {
throw new RuntimeException("文件上传失败");
}
return url;
}
/**
* 为文件名添加前缀c
* @param fix 需添加的前缀
* @param fileName 文件名
* @return 新的文件名
*/
public static String addFixForFileName(String fix, String fileName) {
return fix + getFileSuffix(fileName);
}
/**
* 上传文件到服务器
* @param file 需要上传的文件
* @param finalPath 文件存放的服务器路径
* @return 上传成功返回true,失败返回false
*/
private static boolean upload(MultipartFile file, String finalPath){
File dest = new File(finalPath);
//判断文件父目录是否存在
if(!dest.getParentFile().exists()){
dest.getParentFile().mkdirs();
}
//上传文件到服务器,相当于将内存的文件输出到服务器,OutputStream,需要try....catch....
try {
//保存文件
//transferTo(dest)方法将上传文件写到服务器上指定的文件
file.transferTo(dest);
return true;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
}
private static String getNewFileNameByUuid(String fileName) {
return getUUID() + getFileSuffix(fileName);
}
private static String getUUID(){
return UUID.randomUUID().toString().replace("-", "") ;
}
private static String getFileSuffix(String fileName){
return fileName.substring(fileName.lastIndexOf("."));
}
}
/**
* 读取图片所需基本信息
*/
@Component
class ConfigFileMessageUtils implements InitializingBean {
@Value("${server.port}")
private String serverPort;
/**
* 本机IP地址
*/
public static String LOCAL_IP;
/**
* 本机服务器端口号
*/
public static String SERVER_PORT;
/**
* 保存图片目录名,默认resources/static下
*/
public static String IMAGE_DIR_NAME = "file";
/**
* 图片存放的全路径名
*/
public static String IMAGE_ALL_DIR;
/**
* 该方法在服务器加载时被调用
* @throws Exception
*/
@Override
public void afterPropertiesSet() throws Exception {
SERVER_PORT = this.serverPort;
LOCAL_IP = "localhost";
IMAGE_ALL_DIR = System.getProperty("user.dir") + "/src/main/resources/static/" + IMAGE_DIR_NAME + "/";
}
}
/**
* 释放static下保存文件的目录可被访问
*/
@Configuration
class ImageWebMvcConfigurerAdapter implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry){
//访问映射,请求放行处理
registry.addResourceHandler(""+ ConfigFileMessageUtils.IMAGE_DIR_NAME+"/**")
.addResourceLocations("file:"+ ConfigFileMessageUtils.IMAGE_ALL_DIR);
registry.addResourceHandler("/webjars/**")
.addResourceLocations(
"classpath:/META-INF/resources/webjars/");
}
}
代码解析
图片上传实现解析
这个代码实现了基于Spring框架的本地图片上传功能,主要包含三个部分:上传工具类、配置类和静态资源访问配置。下面我将详细解析其实现原理和工作流程。
1. 核心组件分析
1.1 LocalUploadImageUtils
(上传工具类)
这是图片上传的核心工具类,提供以下功能:
uploadFile
: 主上传方法,接收文件对象和自定义文件名upload
: 实际执行文件存储操作- 文件名处理工具方法:
addFixForFileName
: 为文件名添加前缀getNewFileNameByUuid
: 生成UUID文件名getFileSuffix
: 获取文件后缀名
1.2 ConfigFileMessageUtils
(配置类)
负责读取和存储上传相关的配置信息:
- 使用
@Value
注入服务器端口 - 定义静态常量存储配置信息
- 通过
InitializingBean
接口在初始化时设置静态变量
1.3 ImageWebMvcConfigurerAdapter
(资源访问配置)
配置静态资源访问规则,使上传的图片可以通过HTTP访问
2. 上传流程详解
2.1 上传步骤
- 接收文件:通过
MultipartFile
接收前端上传的文件 - 构建存储路径:
- 使用
ConfigFileMessageUtils.IMAGE_ALL_DIR
获取基础存储目录 - 拼接自定义文件名形成完整存储路径
- 使用
- 构建访问URL:
- 格式:
http://{IP}:{PORT}/{IMAGE_DIR_NAME}/{filename}
- 格式:
- 实际存储:
- 检查父目录是否存在,不存在则创建
- 使用
transferTo()
方法将文件写入目标位置
- 返回访问URL:供前端使用
2.2 关键代码解析
public static String uploadFile(MultipartFile file, String fileName) {
// 构建存储路径
String finalPath = ConfigFileMessageUtils.IMAGE_ALL_DIR + fileName;
// 构建访问URL
String url = "http://" + ConfigFileMessageUtils.LOCAL_IP + ":"
+ ConfigFileMessageUtils.SERVER_PORT + "/"
+ ConfigFileMessageUtils.IMAGE_DIR_NAME + "/"
+ fileName;
// 执行上传
boolean flag = upload(file, finalPath);
if (!flag) {
throw new RuntimeException("文件上传失败");
}
return url;
}
3. 静态资源访问机制
通过WebMvcConfigurer
配置静态资源映射:
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry){
// 映射上传目录到URL路径
registry.addResourceHandler(ConfigFileMessageUtils.IMAGE_DIR_NAME+"/**")
.addResourceLocations("file:"+ConfigFileMessageUtils.IMAGE_ALL_DIR);
}
这样配置后,存储在IMAGE_ALL_DIR
目录下的文件可以通过/file/文件名
的URL访问。
4. 代码特点与改进建议
4.1 优点
- 结构清晰,职责分离
- 支持自定义文件名
- 自动创建不存在的目录
- 提供完整的访问URL返回
图片上传的使用部分
@PostMapping("/uploadAvatar")
public ApiResult uploadAvatar(
@RequestParam("file") MultipartFile file,
@RequestParam("userId") Long userId
) {
try {
// 1. 生成唯一文件名(例如:UUID + 后缀)
String originalFilename = file.getOriginalFilename();
String fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));
String fileName = UUID.randomUUID().toString().replace("-", "") + fileExtension;
// 2. 上传文件到服务器(调用工具类)
String avatarUrl = LocalUploadImageUtils.uploadFile(file, fileName);
// 3. 更新用户头像路径
MyUser user = myUserService.selectMyUserByUserId(userId);
if (user == null) {
return new ApiResult<>(0, "用户不存在", null);
}
user.setAvatarUrl(avatarUrl);
myUserService.updateMyUser(user);
return new ApiResult<>(1, "头像上传成功", avatarUrl);
} catch (Exception e) {
return new ApiResult<>(0, "头像上传失败:" + e.getMessage(), null);
}
}
图片上传调用流程
图片上传与用户头像更新实现原理分析
这个uploadAvatar
方法结合了你之前提供的LocalUploadImageUtils
工具类,实现了完整的用户头像上传和更新流程。下面我将详细解析其工作原理和实现机制。
1. 整体流程
- 前端提交:上传文件(头像图片)和用户ID
- 后端处理:
- 生成唯一文件名
- 保存文件到服务器本地
- 更新数据库中的用户头像URL
- 返回结果:包含操作状态和头像访问URL
2. 核心代码解析
2.1 方法签名
@PostMapping("/uploadAvatar")
public ApiResult uploadAvatar(
@RequestParam("file") MultipartFile file, // 接收上传的文件
@RequestParam("userId") Long userId // 接收用户ID
)
- 使用
@PostMapping
处理HTTP POST请求 @RequestParam
接收表单数据中的文件和用户ID
2.2 文件名生成
String originalFilename = file.getOriginalFilename();
String fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));
String fileName = UUID.randomUUID().toString().replace("-", "") + fileExtension;
- 获取原始文件名
- 提取文件扩展名(如.jpg, .png)
- 使用UUID生成唯一文件名,避免重名冲突
2.3 文件上传
String avatarUrl = LocalUploadImageUtils.uploadFile(file, fileName);
调用你之前定义的LocalUploadImageUtils
工具类完成:
- 构建本地存储路径:
ConfigFileMessageUtils.IMAGE_ALL_DIR + fileName
- 确保目录存在
- 使用
transferTo()
保存文件 - 返回可访问的URL
2.4 数据库更新
MyUser user = myUserService.selectMyUserByUserId(userId);
user.setAvatarUrl(avatarUrl);
myUserService.updateMyUser(user);
- 根据用户ID查询用户
- 更新头像URL字段
- 保存到数据库
2.5 结果返回
return new ApiResult<>(1, "头像上传成功", avatarUrl);
返回统一格式的响应,包含:
- 状态码(1成功/0失败)
- 消息
- 数据(这里是头像URL)
3. 完整技术栈协作
前端(表单提交)
↓ (HTTP POST /uploadAvatar)
Spring MVC Controller
↓ (MultipartFile)
LocalUploadImageUtils (文件存储)
↓ (返回URL)
MyUserService (数据库更新)
↓
返回ApiResult给前端
4. 关键设计考虑
- 唯一文件名:使用UUID避免重名覆盖
- URL生成:工具类自动构建完整访问URL
- 事务完整性:先确保文件保存成功,再更新数据库
- 错误处理:try-catch捕获可能异常,返回友好错误信息
5. 潜在优化点
- 文件验证:添加对文件类型、大小的检查
- 图片处理:可集成缩略图生成
- 异步处理:大文件上传可改为异步方式
- 分布式存储:未来可扩展为云存储方案
- 安全控制:添加权限验证,防止越权修改
这个实现是一个典型而完整的Spring Boot文件上传应用场景,涵盖了从文件接收到存储再到数据库更新的完整流程,具有良好的可扩展性和实用性。