当前位置: 首页 > news >正文

JavaWeb合集23-文件上传

二十三 、 文件上传

实现效果:用户点击上传按钮、选择上传的头像,确定自动上传,将上传的文件保存到指定的目录中,并重新命名,生成访问链接,返回给前端进行回显。

1、前端实现

vue3+AntDesignVue实现

<template><!--图片回显--><a-avatar :size="100"><template #icon><img :src="userStore.userInfo.avatar+'?' + new Date().getTime()" alt=""></template></a-avatar><!--图片上传按钮 --><!--showUploadList=fales 不显示上传列表;:multiple="false" 只上传1个;accept=".png,.jpg" 限制文件格式--><a-upload name="file":file-list="fileList":showUploadList="false":beforeUpload="beforeUpload" :onChange="handleChange" :multiple="false"  accept=".png,.jpg"><a-button class="mt-4">上传头像</a-button></a-upload></template><script setup lang="ts">
import type { UnwrapRef } from 'vue';
import { updateUserAvatarApi } from '~/api/file/file.ts';const { t } = useI18n()
//文件列表
const fileList = ref([]);//
async function beforeUpload(file){//文件类型,限制,可以不用写,因为,在accept=".png,.jpg" 已经限制了
var fileName = file.name.substring(file.name.lastIndexOf('.') + 1)
if (fileName!='png' && fileName!='jpg') {message.error('文件类型必须是png或jpg!')
return false
}//文件大小(3M=3*1024KB*1024字节)
var fileSize=file.size;
if(fileSize > 3*1024*1024){message.error("图片大小不能大于3M");return false
}try {  const formData = new FormData(); formData.append('file', file); // 将文件添加到 FormData 对象中  // 假设updateUserAvatarApi返回的是一个Promise,且解析为包含fileUrl的对象  const response = await updateUserAvatarApi(formData);  if(response.data.code==1){fileList.value=[];  //清空文件列表(没用因为在beforeUpload中,我直接showUploadList="false"不显示列表)userStore.userInfo.avatar=response.data.data;message.success('头像上传成功');}else{message.error('头像上传失败,请重试');  }} catch (error) {  // 处理上传失败的情况  message.error(error);  }  // 返回false以阻止<a-upload>的默认上传行为  return false;  }// 处理文件上传或移除后的逻辑  
function handleChange(info) {  // info.fileList 是更新后的文件列表  // 但由于限制了multiple为false,所以这里fileList应该始终只有一个文件或为空  fileList.value = info.fileList.slice(-1);  
}  </script>

请求函数

// 后面的方法是用户自己头像
export function updateUserAvatarApi(param: any) {return usePost<FileUrl>('/upload/uploadUserAvater', param, {// 设置为false的时候不会携带tokentoken: true,// 开发模式下使用自定义的接口customDev: true,// 是否开启全局请求loadingloading: false,// 设置请求头headers: {'Content-Type': 'multipart/form-data'}})}export interface FileUrl {data: string}

2、后端实现

配置拦截器的静态资源映射,方便对上传后的文件进行访问

/*** 配置拦截器的静态资源映射*/
@Slf4j
@Configuration
public class ResourConfigure implements WebMvcConfigurer {// 静态资源映射@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {/*** 资源映射路径* addResourceHandler:访问映射路径* addResourceLocations:资源绝对路径*/String osName=System.getProperty("os.name");String fileUploadResources="/static/**";String win="win";if(osName.toLowerCase().startsWith(win)){ApplicationHome applicationHome=new ApplicationHome(this.getClass());String pre="file:"+applicationHome.getDir().getParentFile().getParentFile()+ "\\src\\main\\resources\\static\\";registry.addResourceHandler(fileUploadResources).addResourceLocations(pre);}else {ApplicationHome applicationHome=new ApplicationHome(this.getClass());String pre="file:"+applicationHome.getDir().getParentFile().getParentFile()+ "/src/main/resources/static/";registry.addResourceHandler(fileUploadResources).addResourceLocations(pre);}}}

写相关配置,在application.properties中,方便生成访问链接

#根据自己的需求进行修改即可
#端口号
server.port=8080   
#服务地址
server.address=localhost  
#访问路径
server.servlet.context-path=/    
#限制单个文件的上传大小
spring.servlet.multipart.max-file-size=5MB
#限制整个请求的最大大小
spring.servlet.multipart.max-request-size=5MB

创建文件上传工具类,方便对文件上传进行操作。

在此之前,确保这个目录的存在:(\src\main\resources\static\)可根据自己需求进行修改,在工具类中

/*** 文件上传工具类*/
@Component
public class FileUpload {@Value("${server.servlet.context-path}")private String contextPath;@Value("${server.port}")private String serverPort;@Value("${server.address}")private String serverAddress;@Autowiredprivate ServletContext servletContext;public String uploadFile(MultipartFile file, String folder) {// 获取图片的原始名字String originalFilename = file.getOriginalFilename();if (originalFilename == null || originalFilename.isEmpty()) {throw new IllegalArgumentException("文件名不能为空");}// 获取文件的后缀和新文件名String ext = "." + originalFilename.substring(originalFilename.lastIndexOf('.') + 1);String uuid = UUID.randomUUID().toString().replace("-", "");String fileName = uuid + ext;// 构建目标文件路径String pre = getResourcePath(folder);String filePath = pre + fileName;// 上传图片try {file.transferTo(new File(filePath));// 返回访问链接return getAccessPath(folder, fileName);} catch (IOException e) {e.printStackTrace();}return null;}public String uploadFile(MultipartFile file, String folder, String fileName) {// 获取图片的原始名字String originalFilename = file.getOriginalFilename();if (originalFilename == null || originalFilename.isEmpty()) {throw new IllegalArgumentException("文件名不能为空");}// 获取文件的后缀和新文件名String ext = "." + originalFilename.substring(originalFilename.lastIndexOf('.') + 1);fileName = fileName + ext;// 构建目标文件路径String pre = getResourcePath(folder);String filePath = pre + fileName;// 上传图片try {file.transferTo(new File(filePath));// 返回访问链接return getAccessPath(folder, fileName);} catch (Exception e) {e.printStackTrace();}return null;}//获取上传路径private String getResourcePath(String folder) {// 获取操作系统的名称String osName = System.getProperty("os.name");String win = "win";// 获取项目的根目录String projectRoot = System.getProperty("user.dir");// 根据操作系统生成正确的路径String staticPath;if (osName.toLowerCase().startsWith(win)) {//windos系统staticPath = projectRoot + "\\src\\main\\resources\\static\\" + folder + "\\";} else {//Linux系统staticPath = projectRoot + "/src/main/resources/static/" + folder + "/";}// 如果目录不存在,就创建目录File dir = new File(staticPath);if (!dir.exists()) {dir.mkdirs();}return staticPath;}//构建访问路径private String getAccessPath(String folder, String fileName) {// 构建访问路径return "http://" + serverAddress + ":" + serverPort + contextPath + "static/" + folder + "/" + fileName;}
}

可以设置一个常量类,来指定上传到的目录

public class FileUploadFolder {public static final String USER_AVATER_FOLDER = "user_avatar";public static final String  ACTIVITY_FOLDER = "activity";
}

后端接口编写:Controller层,根据自己的项目来即可

@Tag(name="文件上传接口")
@RestController
@RequestMapping("/upload")
@Slf4j
public class UploadController {@Autowiredprivate UserService userService;/*** 修改用户头像* @param file* @return*/@Operation(summary = "修改用户头像")@PostMapping("/uploadUserAvater")public ResponseResult uploadUserAvater(@RequestParam("file") MultipartFile file){if(file.isEmpty()){return ResponseResult.error("头像为空,请重新选择");}String imgUrl = userService.uploadUserAvater(file);if(imgUrl==null){return ResponseResult.error("头像上传失败");}return ResponseResult.success(imgUrl);}}

Service层:根据自己的项目来即可

@Slf4j
@Service
@Transactional
public class UserServiceImpl implements UserService {//根据自己的项目来,注入对应的Bean@Autowiredprivate final UserMapper userMapper;//注入写好的工具类@Autowiredprivate FileUpload fileUpload;/*** 修改用户头像* @param file* @return*/@Overridepublic String uploadUserAvater(MultipartFile file) {// 获取用户获取用户信息(根据自己的项目来,获取用户ID,来查询用户修改头像链接)Long uid = Long.parseLong(StpUtil.getLoginId().toString());UserInfo userInfo = userMapper.getUserById(uid);// 调用文件上传工具类,传入:文件,保存到的文件夹,文件名//设置文件名是为了替换旧的头像文件String imgUrl= fileUpload.uploadFile(file, FileUploadFolder.USER_AVATER_FOLDER,userInfo.getUsername());if(imgUrl!=null) {userInfo.setAvatar(imgUrl);userMapper.updateById(userInfo);log.info("头像上传成功:" + imgUrl);//返回生成的链接return imgUrl;}return null;}}

3、测试与效果

上传后的图片

在这里插入图片描述

生成的访问链接,存入到数据库的样子

在这里插入图片描述

相关文章:

JavaWeb合集23-文件上传

二十三 、 文件上传 实现效果&#xff1a;用户点击上传按钮、选择上传的头像&#xff0c;确定自动上传&#xff0c;将上传的文件保存到指定的目录中&#xff0c;并重新命名&#xff0c;生成访问链接&#xff0c;返回给前端进行回显。 1、前端实现 vue3AntDesignVue实现 <tem…...

当AI遇上时尚:未来的衣橱会由机器人来打理吗?

内容概要 在当今这个快速发展的时代&#xff0c;人工智能与时尚的结合正在逐渐改写我们对衣橱管理的认知。传统的衣橱管理常常面临着空间不足、穿搭单调及库存过多等挑战&#xff0c;许多人在挑选服饰时难以做出决策。然而&#xff0c;随着技术的进步&#xff0c;智能推荐和自…...

【初阶数据结构篇】二叉树OJ题

文章目录 须知 &#x1f4ac; 欢迎讨论&#xff1a;如果你在学习过程中有任何问题或想法&#xff0c;欢迎在评论区留言&#xff0c;我们一起交流学习。你的支持是我继续创作的动力&#xff01; &#x1f44d; 点赞、收藏与分享&#xff1a;觉得这篇文章对你有帮助吗&#xff1…...

Windows系统中Oracle VM VirtualBox的安装

一.背景 公司安排了师带徒&#xff0c;环境搭建问题一直是初级程序员头疼的事情&#xff0c;我记录一下这些基础的内容&#xff0c;方便初学者。大部分开发者的机器还是windows系统&#xff0c;所以写了怎么安装。 二.版本信息及 操作系统&#xff1a;windows11 家庭版…...

go语言使用总结(持续更新)

整理后的内容如下&#xff1a; 1. 先了解函数签名&#xff0c;再了解传入参数以及调用 函数签名是函数的声明部分&#xff0c;包括函数名、参数列表和返回值列表。理解函数签名是理解函数行为的第一步&#xff0c;尤其是在了解参数类型、参数数量和返回值类型等方面。通过了解…...

如何在Android中自定义property

在Android中创建自定义的属性&#xff08;Android property&#xff09;通常用于调试、性能调优或传递应用和系统之间的信息。 以下是如何在Android中创建和使用自定义属性的步骤&#xff1a; 1. 定义属性 在Android中&#xff0c;属性是以“属性名称属性值”形式定义的键值对…...

机器学习5_支持向量机_原问题和对偶问题——MOOC

目录 原问题与对偶问题的定义 定义该原问题的对偶问题如下 在定义了函数 的基础上&#xff0c;对偶问题如下&#xff1a; 综合原问题和对偶问题的定义得到&#xff1a; 定理一 对偶差距&#xff08;Duality Gap&#xff09; 强对偶定理&#xff08;Strong Duality Theo…...

索引的细节

目录 什么是线性 搜索算法&#xff1f; 算法&#xff1a;二进制搜索算法 二进制搜索如何工作&#xff1f; 什么是二叉排序树&#xff1f; 构建二叉排序树 什么是AVL树&#xff1f; AVL树的性能分析 什么是线性 搜索算法&#xff1f; 线性搜索是一种非常简单的搜索算法。在…...

LeetCode 540.有序数组中的单一元素

思路一&#xff1a;hash&#xff0c;键存入元素&#xff0c;值存入次数&#xff0c;然后遍历&#xff0c;不是最优解 思路二&#xff1a;二分查找 假设数组为 [1, 1, 2, 2, 3, 4, 4]&#xff0c;其中唯一出现一次的元素是 3。在一个有序数组中&#xff0c;如果没有唯一的元素&…...

【图文】【DIY便签】如何自行编译OPENCV使用动态库

1 去官网下载安装包和源码 下面红色圈中的是源码&#xff0c;绿色圈中的是安装包&#xff1a; 2 配置工具链 安装过程不说了&#xff0c;教程到处都是。编译的话使用CMAKE&#xff0c;配置如下&#xff1a; 上面两个路径分别是&#xff1a; 源码目录编译生成的文件放置的位…...

WordPress文章自动提交Bing搜索引擎:PHP推送脚本教程

随着网站SEO优化的重要性日益增加,将新发布的内容快速提交到搜索引擎显得尤为重要。尤其对于Bing站长平台,自动化推送能让Bing尽快发现和索引我们网站的新内容。本文将详细介绍如何通过PHP脚本自动推送WordPress当天发布的文章至Bing站长平台,确保新文章被Bing及时收录。 前…...

C++题目分享

嗨嗨嗨&#xff0c;我又来更新这个系列了&#xff0c;很久没更新了。让我们看一看有那些有趣的题目&#xff1a; 题目一&#xff1a; 1.以单链表作为存储结构&#xff0c;实现线性表的就地逆置&#xff08;提示&#xff0c;就地逆置&#xff1a;在不使用额外的数据结构或空间…...

【Spring 框架】初识 Spring

文章目录 前言1. 什么是 Spring2. 什么是 Maven3. 第一个 SpringBoot 项目4. 项目讲解结语 前言 在前面我们一起学习了 JavaSE 的基础知识&#xff0c;随着学习的深入&#xff0c;我们也将逐步介绍 JavaEE 的内容&#xff0c;像 Spring 框架&#xff0c;Mybatis 等等。在本篇博…...

链表(Linkedlist)

序言 我们都了解链表是一种数据的存储结构&#xff0c;在Java使用中逻辑与c&#xff0c;c语言数据结构别无二致&#xff0c;但主要由于Java中不存在指针的说法&#xff0c;从而导致在实现过程中的代码不同&#xff0c;所以在学习的过程中我们无需过于担心&#xff0c;逻辑都是…...

信息安全工程师(79)网络安全测评概况

一、定义与目的 网络安全测评是指参照一定的标准规范要求&#xff0c;通过一系列的技术、管理方法&#xff0c;获取评估对象的网络安全状况信息&#xff0c;并对其给出相应的网络安全情况综合判定。其对象主要为信息系统的组成要素或信息系统自身。网络安全测评的目的是为了提高…...

保研考研机试攻略:python笔记(3)

&#x1f428;&#x1f428;&#x1f428;11sort 与 sorted 区别 sort 是应用在 list 上的方法&#xff0c;sorted 可以对所有可迭代的对象进行排序操作。 list 的 sort 方法返回的是对已经存在的列表进行操作&#xff0c; 无返回值&#xff0c;而内建函数 sorted 方法返回的…...

刘卫国MATLAB程序设计与应用课后答案PDF第三版

刘卫国《MATLAB程序设计与应用》&#xff08;第三版&#xff09;是对普通高等教育“十一五”国家级规划教材《MATLAB程序设计与应用》(第二版)的一次全面修订。全书总体保持第二版原有体系结构&#xff0c;但根据技术发展和应用的需要扩充了许多新内容。全书强调数学方法、算法…...

【鉴权】Web 会话管理:Cookie、Session 和 Token 深度对比

目录 引言一、Cookie二、Session三、Token (JWT)四、总结对比五、Token、Session 和 Cookie 的选择总结 引言 在现代 Web 开发中&#xff0c;Cookie、Session 和 Token 都是用于用户身份验证和状态管理的常见技术。每种技术有其特定的应用场景和优缺点&#xff0c;理解它们之间…...

ArkTS--应用状态

应用状态 应用状态相关的内容需要使用模拟器或真机调试&#xff0c;在API 11开始也支持preview 1.LocalStorage LocalStorage是页面级的UI状态存储&#xff0c;通过Entry装饰器接收参数可以在页面内共享数据 1.1 页面内共享数据 import {MyUser} from ../model/MyUser //用户对…...

yolov8涨点系列之引入CBAM注意力机制

文章目录 YOLOv8 中添加注意力机制 CBAM 具有多方面的好处特征增强与选择通道注意力方面空间注意力方面 提高模型性能计算效率优化&#xff1a; yolov8增加CBAM具体步骤CBAM代码(1)在__init.pyconv.py文件的__all__内添加‘CBAM’(2)conv.py文件复制粘贴CBAM代码(3)修改task.py…...

大数据学习栈记——Neo4j的安装与使用

本文介绍图数据库Neofj的安装与使用&#xff0c;操作系统&#xff1a;Ubuntu24.04&#xff0c;Neofj版本&#xff1a;2025.04.0。 Apt安装 Neofj可以进行官网安装&#xff1a;Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

51c自动驾驶~合集58

我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留&#xff0c;CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制&#xff08;CCA-Attention&#xff09;&#xff0c;…...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统

医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上&#xff0c;开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识&#xff0c;在 vs 2017 平台上&#xff0c;进行 ASP.NET 应用程序和简易网站的开发&#xff1b;初步熟悉开发一…...

django filter 统计数量 按属性去重

在Django中&#xff0c;如果你想要根据某个属性对查询集进行去重并统计数量&#xff0c;你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求&#xff1a; 方法1&#xff1a;使用annotate()和Count 假设你有一个模型Item&#xff0c;并且你想…...

生成 Git SSH 证书

&#x1f511; 1. ​​生成 SSH 密钥对​​ 在终端&#xff08;Windows 使用 Git Bash&#xff0c;Mac/Linux 使用 Terminal&#xff09;执行命令&#xff1a; ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" ​​参数说明​​&#xff1a; -t rsa&#x…...

Neo4j 集群管理:原理、技术与最佳实践深度解析

Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案

目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后&#xff0c;迭代器会失效&#xff0c;因为顺序迭代器在内存中是连续存储的&#xff0c;元素删除后&#xff0c;后续元素会前移。 但一些场景中&#xff0c;我们又需要在执行删除操作…...

密码学基础——SM4算法

博客主页&#xff1a;christine-rr-CSDN博客 ​​​​专栏主页&#xff1a;密码学 &#x1f4cc; 【今日更新】&#x1f4cc; 对称密码算法——SM4 目录 一、国密SM系列算法概述 二、SM4算法 2.1算法背景 2.2算法特点 2.3 基本部件 2.3.1 S盒 2.3.2 非线性变换 ​编辑…...

简单介绍C++中 string与wstring

在C中&#xff0c;string和wstring是两种用于处理不同字符编码的字符串类型&#xff0c;分别基于char和wchar_t字符类型。以下是它们的详细说明和对比&#xff1a; 1. 基础定义 string 类型&#xff1a;std::string 字符类型&#xff1a;char&#xff08;通常为8位&#xff09…...

【threejs】每天一个小案例讲解:创建基本的3D场景

代码仓 GitHub - TiffanyHoo/three_practices: Learning three.js together! 可自行clone&#xff0c;无需安装依赖&#xff0c;直接liver-server运行/直接打开chapter01中的html文件 运行效果图 知识要点 核心三要素 场景&#xff08;Scene&#xff09; 使用 THREE.Scene(…...