文件上传和阿里云OSS
文件上传,是指将本地图片、视频、音频等文件上传到服务器,供其他用户浏览或下载的过程。用来接收上传的文件录入数据并提交,通过后端程序控制台可以看到,表单提交的三项数据(姓名、年龄、文件)存放在一个临时目录,分别存储在不同的临时文件中,当程序运行完毕之后,临时文件会自动删除。所以如果想要实现文件上传,需要将这个临时文件转存到我们的磁盘目录中。
1. 简介
文件上传,是指将本地图片、视频、音频等文件上传到服务器,供其他用户浏览或下载的过程。
前端程序:
<form action="/upload" method="post" enctype="multipart/form-data">
姓名: <input type="text" name="username"><br>
年龄: <input type="text" name="age"><br>
头像: <input type="file" name="image"><br>
<input type="submit" value="提交">
</form>
上传文件的原始 form 表单,要求表单必须具备以下三点(上传文件页面三要素):
- 表单必须有
file
域,用于选择要上传的文件 - 表单提交方式必须为
POST
通常上传的文件会比较大,所以需要使用POST
提交方式 - 表单的编码类型
enctype
必须要设置为:multipart/form-data
默认的编码格式只能上传文件名,不适合传输大型的二进制数据
后端程序:
@RestController
public class UploadController {
@PostMapping("/upload")
public Result upload(String username, Integer age, MultipartFile image) {
return Result.success();
}
}
- 在服务端定义一个 Controller 用来进行文件上传,在 Controller 当中定义一个方法来处理
/upload
请求 - 在定义的方法中接收提交的数据 (方法中的形参名和请求参数的名字保持一致)
- 用户名:
String name
- 年龄:
Integer age
- 文件:
MultipartFile image
- 用户名:
Spring 中提供了一个 API:
MultipartFile
,用来接收上传的文件
后端程序打个断点,以 debug 方式启动项目,打开浏览器输入:http://localhost:8080/upload.html录入数据并提交,通过后端程序控制台可以看到,表单提交的三项数据(姓名、年龄、文件)存放在一个临时目录,分别存储在不同的临时文件中,当程序运行完毕之后,临时文件会自动删除。
所以如果想要实现文件上传,需要将这个临时文件转存到我们的磁盘目录中。
2. 本地存储
- 在服务器本地磁盘上创建 images 目录,用来存储上传的文件(例:E盘创建 images 目录)
- 使用
MultipartFile
类提供的 API 方法,把临时文件转存到本地磁盘目录下
String getOriginalFilename(); //获取原始文件名
void transferTo(File dest); //将接收的文件转存到磁盘文件中
long getSize(); //获取文件的大小,单位:字节
byte[] getBytes(); //获取文件内容的字节数组
InputStream getInputStream(); //获取接收到的文件内容的输入流
为保证每次上传文件时文件名都唯一的,可以使用 UUID 获取随机文件名。
@Slf4j
@RestController
public class UploadController {
@PostMapping("/upload")
public Result upload(String username, Integer age, MultipartFile image) throws IOException {
log.info("文件上传:{},{},{}",username,age,image);
//获取原始文件名
String originalFilename = image.getOriginalFilename();
//找到最后一个.的位置截取文件扩展名
String extname = originalFilename.substring(originalFilename.lastIndexOf("."));
//使用UUID获取随机文件名+文件扩展名
String newFileName = UUID.randomUUID().toString()+extname;
//将文件存储在服务器的磁盘目录
image.transferTo(new File("E:/images/"+newFileName));
return Result.success();
}
}
如果需要上传大文件,可以在 application.properties
进行如下配置:
#配置单个文件最大上传大小
spring.servlet.multipart.max-file-size=10MB
#配置单个请求最大上传大小(一次请求可以上传多个文件)
spring.servlet.multipart.max-request-size=100MB
缺点:
- 不安全:磁盘如果损坏,所有的文件就会丢失
- 容量有限:如果存储大量的图片,磁盘空间有限(磁盘不可能无限制扩容)
- 无法直接访问
为了解决上述问题,通常有两种解决方案:
- 自己搭建存储服务器,如:fastDFS 、MinIO
- 使用现成的云服务,如:阿里云,腾讯云,华为云
3. 阿里云 OSS
1.在官网对象存储 OSS_云存储服务_企业数据管理_存储-阿里云 (aliyun.com)注册并实名认证,打开控制台开通 OSS 对象存储服务。
2.进入 OSS 控制台,创建 Bucket 存储容器,选择本地冗余存储和公共读。
3.在 Java 中使用 OSS,参考官方文档
(1)引入依赖
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.17.4</version>
</dependency>
如果是 Java 9及以上的版本,还需要引入以下依赖
<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>
(2)获取 AccessKeyId
(3)图片上传
在 Java 程序中使用 OSS 服务需要提供 endpoint、accessKeyId、accessKeySecret、bucketName
四个量。前三个用于创建 OSSClient 对象,OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
,最后一个用于确定上传的图片放在哪个 Bucket 下边。
先构造一个 PutObjectRequest
或者 GetObjectRequest
,然后通过 ossclient
调用 putObject
(put 请求)/ getObject
(get 请求)。
// 创建put请求
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, inputStream);
// 调用这个put请求,返回请求的result结果
PutObjectResult result = ossClient.putObject(putObjectRequest);
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import java.io.FileInputStream;
import java.io.InputStream;
public class Demo {
public static void main(String[] args) throws Exception {
// Endpoint以华北2(北京)为例,其它Region请按实际情况填写。
String endpoint = "https://oss-cn-beijing.aliyuncs.com";
// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
String accessKeyId = "yourAccessKeyId";
String accessKeySecret = "yourAccessKeySecret";
// 填写Bucket名称,例如examplebucket。
String bucketName = "examplebucket";
// 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
String objectName = "exampledir/exampleobject.txt";// 图片上传之后的名字
// 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。
// 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件流。
String filePath= "D:\\localpath\\examplefile.txt";
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
try {
InputStream inputStream = new FileInputStream(filePath);
// 创建PutObjectRequest对象。
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, inputStream);
// 创建PutObject请求。
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 上传文件工具类,使用 @Component
注解交给 IOC 容器管理。
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
import java.util.UUID;
@Component
public class AliOssUtil {
private String endpoint = "https://oss-cn-beijing.aliyuncs.com";
private String prefix = "https://";
private String point = ".oss-cn-beijing.aliyuncs.com/";
private String accessKeyId = "yourAccessKeyId";
private String accessKeySecret = "yourAccessKeySecret";
private String bucketName = "examplebucket";
public String upload(MultipartFile file) throws Exception {
// 获取上传文件的输入流
InputStream inputStream = file.getInputStream();
//获取文件原始名
String originalFilename = file.getOriginalFilename();
//获取文件扩展名
String extname = originalFilename.substring(originalFilename.lastIndexOf('.'));
//拼接随机名加扩展名作为文件名
String newFilename = UUID.randomUUID().toString() + extname;
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
//上传文件到 OSS
ossClient.putObject(bucketName, newFilename, inputStream);
//文件访问路径
String url = prefix + bucketName + point + newFilename;
return url;
}
}
更多推荐
所有评论(0)