文件上传,也称为upload,是指将本地图片、视频、音频等文件上传到服务器上,可以供其他用户浏览或下载的过程。
文件上传在项目中应用非常广泛,我们经常发微博、发微信朋友圈都用到了文件上传功能。
上传文件的原始form表单,要求表单必须具备以下三点(上传文件页面三要素):
表单必须有 file 域,用于选择要上传的文件。
表单提交方式必须为 POST。
表单的编码类型enctype必须要设置为 multipart/form-data。
如果我们加上 enctype="multipart/form-data",代表的是我们请求的数据是多部分的,通过浏览器的开发者工具( firefox浏览器 ),我们也可以看到请求的数据:
在服务端,我们要想接收上传上来的文件,需要使用Spring给我们提供的一个,专门接收文件的API : MultipartFile。
import com.itheima.pojo.Result;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
@RestController
public class UploadController {
@PostMapping("/upload")
public Result upload(MultipartFile image) throws IOException {
System.out.println(image.getName)
return Result.success();
}
}
上传上来的文件,其实呢,是暂存在系统的临时文件中了。 我们可以通过debug,就可以看出来。
对于这个图片上传功能呢,主要分为两部操作:
选择文件,进行图片上传,将图片文件上传到服务器存储起来,然后返回图片访问的URL。
当点击保存时,除了页面的基本表单数据需要提交到服务端,图片访问的URL,也需要提交到服务端。
我们先来完成第一部分,将上传的图片保存在本地磁盘目录。
package com.itheima.controller;
import com.itheima.pojo.Result;
import org.springframework.beans.factory.annotation.Autowired;
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.io.IOException;
import java.util.UUID;
@RestController
public class UploadController {
@Autowired
private AliOSSUtils aliOSSUtils;
//上传至本地服务器
@PostMapping("/upload")
public Result upload(MultipartFile image) throws IOException {
//获取原始文件名
String originalFilename = image.getOriginalFilename();
//构建新的文件名
String newFileName = UUID.randomUUID().toString()+originalFilename.substring(originalFilename.lastIndexOf("."));
//将文件保存在服务器端 E:/images/ 目录下
image.transferTo(new File("E:/images/"+newFileName));
return Result.success();
}
}
MultipartFile 常见方法:
getOriginalFilename():获取原始文件名
getContentType():获取文件的类型
getInputStream():获取文件的输入流
getBytes():获取文件的字节数组
可以直接使用我们准备好的文件上传的页面进行测试。
在我们进行图片上传的测试中,我们发现,有时候可以上传成功,而有时候呢,又不能上传成功,报出如下错误。
报错我原因呢,是因为:在SpringBoot中,文件上传,默认单个文件允许最大大小为 1M,如果需要上传大文件,可以在application.properties进行如下配置:
#配置单个文件的最大上传大小
spring.servlet.multipart.max-file-size=10MB
#配置单个请求最大上传大小(一次请求可以上传多个文件)
spring.servlet.multipart.max-request-size=100MB
阿里云对象存储OSS(Object Storage Service)是一款海量、安全、低成本、高可靠的云存储服务,提供99.9999999999% (12个9)的数据持久性,99.995%的数据可用性。多种存储类型供选择,全面优化存储成本。
注册完账号之后,就可以登录阿里云:
点击控制台,然后找到 对象存储OSS 服务。
如果是第一次访问,还需要开通 对象存储服务OSS。
开通之后,就可以进入到阿里云对象存储的控制台。
点击左侧的 "Bucket列表",然后创建一个Bucket。
参照官方提供的SDK,改造一下,即可实现文件上传功能。
1). pom.xml
com.aliyun.oss
aliyun-sdk-oss
3.15.0
2). 测试文件上传
import org.junit.jupiter.api.Test;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import java.io.FileInputStream;
import java.io.InputStream;
public class AliOssTest {
@Test
public void testOss(){
// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
String endpoint = "********";
// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
String accessKeyId = "********";
String accessKeySecret = "*********";
// 填写Bucket名称,例如examplebucket。
String bucketName = "web-397";
// 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
String objectName = "0001.jpg";
// 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。
// 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件流。
String filePath= "C:\\Users\\Administrator\\Pictures\\Saved Pictures\\10.jpg";
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
try {
InputStream inputStream = new FileInputStream(filePath);
// 创建PutObject请求。
ossClient.putObject(bucketName, objectName, inputStream);
} 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 (Exception 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();
}
}
}
}
在上述的代码中,需要替换的内容为:
accessKeyId:阿里云账号AccessKey
accessKeySecret:阿里云账号AccessKey对应的秘钥
bucketName:Bucket名称
objectName:对象名称,在Bucket中存储的对象的名称
filePath:文件路径
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* 阿里云 OSS 工具类
*/
@Component
public class AliOSSUtils {
private String endpoint = "*************";
private String accessKeyId = "*************";
private String accessKeySecret = "*************";
private String bucketName = "web-397";
/**
* 实现上传图片到OSS
*/
public String upload(MultipartFile multipartFile) throws IOException {
// 获取上传的文件的输入流
InputStream inputStream = multipartFile.getInputStream();
// 避免文件覆盖
String fileName = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss")) + multipartFile.getOriginalFilename();
//上传文件到 OSS
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
ossClient.putObject(bucketName, fileName, inputStream);
//文件访问路径
String url = endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + fileName;
// 关闭ossClient
ossClient.shutdown();
return url;// 把上传到oss的路径返回
}
}
在原有的UploadController的基础上进行升级改造
@RestController
public class UploadController {
@Autowired
private AliOSSUtils aliOSSUtils;
//上传至本地服务器
/*@PostMapping("/upload")
public Result upload(MultipartFile image) throws IOException {
//获取原始文件名
String originalFilename = image.getOriginalFilename();
//构建新的文件名
String newFileName = UUID.randomUUID().toString()+originalFilename.substring(originalFilename.lastIndexOf("."));
//将文件保存在服务器端 E:/images/ 目录下
image.transferTo(new File("E:/images/"+newFileName));
return Result.success();
}*/
@PostMapping("/upload")
public Result upload(MultipartFile image) throws IOException {
String url = aliOSSUtils.upload(image);
return Result.success(url);
}
}