图片上传的util和使用
图片上传的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 blocke.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*/@Overridepublic 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 {@Overridepublic 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;// 构建访问URLString 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文件上传应用场景,涵盖了从文件接收到存储再到数据库更新的完整流程,具有良好的可扩展性和实用性。
相关文章:
图片上传的util和使用
图片上传的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.spri…...
2025年4月个人工作生活总结
本文为 2025年4月工作生活总结。 研发编码 一个项目的临时记录 自2月份领导让我牵头负责一个项目起,在本月算是有较多时间投入——但也是与之前的相比。 月初,清明节前一晚上,因某事务被叫上参加临时紧急远程会议,几方领导都在…...
利用Elixir中的原子特性 + 错误消息泄露 -- Atom Bomb
题目信息: This new atom bomb early warning system is quite strange… 题目使用 elixir 语言 一开始,我们会访问 /page.html <!DOCTYPE html> <!-- 设定文档语言为英语 --> <html lang"en"> <head><!-- 设定字符编码为UTF-8 --><…...
numpy pandas
视频链接 numpy numpy是基于一个矩阵的运算 矩阵的属性 import numpy as np# 把一个列表转换成矩阵的方法 array np.array([[1,2,3],[3,4,5]])# 打印矩阵 print(array)# 维度 print(number of dim:,array.ndim)# 行数和列数 print(shape:,array.shape)# 总共有多少个元素在…...
Amazon Redshift 使用场景解析与最佳实践
作为 AWS 云上数据仓库服务的核心成员,Amazon Redshift 凭借其高性能、可扩展性与经济性,正在成为越来越多企业实现数据驱动决策的首选方案。本文将解析 Redshift 的典型使用场景,并分享几项实用的落地最佳实践,帮助企业在数据仓库…...
STM32F446 RTC在VDD/VDDA关闭后失振问题的分析与解决
【原创】STM32F446 RTC在VDD/VDDA关闭后失振问题的分析与解决 作者: 思考的味道[你的ID] | weix_42368227 版权声明: 禁止未经授权转载 1. 问题描述 在某低功耗STM32F446项目中,采用以下供电方案: VDD:由DC-DC 3.3V提供(主电源…...
SSM框架(Spring + Spring MVC + MyBatis)整合配置的详细步骤
以下是 SSM框架(Spring Spring MVC MyBatis)整合配置的详细步骤,适用于 Maven 项目。 (一)、pom.xml中添加相关依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"ht…...

Elasticsearch 中的索引模板:如何使用可组合模板
作者:来自 Elastic Kofi Bartlett 探索可组合模板以及如何创建它们。 更多阅读: Elasticsearch:可组合的 Index templates - 7.8 版本之后 想获得 Elastic 认证吗?查看下一期 Elasticsearch Engineer 培训的时间! El…...
内存泄漏系列专题分析之七:高通相机CamX--Android通用ION(dmabuf)内存分配和释放原理
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:内存泄漏系列专题分析之六:高通camx 内存泄漏测试的未回收问题分析 这一篇我们开始讲:内存泄漏系列专题分析之七:高通相机CamX--Android通用ION(dmabuf)内存分配和释放原理 目录 一、背景 二、…...

【LeetCode 42】接雨水(单调栈、DP、双指针)
题面: 思路: 能接雨水的点,必然是比两边都低(小)的点。有两种思路,一种是直接计算每个点的最大贡献(也就是每个点在纵向上最多能接多少水),另一种就是计算每个点在横向上…...

【JS逆向基础】前端基础-HTML与CSS
1,flask框架 以下是一个使用flask框架写成的serve程序 # noinspection PyUnresolvedReferences #Flash框架的基本内容from flask import Flask app Flask(__name__)app.route(/index) def index():return "hello index"app.route(/login) def login():re…...
什么是HTML、CSS 和 JavaScript?
HTML、CSS 和 JavaScript 是构建网页的三大核心技术,它们分工明确又紧密协作。接下来我将分别介绍三者的定义、功能,并阐述它们如何共同构成网页,最后推荐学习资源。 一、HTML:网页的骨架与内容基础 HTML(HyperText …...

手机网页提示ip被拉黑名单什么意思?怎么办
当您使用手机浏览网页时,突然看到“您的IP地址已被列入黑名单”的提示,是否感到困惑和不安?这种情况在现代网络生活中并不罕见,但确实会给用户带来诸多不便。本文将详细解释IP被拉黑的含义、常见原因,并提供一系列实…...

CCF编程能力等级认证 一级 第一次课
介绍 CCF 编程能力等级认证(GESP)为青少年计算机和编程学习者提供学业能力验证的规则和平台,由中国计算机学会发起并主办。 每年考试分四次,时间是每年的3月、6月、9月、12月,以当年每期公布的时间为准。 GESP适用年…...

SpringBoot 讯飞星火AI WebFlux流式接口返回 异步返回 对接AI大模型 人工智能接口返回
介绍 用于构建基于 WebFlux 的响应式 Web 应用程序。集成了 Spring WebFlux 模块,支持响应式编程模型,构建非阻塞、异步的 Web 应用。WebFlux 使用了非阻塞的异步模型,能够更好地处理高并发请求。适合需要实时数据推送的应用场景。 WebClie…...

Python爬虫中time.sleep()与动态加载的配合使用
一、动态加载网页的挑战 动态加载网页是指网页的内容并非一次性加载完成,而是通过JavaScript等技术在用户交互或页面加载过程中逐步加载。这种设计虽然提升了用户体验,但对于爬虫来说,却增加了抓取的难度。传统的爬虫方法,如简单…...
学习Cesium Entities
🌐 Cesium中的Entities系统趣味学习 📊 Entities系统架构流程图 #mermaid-svg-Lkue5O3gYOkEVSbD {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-Lkue5O3gYOkEVSbD .error-icon{fill:#552222;}#mermaid-svg-Lku…...
如何减少锁竞争并细化锁粒度以提高 Rust 多线程程序的性能?
在并发编程中,锁(Lock)是一种常用的同步机制,用于保护共享数据免受多个线程同时访问造成的竞态条件(Race Condition)。然而,不合理的锁使用会导致严重的性能瓶颈,特别是在高并发场景…...
Logback官方文档翻译章节目录
Logback官方文档翻译章节目录 第一章 Logback简介 第二章 Logback的架构(一) Logback的架构(二) Logback的架构(三) 持续更新中…...

AtCoder Beginner Contest 404 A-E 题解
还是ABC好打~比ARC好打多了( 题解部分 A - Not Found 给定你一个长度最大25的字符串,任意输出一个未出现过的小写字母 签到题,map或者数组下标查询一下就好 #include<bits/stdc.h>using namespace std;#define int long long #def…...

【mysql】常用命令
一 系统mysql用户密码查询 1、在工程目录如/usr/local/httpd/下的*.php中查找类似有db.inf的文件 以php为例。 2、在代码文件中确认有数据库连接的的功能实现 例如: $dbconf parse_ini_file(/usr/local/httpd/conf/db.inf); $link mysql_connect($dbconf[d…...

macOS Arduino IDE离线安装ESP8266支持包
其实吧,本来用platformio也是可以的,不过有时候用Arduino IDE可能更快一些,因为以前一直是Arduino.app和Arduino IDE.app共存了一段时间,后来下决心删掉Arduino.app并升级到最新的Arduino IDE.app。删除了旧的支持板级支持包之后就…...

网络靶场基础知识
一、网络靶场的核心概念 网络靶场(Cyber Range)是一种基于虚拟化和仿真技术的网络安全训练与测试平台,通过模拟真实网络环境和业务场景,为攻防演练、漏洞验证、安全测试和人才培养提供安全可控的实验空间。其核心目标是通过“虚实…...
基于Partial Cross Entropy的弱监督语义分割实战指南
一、问题背景:弱监督学习的挑战 在计算机视觉领域,语义分割任务面临最大的挑战之一是**标注成本**。以Cityscapes数据集为例,单张图像的像素级标注需要约90分钟人工操作。这催生了弱监督学习(Weakly Supervised Learning)的研究方向,其中partial cross entropy loss(部…...
【算法基础】选择排序算法 - JAVA
一、算法基础 1.1 什么是选择排序 选择排序是一种简单直观的排序算法,它的工作原理是:首先在未排序序列中找到最小(或最大)元素,存放到排序序列的起始位置,然后再从剩余未排序元素中继续寻找最小…...
电商平台的流量秘密:代理IP在用户行为分析中的角色
在电商江湖中,流量是氧气,用户行为数据是DNA。当你在电商平台点击商品、加入购物车时,背后有一套精密的系统正在分析你的每个动作。而在这套系统的运作中,代理IP正扮演着"隐形推手"的角色——它既是数据采集的"隐身…...
批量清洗与修改 YOLO 标签:删除与替换指定类别
在使用 YOLO 格式的数据进行训练或部署前,常常需要对标签文件进行清洗或修改。本文整理了两种常见场景的 Python 脚本:删除指定类别 和 修改某类为其他类,并支持自动打印检测到该类别的文件名,帮助你快速定位问题数据。 …...

Python项目源码57:数据格式转换工具1.0(csv+json+excel+sqlite3)
1.智能路径处理:自动识别并修正文件扩展名,根据转换类型自动建议目标路径,实时路径格式验证,自动补全缺失的文件扩展名。 2.增强型预览功能:使用pandastable库实现表格预览,第三方模块自己安装一下&#x…...
TypeScript 中,属性修饰符
在 TypeScript 中,属性修饰符(Property Modifiers)是用于修饰类的属性或方法的关键字,它们可以改变属性或方法的行为和访问权限。TypeScript 提供了三种主要的属性修饰符:public、private 和 protected。此外ÿ…...

雷赛伺服电机
ACM0经济 编码器17位: ACM1基本 编码器23位磁编, ACM2通用 编码器24位光电, 插头定义:...