图片上传的util和使用

news2025/5/9 12:46:23

图片上传的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 上传步骤

  1. 接收文件:通过MultipartFile接收前端上传的文件
  2. 构建存储路径
    • 使用ConfigFileMessageUtils.IMAGE_ALL_DIR获取基础存储目录
    • 拼接自定义文件名形成完整存储路径
  3. 构建访问URL
    • 格式:http://{IP}:{PORT}/{IMAGE_DIR_NAME}/{filename}
  4. 实际存储
    • 检查父目录是否存在,不存在则创建
    • 使用transferTo()方法将文件写入目标位置
  5. 返回访问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. 整体流程

  1. 前端提交:上传文件(头像图片)和用户ID
  2. 后端处理
    • 生成唯一文件名
    • 保存文件到服务器本地
    • 更新数据库中的用户头像URL
  3. 返回结果:包含操作状态和头像访问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工具类完成:

  1. 构建本地存储路径:ConfigFileMessageUtils.IMAGE_ALL_DIR + fileName
  2. 确保目录存在
  3. 使用transferTo()保存文件
  4. 返回可访问的URL

2.4 数据库更新

MyUser user = myUserService.selectMyUserByUserId(userId);
user.setAvatarUrl(avatarUrl);
myUserService.updateMyUser(user);
  1. 根据用户ID查询用户
  2. 更新头像URL字段
  3. 保存到数据库

2.5 结果返回

return new ApiResult<>(1, "头像上传成功", avatarUrl);

返回统一格式的响应,包含:

  • 状态码(1成功/0失败)
  • 消息
  • 数据(这里是头像URL)

3. 完整技术栈协作

前端(表单提交)
  ↓ (HTTP POST /uploadAvatar)
Spring MVC Controller
  ↓ (MultipartFile)
LocalUploadImageUtils (文件存储)
  ↓ (返回URL)
MyUserService (数据库更新)
  ↓ 
返回ApiResult给前端

4. 关键设计考虑

  1. 唯一文件名:使用UUID避免重名覆盖
  2. URL生成:工具类自动构建完整访问URL
  3. 事务完整性:先确保文件保存成功,再更新数据库
  4. 错误处理:try-catch捕获可能异常,返回友好错误信息

5. 潜在优化点

  1. 文件验证:添加对文件类型、大小的检查
  2. 图片处理:可集成缩略图生成
  3. 异步处理:大文件上传可改为异步方式
  4. 分布式存储:未来可扩展为云存储方案
  5. 安全控制:添加权限验证,防止越权修改

这个实现是一个典型而完整的Spring Boot文件上传应用场景,涵盖了从文件接收到存储再到数据库更新的完整流程,具有良好的可扩展性和实用性。

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

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

相关文章

Elasticsearch 中的索引模板:如何使用可组合模板

作者&#xff1a;来自 Elastic Kofi Bartlett 探索可组合模板以及如何创建它们。 更多阅读&#xff1a; Elasticsearch&#xff1a;可组合的 Index templates - 7.8 版本之后 想获得 Elastic 认证吗&#xff1f;查看下一期 Elasticsearch Engineer 培训的时间&#xff01; El…

【LeetCode 42】接雨水(单调栈、DP、双指针)

题面&#xff1a; 思路&#xff1a; 能接雨水的点&#xff0c;必然是比两边都低&#xff08;小&#xff09;的点。有两种思路&#xff0c;一种是直接计算每个点的最大贡献&#xff08;也就是每个点在纵向上最多能接多少水&#xff09;&#xff0c;另一种就是计算每个点在横向上…

【JS逆向基础】前端基础-HTML与CSS

1&#xff0c;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…

手机网页提示ip被拉黑名单什么意思?怎么办

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

CCF编程能力等级认证 一级 第一次课

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

SpringBoot 讯飞星火AI WebFlux流式接口返回 异步返回 对接AI大模型 人工智能接口返回

介绍 用于构建基于 WebFlux 的响应式 Web 应用程序。集成了 Spring WebFlux 模块&#xff0c;支持响应式编程模型&#xff0c;构建非阻塞、异步的 Web 应用。WebFlux 使用了非阻塞的异步模型&#xff0c;能够更好地处理高并发请求。适合需要实时数据推送的应用场景。 WebClie…

Python爬虫中time.sleep()与动态加载的配合使用

一、动态加载网页的挑战 动态加载网页是指网页的内容并非一次性加载完成&#xff0c;而是通过JavaScript等技术在用户交互或页面加载过程中逐步加载。这种设计虽然提升了用户体验&#xff0c;但对于爬虫来说&#xff0c;却增加了抓取的难度。传统的爬虫方法&#xff0c;如简单…

AtCoder Beginner Contest 404 A-E 题解

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

【mysql】常用命令

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

macOS Arduino IDE离线安装ESP8266支持包

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

网络靶场基础知识

一、网络靶场的核心概念 网络靶场&#xff08;Cyber Range&#xff09;是一种基于虚拟化和仿真技术的网络安全训练与测试平台&#xff0c;通过模拟真实网络环境和业务场景&#xff0c;为攻防演练、漏洞验证、安全测试和人才培养提供安全可控的实验空间。其核心目标是通过“虚实…

Python项目源码57:数据格式转换工具1.0(csv+json+excel+sqlite3)

1.智能路径处理&#xff1a;自动识别并修正文件扩展名&#xff0c;根据转换类型自动建议目标路径&#xff0c;实时路径格式验证&#xff0c;自动补全缺失的文件扩展名。 2.增强型预览功能&#xff1a;使用pandastable库实现表格预览&#xff0c;第三方模块自己安装一下&#x…

雷赛伺服电机

ACM0经济 编码器17位&#xff1a; ACM1基本 编码器23位磁编&#xff0c; ACM2通用 编码器24位光电&#xff0c; 插头定义&#xff1a;

【deepseek教学应用】001:deepseek如何撰写教案并自动实现word排版

本文讲述利用deepseek如何撰写教案并自动实现word高效完美排版。 文章目录 一、访问deepseek官网二、输入教案关键词三、格式转换四、word进一步排版 一、访问deepseek官网 官网&#xff1a;https://www.deepseek.com/ 进入主页后&#xff0c;点击【开始对话】&#xff0c;如…

CH32V208GBU6沁恒绑定配对获取静态地址

从事嵌入式单片机的工作算是符合我个人兴趣爱好的,当面对一个新的芯片我即想把芯片尽快搞懂完成项目赚钱,也想着能够把自己遇到的坑和注意事项记录下来,即方便自己后面查阅也可以分享给大家,这是一种冲动,但是这个或许并不是原厂希望的,尽管这样有可能会牺牲一些时间也有哪天原…

RT Thread Studio创建软件和硬件RTC工程

MCU型号&#xff1a;STM32F103RET6 一.配置软件模拟RTC 1.生成一个带串口输出的工程文件&#xff0c;新建RT-Thread项目工程文件。 2.查看电路图中的串口输出管脚&#xff0c;根据STMCubeMx软件可知此串口为USART1&#xff0c;选择芯片型号为STM32F103RET6&#xff0c;控制台…

苍穹外卖心得体会

1 登录认证 技术点&#xff1a;JWT令牌技术&#xff08;JSON Web Token&#xff09; JWT&#xff08;JSON Web Token&#xff09;是一种令牌技术&#xff0c;主要由三部分组成&#xff1a;Header头部、Payload载荷和Signature签名。Header头部存储令牌的类型&#xff08;如JW…

Zcanpro搭配USBCANFD-200U在新能源汽车研发测试中的应用指南(周立功/致远电子)

——国产工具链的崛起与智能汽车测试新范式 引言&#xff1a;新能源汽车测试的国产化突围 随着新能源汽车智能化、网联化程度的提升&#xff0c;研发测试面临三大核心挑战&#xff1a;多协议融合&#xff08;CAN FD/LIN/以太网&#xff09;、高实时性数据交互需求、复杂工况下…

青少年抑郁症患者亚群结构和功能连接耦合的重构

目录 1 研究背景及目的 2 研究方法 2.1 数据来源与参与者 2.1.1 MDD患者&#xff1a; 2.1.2 健康对照组&#xff1a; 2.2 神经影像分析流程 2.2.1 图像采集与预处理&#xff1a; 2.2.2 网络构建&#xff1a; 2.2.3 区域结构-功能耦合&#xff08;SC-FC耦合&#xff09…

SQL手工注入(DVWA)

手工SQL注入攻击的标准思路 Low等级 &#xff08;1&#xff09;判断是否存在注入 &#xff08;2&#xff09;猜解字段个数 &#xff08;3&#xff09;确定字段顺序 &#xff08;4&#xff09;获取当前数据库 &#xff08;5&#xff09;获取当前数据库中的表 &#xff08…