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

SpringBoot速成(14)文件上传P23-P26

1. 什么是 multipart/form-data

想象一下,你有一个包裹要寄给朋友,但包裹里有不同类型的东西:比如一封信(文字)、一张照片(图片)和一个小礼物(文件)。为了确保这些东西都能安全地送到朋友手里,你需要把它们分别包装好,然后放在一个大盒子里寄出去。

multipart/form-data 就是这样一个“大盒子”,它用来把不同类型的数据(比如文字、文件等)打包在一起,然后通过网络发送给服务器。

2. 为什么需要 multipart/form-data

当你需要上传文件(比如图片、文档)到服务器时,普通的表单数据(application/x-www-form-urlencoded)是不够用的,因为它只能发送文本数据,不能发送文件内容。而 multipart/form-data 可以同时发送文本和文件,就像一个多功能的快递盒子。

3.创建对象:alt+enter

4.假设用户上传了一个名为 photo.jpg 的文件,那么 file.getOriginalFilename() 的返回值就是 "photo.jpg"

file.getOriginalFilename():获取文件的原始文件名,例如用户上传的文件名。

file.transferTo(destFile):将上传的文件保存到服务器的指定路径。

5.文件上传:上传用户头像,上传文章图片

代码展示:

@RestController
public class FileUploadController {@SneakyThrows@PostMapping("/upload")public Result<String> upload(MultipartFile file){//原文件名String originalFilename = file.getOriginalFilename();
//        //文件名唯一:防止覆盖,用uuid拼成唯一的名字
//        String filename= UUID.randomUUID().toString()+originalFilename.substring(originalFilename.lastIndexOf("."));//把文件内容存到本地磁盘上file.transferTo(new File("C:\\Users\\enjoy\\Desktop\\files\\"+originalFilename));return Result.success("url访问地址...");}
}

运行:

换图片:

file未传上:

修改:1.yml中增加对上传文件大小的限制

  servlet:multipart:max-file-size: 300KBmax-request-size: 300KB

2.磁盘路径有错

更改为:

运行成功:尽管在调试过程中postman运行几次,该图片上传好几次,但在磁盘中,若文件原名字相同,则覆盖:


优化:自己用还行,可以覆盖,但是若多个用户上传不同图片仅仅是名字相同就覆盖XXXXXXXXXXXXXXX 

1.UUID 是一个类,用来生成全局唯一标识符(Universally Unique Identifier)。每次调用 UUID.randomUUID() 都会生成一个独一无二的字符串,类似于 123e4567-e89b-12d3-a456-426614174000

作用:生成一个唯一的前缀,确保文件名不会重复。

2.originalFilename.lastIndexOf(".")

originalFilename 是上传文件的原始文件名,比如 photo.jpg

3.lastIndexOf(".") 是一个字符串方法,用来找到最后一个 . 的位置。对于文件名 photo.jpglastIndexOf(".") 会返回 5,因为 . 的位置是第 6 个字符(从 0 开始计数)。

作用:找到文件扩展名的起始位置。

4.substring(...) 是字符串方法,用来截取字符串的一部分。

originalFilename.substring(originalFilename.lastIndexOf(".")):从最后一个 . 开始截取到字符串的末尾。对于 photo.jpg,截取的结果是 .jpg

作用:获取文件的扩展名部分。

5.拼接字符串

把生成的唯一字符串(UUID)和文件扩展名拼接起来,形成一个新的文件名

  • 例如:

    • 原始文件名是 photo.jpg

    • 生成的 UUID123e4567-e89b-12d3-a456-426614174000

    • 最终生成的文件名是 123e4567-e89b-12d3-a456-426614174000.jpg

@RestController
public class FileUploadController {@SneakyThrows@PostMapping("/upload")public Result<String> upload(MultipartFile file){//原文件名String originalFilename = file.getOriginalFilename();//文件名唯一:防止覆盖,用uuid拼成唯一的名字String filename= UUID.randomUUID().toString()+originalFilename.substring(originalFilename.lastIndexOf("."));//把文件内容存到本地磁盘上file.transferTo(new File("C:\\Users\\enjoy\\Desktop\\files\\"+filename));return Result.success("url访问地址...");}
}

运行:相同文件名不覆盖:


优化:使用阿里云对象存储服务(OSS)

1.在输入图片地址时,现有" ",再在里边粘上地址->\\

2.Bucket本身可以理解为一个存储容器或逻辑空间,用于存储和组织数据。在对象存储系统中,Bucket列表帮助用户快速管理和调度资源

OSS使用过程:

1.创建bucket

2.创建AccessKey

3.点击SDK下载

4.yml中添加:

<!--    阿里云oss依赖坐标--><dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId><version>3.17.4</version></dependency><dependency><groupId>javax.xml.bind</groupId><artifactId>jaxb-api</artifactId><version>2.3.1</version></dependency><dependency><groupId>javax.activation</groupId><artifactId>activation</artifactId><version>1.1.1</version></dependency><!-- no more than 2.3.3--><dependency><groupId>org.glassfish.jaxb</groupId><artifactId>jaxb-runtime</artifactId><version>2.3.3</version></dependency>

5.复制该类,并进行修改:

package com.itheima;import java.io.ByteArrayInputStream;import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;public class Demo {public static void main(String[] args) throws Exception {// Endpoint以华北(北京)为例,其它Region请按实际情况填写。String endpoint = "https://oss-cn-beijing.aliyuncs.com";// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
//            EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();String ACCESS_KEY_ID="自己填";String ACCESS_KEY_SSCREST="自己填";// 填写Bucket名称,例如big-event。String bucketName = "big-event";// 填写Object完整路径,完整路径中不能包含Bucket名称,例如001.png。String objectName ="001.png";// 填写Bucket所在地域。以华东1(杭州)为例,Region填写为cn-hangzhou。
//            String region = "cn-hangzhou";// 创建OSSClient实例。
//            ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
//            clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);OSS ossClient = new OSSClientBuilder().build(endpoint,ACCESS_KEY_ID,ACCESS_KEY_SSCREST);
//            .create()
//                    .endpoint(endpoint)
//                    .credentialsProvider(credentialsProvider)
//                    .clientConfiguration(clientBuilderConfiguration)
//                    .region(region)try {// 填写字符串。String content = "Hello OSS,你好世界";// 创建PutObjectRequest对象。PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, new FileInputStream("C:\\Users\\enjoy\\Pictures\\001.png"));// 如果需要上传时设置存储类型和访问权限,请参考以下示例代码。// ObjectMetadata metadata = new ObjectMetadata();// metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());// metadata.setObjectAcl(CannedAccessControlList.Private);// putObjectRequest.setMetadata(metadata);// 上传字符串。PutObjectResult result = ossClient.putObject(putObjectRequest);} catch (OSSException oe) {System.out.println("Caught an OSSException, which means your request made it to OSS, "+ "but was rejected with an error response for some reason.");System.out.println("Error Message:" + oe.getErrorMessage());System.out.println("Error Code:" + oe.getErrorCode());System.out.println("Request ID:" + oe.getRequestId());System.out.println("Host ID:" + oe.getHostId());} catch (ClientException ce) {System.out.println("Caught an ClientException, which means the client encountered "+ "a serious internal problem while trying to communicate with OSS, "+ "such as not being able to access the network.");System.out.println("Error Message:" + ce.getMessage());} finally {if (ossClient != null) {ossClient.shutdown();}}}}

运行:

点对象存储,快速进入OSS管理控制台

文件列表出现001.png

在浏览器地址栏粘贴地址,自动下载


结合源代码:

代码展示:

AliOssUtil:

package com.itheima.utils;import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;import java.io.FileInputStream;
import java.io.InputStream;public class AliOssUtil {private static String ENDPOINT = "https://oss-cn-beijing.aliyuncs.com";private static String ACCESS_KEY_ID="LTAI5tAi5kPgBPddtw9W1Cyk";private static String ACCESS_KEY_SSCREST="H7ATBUYZaKlcznauOO10LrpJYjdIuV";private static String BUCKETNAME= "big-eventxian";//会更改的是图片的名字和地址,把这两个提出来做参数//原方法名main,改名//方法运行后返回图片地址,所以返回值改为stringpublic static String uploadFile(String objectName, InputStream in) throws Exception {OSS ossClient = new OSSClientBuilder().build(ENDPOINT,ACCESS_KEY_ID,ACCESS_KEY_SSCREST);
//添加返回值为空String url="";
//成功执行,并赋地址给urltry {String content = "Hello OSS,你好世界";PutObjectRequest putObjectRequest = new PutObjectRequest(BUCKETNAME, objectName, in);PutObjectResult result = ossClient.putObject(putObjectRequest);//url的格式https://big-eventxian.oss-cn-beijing.aliyuncs.com/001.png?Expires=1739886181&OSSAccessKeyId=TMP.3KkTvEibCf7tgTUtbapGLFhRg5NVwjJsi44ghDSZnxrzZkJdj3M4R1UeLCHQWg54L41EQYdqVE8rRhrpY7AC74ZsVCdNBX&Signature=PdGRCtze5IpO0bOnlEgHsRUuKLA%3Durl="https://"+BUCKETNAME+"."+ENDPOINT.substring(ENDPOINT.lastIndexOf("/")+1)+"/"+objectName;} catch (OSSException oe) {System.out.println("Caught an OSSException, which means your request made it to OSS, "+ "but was rejected with an error response for some reason.");System.out.println("Error Message:" + oe.getErrorMessage());System.out.println("Error Code:" + oe.getErrorCode());System.out.println("Request ID:" + oe.getRequestId());System.out.println("Host ID:" + oe.getHostId());} catch (ClientException ce) {System.out.println("Caught an ClientException, which means the client encountered "+ "a serious internal problem while trying to communicate with OSS, "+ "such as not being able to access the network.");System.out.println("Error Message:" + ce.getMessage());} finally {if (ossClient != null) {ossClient.shutdown();}}//返回值return url;}}

FileUploadController:

package com.itheima.controller;import com.itheima.pojo.Result;
import com.itheima.utils.AliOssUtil;
import lombok.SneakyThrows;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;import java.io.File;
import java.util.UUID;@RestController
public class FileUploadController {@SneakyThrows@PostMapping("/upload")public Result<String> upload(MultipartFile file){//原文件名String originalFilename = file.getOriginalFilename();
//        //文件名唯一:防止覆盖,用uuid拼成唯一的名字String filename= UUID.randomUUID().toString()+originalFilename.substring(originalFilename.lastIndexOf("."));//把文件内容存到本地磁盘上
//        file.transferTo(new File("C:\\Users\\enjoy\\Desktop\\files\\"+originalFilename));String url=AliOssUtil.uploadFile(filename,file.getInputStream());return Result.success(url);}
}

运行成功:

但是点击data的url,访问失败:You have no right to access this object because of bucket acl.,意思是你没有权限访问这个对象,因为存储桶的访问控制列表(ACL)设置不允许。

修改方式: 

如果粘贴url到地址栏,可以直接下载:

相关文章:

SpringBoot速成(14)文件上传P23-P26

1. 什么是 multipart/form-data&#xff1f; 想象一下&#xff0c;你有一个包裹要寄给朋友&#xff0c;但包裹里有不同类型的东西&#xff1a;比如一封信&#xff08;文字&#xff09;、一张照片&#xff08;图片&#xff09;和一个小礼物&#xff08;文件&#xff09;。为了确…...

图论入门算法:拓扑排序(C++)

上文中我们了解了图的遍历(DFS/BFS), 本节我们来学习拓扑排序. 在图论中, 拓扑排序(Topological Sorting)是对一个有向无环图(Directed Acyclic Graph, DAG)的所有顶点进行排序的一种算法, 使得如果存在一条从顶点 u 到顶点 v 的有向边 (u, v) , 那么在排序后的序列中, u 一定…...

PTA:使用指针方式求一个给定的m×n矩阵各行元素之和

本题要求编写程序&#xff0c;使用指针方式求一个给定的mn矩阵各行元素之和。&#xff08;例如&#xff1a;scanf("%d", *(matrix i) j); // 使用指针方式访问二维数组元素&#xff09; 输入格式: 输入第一行给出两个正整数m和n&#xff08;1<m<6, 1<n&…...

【iOS】SwiftUI状态管理

State ObservedObject StateObject 的使用 import SwiftUIclass CountModel: ObservableObject {Published var count: Int 0 // 通过 Published 标记的变量会触发视图更新init() {print("TimerModel initialized at \(count)")} }struct ContentView: View {State…...

自制简单的图片查看器(python)

图片格式&#xff1a;支持常见的图片格式&#xff08;JPG、PNG、BMP、GIF&#xff09;。 import os import tkinter as tk from tkinter import filedialog, messagebox from PIL import Image, ImageTkclass ImageViewer:def __init__(self, root):self.root rootself.root.…...

ChatGPT行业热门应用提示词案例-AI绘画类

AI 绘画指令是一段用于指导 AI 绘画工具&#xff08;如 DALLE、Midjourney 等&#xff09;生成特定图像的文本描述。它通常包含场景、主体、风格、色彩、氛围等关键信息&#xff0c;帮助 AI 理解创作者的意图&#xff0c;从而生成符合要求的绘画作品。 ChatGPT 拥有海量的知识…...

Visual Studio Code的下载安装与汉化

1.下载安装 Visual Studio Code的下载安装十分简单&#xff0c;在本电脑的应用商店直接下载安装----注意这是社区版-----一般社区版就足够用了---另外注意更改安装地址 2.下载插件 重启后就是中文版本了...

分词器(Tokenizer) | 有了分词器,为什么还需要嵌入模型

文章目录 什么是tokenizer有了分词器&#xff0c;为什么还需要嵌入模型分词器为什么在transformers 里Hugging Face的Tokenizer大模型不同tokenizer训练效果对比分词器库选择当前顶尖大模型所采用的 Tokenizer 方法与词典大小 参考 什么是tokenizer Tokenizers huggingface官方…...

scala中 隐式转换

一、 隐式转换&#xff1a; 编译器 偷偷地&#xff0c;自动地帮我们把一种数据类型转换为另一种类型 例如&#xff1a; int --> double object test {// 复习隐式转换// 隐式转换&#xff1a; 编译器 偷偷地&#xff0c;自动地帮我们把一种数据类型转换为另一…...

实战开发coze应用-姓氏头像生成器(上)

​欢迎关注【AI技术开发者】 上次&#xff0c;我们开发了一个对话形式的头像生成器智能体&#xff08;Agents&#xff09;&#xff0c;广受大家欢迎。 同时也接收到一些用户的反馈&#xff0c;生成前无法看到头像样式、初次使用不会用等等。 对此&#xff0c;我准备使用Coze开…...

【Node.js】express框架

目录 1初识express框架 2 初步使用 2.1 安装 2.2 创建基本的Web服务器 2.3 监听方法 2.3.1 监听get请求 2.3.2 监听post请求 2.4 响应客户端 2.5 获取url中的参数(get) 2.5.1 获取查询参数 2.5.2 获取动态参数 2.6 托管静态资源 2.6.1 挂载路径前缀 2.6.2 托管多…...

JS逆向实战三:1688工厂信息

本文说明&#xff1a;B站学习笔记整理&#xff0c;仅供学习参考~~ 网站&#xff1a;https://sale.1688.com/factory/category.html 1. 页面分析与解密 刷新页面&#xff0c;通过对关键词进行搜索&#xff0c;实现接口定位。 通过多次刷新页面或者页面翻页&#xff0c;找到变化…...

Pipeline 获取 Jenkins参数

Pipeline 获取 Jenkins参数 Jenkins 提供了一系列默认的环境变量&#xff0c;这些变量在构建过程中可以被使用。以下是一些常见的 Jenkins 默认环境变量&#xff1a; WORKSPACE: 当前构建的工作目录路径 JOB_NAME: 当前构建的作业名称 BUILD_NUMBER: 当前构建的编号&#xff…...

ESP32 在IDF_V5.3.1版本下实现AP无线热点模式!(带WIFI事件处理)

一、什么是ESP32的AP无线热点模式&#xff1f; ESP32 的 AP&#xff08;Access Point&#xff09;模式 是指 ESP32 作为无线接入点运行&#xff0c;它自己创建一个 Wi-Fi 网络&#xff0c;允许其他设备&#xff08;如手机、电脑、平板等&#xff09;直接连接到它上面&#xff0…...

Elasticsearch:探索 CLIP 替代方案

作者&#xff1a;来自 Elastic Jeffrey Rengifo 及 Toms Mura 分析图像到图像和文本到图像搜索的 CLIP 模型的替代方案。 在本文中&#xff0c;我们将通过一个模拟房地产网站的实际示例介绍 CLIP 多模态模型&#xff0c;探索替代方案&#xff0c;并分析它们的优缺点&#xff0c…...

Nginx 在Linux中安装、使用

Nginx 在Linux中安装、使用 一、官网下载Nginx 官网地址&#xff1a;http://nginx.org/en/download.html 二、上传到服务器解压 1、上传到指定的服务器地址 上传的地址自己决定&#xff0c;我上传到 /data/home/prod/nginx/ 2、解压 使用命令&#xff1a; tar -zxvf “你的N…...

CodeGPT 使用教程(适用于 VSCode)

CodeGPT 使用教程&#xff08;适用于 VSCode&#xff09; CodeGPT 是一个 VSCode 插件&#xff0c;可以让你在代码编辑器中直接调用 GPT 进行代码补全、优化、调试等操作。以下是详细的安装和使用步骤&#xff1a; 1. 安装 CodeGPT 方式 1&#xff1a;从 VSCode 插件市场安装…...

Python常见面试题的详解9

1. 如何找出整数数组中第二大的数 要点 定义一个函数用于在整数数组里找出第二大的数。 若数组元素少于 2 个&#xff0c;则返回 None。 借助两个变量 first 和 second 来跟踪最大数和第二大数。 可以添加异常处理&#xff0c;以应对输入非整数数组的情况。 若数组包含重复…...

【Spring+MyBatis】_图书管理系统(下篇)

图书管理系统上篇、中篇如下&#xff1a; 【SpringMyBatis】_图书管理系统&#xff08;上篇&#xff09;-CSDN博客 【SpringMyBatis】_图书管理系统&#xff08;中篇&#xff09;-CSDN博客 目录 功能5&#xff1a;删除图书 6.1 约定前后端交互接口 6.2 后端接口 6.3 前端…...

若依-@Excel新增注解numberFormat

Excel注解中原本的scale会四舍五入小数&#xff0c;导致进度丢失 想要的效果 显示的时候保留两个小数真正的数值是保留之前的数值 还原过程 若以中有一個專門的工具类&#xff0c;用来处理excel的 找到EXCEL导出方法exportExcel()找到writeSheet,写表格的方法找到填充数据的方法…...

Cherry-Studio下载安装教程,AI面向开发者的工具或平台(付安装包)

文章目录 一、Cherry Studio是什么&#xff1f;二、功能特点 一、Cherry Studio是什么&#xff1f; Cherry Studio 是一款开源跨平台的多模型服务桌面客户端&#xff0c;集成超 300 个大语言模型&#xff0c;内置 300 多个预配置 AI 助手&#xff0c;支持多格式文件处理、全局…...

多信道接收机

线性调频&#xff08;LFM&#xff09;信号&#xff0c;模拟多个目标反射的回波信号&#xff0c;并进行混频和滤波处理。 % 参数设置 c 3e8; % 光速 (m/s) f0 8.566e9; % 载波频率 (Hz) T 10e-6; % 脉冲持续时间 (s) B 100e6; % 信号带宽 (Hz) mu B / T; % 调频斜率 (Hz/s…...

修改项目的一些前端记录(自用)

<div style"background:#f2f2f2;position:absolute;top:75px;width:10%;bottom:0px">\<ol class"tree">\<li>\<label for"folder1" class"folderOne foldertop"><img src"common/img/时间.png" …...

阿里云虚机的远程桌面登录提示帐户被锁定了

提示由于安全原因&#xff0c;帐户被锁定。 阿里云虚机ECS的远程桌面登录提示帐户被锁定了&#xff0c;只能登录阿里云处理 阿里云-计算&#xff0c;为了无法计算的价值 需选择通过VNC连接 然后计算机管理&#xff0c;解除帐户锁定即可。...

AD(Altium Designer)器件封装——立创商城导出原理图和PCB完成器件封装操作指南

1、立创商城下载原理图和PCB图 1.1 打开立创商城 官网:www.SZLCSC.COM 1.2 寻找所需器件 以芯片为例 器件类——>芯片类——>对应芯片 1.3 确定所需芯片 确定芯片——>数据手册 1.4 打开原理图和PCB图 1:原理图 2:PCB 3:打开 1.5 导出原理图 操作...

【DeepSeek系列】04 DeepSeek-R1:带有冷启动的强化学习

文章目录 1、简介2、主要改进点3、两个重要观点4、四阶段后训练详细步骤4.1 冷启动4.2 推理导向的强化学习4.3 拒绝采样和有监督微调4.4 针对所有场景的强化学习 5、蒸馏与强化学习对比6、评估6.1 DeepSeek-R1 评估6.2 蒸馏模型评估 7、结论8、局限性与未来方向 1、简介 DeepS…...

【C++八股】野指针和悬空指针

野指针&#xff08;Wild Pointer&#xff09;是指未被初始化或指向非法内存地址的指针。在 C/C 等语言中&#xff0c;指针变量如果在定义时未被初始化&#xff0c;其值是随机的&#xff0c;可能指向任意内存位置&#xff0c;这种指针被称为野指针。使用野指针进行解引用操作会导…...

Mac 清理缓存,提高内存空间

步骤 1.打开【访达】 2.菜单栏第五个功能【前往】&#xff0c;点击【个人】 3.【command shift J】显示所有文件&#xff0c;打开【资源库】 4.删除【Containers】和【Caches】文件 Containers 文件夹&#xff1a;用于存储每个应用程序的沙盒数据&#xff0c;确保应用程序…...

fpga助教面试题

第一题 module sfp_pwm( input wire clk, //clk is 200M input wire rst_n, input wire clk_10M_i, input wire PPS_i, output reg pwm ) reg [6:0] cunt ;always (posedge clk ) beginif(!rst_n)cunt<0;else if(cunt19) //200M是10M的20倍cunt<0;elsecunt<cunt1;…...

DeepSeek与ChatGPT:会取代搜索引擎和人工客服的人工智能革命

云边有个稻草人-CSDN博客 在众多创新技术中&#xff0c;DeepSeek和ChatGPT无疑是最为引人注目的。它们通过强大的搜索和对话生成能力&#xff0c;能够改变我们与计算机交互的方式&#xff0c;帮助我们高效地获取信息&#xff0c;增强智能服务。本文将深入探讨这两项技术如何结合…...