文件上传功能
- 前端文件上传
前端完成文件上传需要:三要素
- 表单必须有 file 域,用于选择要上传的文件
- 表单提交方式必须为 POST。因为上传的文件相对来比较大,所以用post请求
- 表单的编码类型enctype必须要设置为 multipart/form-data。如果选择默认的不设置这个编码类型的话,只能上传名字,不能将具体内容上传上去。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>文件上传</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
姓名: <input type="text" name="name"/><br/>
年龄: <input type="text" name="age"/></br>
图片: <input type="file" name="image"/><br/><br/>
<input type="submit" value="提交"/>
</form>
</body>
</html>
- 后端文件上传
在后端的SpringBoot框架当中,我们有一个类型为MultipartFile,使用它就能够完成文件上传的功能。
@Slf4j
@RestController
public class UpLoadController {
@PostMapping("/upload")
//在Spring中提供了一个上传文件的类型为:MultipartFile,我们可以借助这个来完成上传文件的功能
//但是我们需要保证类型后面的变量的名字和前端提交文件时所用的名字一致,如果不一致的话需要在前面加一个
//@RequestParam("文件上传时的变量名")
public Result upload(String name, Integer age, MultipartFile image) {
//搞一个日志来记录过程
log.info("输出结果为:{},{},{}",name,age,image);
return Result.success();
}
}
- 使用这种方式,结合我们在static下写的一个html上传功能的文件,就可以实现前端上传后端接受了。
- 但是这个上传的文件只会临时保存在硬盘当中,当程序运行结束之后,零时文件就会被自动删除。那么我们在后端怎么把上传来的文件保存起来呢?
将文件保存在本地以使用MultipartFile当中的两个方法。
以及使文件不会被覆盖
@Slf4j
@RestController
public class UpLoadController {
@PostMapping("/upload")
//在Spring中提供了一个上传文件的类型为:MultipartFile,我们可以借助这个来完成上传文件的功能
//但是我们需要保证类型后面的变量的名字和前端提交文件时所用的名字一致,如果不一致的话需要在前面加一个
//@RequestParam("文件上传时的变量名")
public Result upload(String name, Integer age, MultipartFile image)throws Exception {
//搞一个日志来记录过程
log.info("输出结果为:{},{},{}",name,age,image);
//获取要上传的文件名
String originalFilename = image.getOriginalFilename();
//找文件的后缀
int i = originalFilename.lastIndexOf(".");
String extname = originalFilename.substring(i);
//将名字改过来,使用这个就可以使文件不会重名而导致的覆盖情况
String newFuleName = UUID.randomUUID().toString() + extname;
//将文件存储在服务器的磁盘目录中
image.transferTo(new File("E:\\images\\"+newFuleName));
return Result.success();
}
}
问题:在SpringBoot中,文件上传,默认单个文件允许最大大小为 1M,如果需要上传大文件,可以在application.properties进行如下配置
#配置单个文件的最大上传大小
spring.servlet.multipart.max-file-size=10MB
#配置单个请求最大上传大小(一次请求可以上传多个文件)
spring.servlet.multipart.max-request-size=100MB
后续问题:
如果直接存储在服务器的磁盘目录中,存在以下缺点:
- 不安全: 磁盘如果损坏,所有的文件就会丢失
- 容量有限:如果存储大量的图片,磁盘空间有限(磁盘不可能无限制扩容).
- 无法直接访问
为了解决上述问题呢一般有两种解决方案
- 自己搭建文件存储系统,如: fastDFS
- 自己搭建对象存储服务,如: MinlO
- 使用现成的云服务,如: 阿里云,腾讯云,华为云
- 使用阿里云OSS上传文件
- 引入依赖
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.15.0</version>
</dependency>
(2)测试文件上传
public class AliOssTest {
@Test
public void testOss(){
// Endpoint指定OSS服务的地址。
String endpoint = "https://oss-cn-shanghai.aliyuncs.com";
// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。
// 强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
String accessKeyId = "LTAI5tFsWn7sUXf8XfvJgXgk";
String accessKeySecret = "jXSHJzb1IS7iZr6ELaH68TZArr0rgf";
// 填写Bucket名称,例如examplebucket。
String bucketName = "myjava161";
// 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
String objectName = "0001.jpg";
// 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。
// 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件流。
String filePath= "C:\\Users\\Xuan Zhi Zhou\\Desktop\\图片例子\\photo_new_T001R150x150M000002XPByY4NwIAp_2.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();
}
}
}
}
- 阿里云OSS-集成
步骤:
- 引入阿里云OSS上传文件工具类(由官方示例代码改造而来)
public class AliOSSUtils {
private String endpoint = "https://oss-cn-shanghai.aliyuncs.com";
private String accessKeyId = "LTAI5tFsWn7sUXf8XfvJgXgk";
private String accessKeySecret = "jXSHJzb1IS7iZr6ELaH68TZArr0rgf";
private String bucketName = "myjava161";
/**
* 实现上传图片到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的路径返回
}
}
- 上传图片接口开发
/*
* 集成oss上传
* */
@Autowired
private AliOSSUtils aliOSSUtils;
public Result upload(MultipartFile image) throws Exception {
//调用阿里云OSS工具类,将上传上来的文件存入阿里云
String url = aliOSSUtils.upload(image);
//将图片上传完成后的url返回,用于浏览器回显展示
return Result.success(url);
}