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: 300KB
max-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.jpg
,lastIndexOf(".")
会返回5
,因为.
的位置是第 6 个字符(从 0 开始计数)。作用:找到文件扩展名的起始位置。
4.substring(...)
是字符串方法,用来截取字符串的一部分。
originalFilename.substring(originalFilename.lastIndexOf("."))
:从最后一个.
开始截取到字符串的末尾。对于photo.jpg
,截取的结果是.jpg
。作用:获取文件的扩展名部分。
5.拼接字符串
把生成的唯一字符串(
UUID
)和文件扩展名拼接起来,形成一个新的文件名
例如:
原始文件名是
photo.jpg
。生成的
UUID
是123e4567-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,改名
//方法运行后返回图片地址,所以返回值改为string
public static String uploadFile(String objectName, InputStream in) throws Exception {
OSS ossClient = new OSSClientBuilder().build(ENDPOINT,ACCESS_KEY_ID,ACCESS_KEY_SSCREST);
//添加返回值为空
String url="";
//成功执行,并赋地址给url
try {
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%3D
url="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到地址栏,可以直接下载: