Day11-03.案例-文件上传-本地存储
1.本地存储:
在服务端,接收到上传上来的文件之后,将文件存储在本地服务器磁盘当中。
2.怎么获取到原始文件的名字呢??
上一小节在抓包的过程当中会看到,一旦将enctype属性设置为multipart/form-data,此时表单分为多个部分提交,而如果我们提交的是一个文件,会看到文件表单项的名字,文件的原始名字(中国梦.txt),文件的类型,文件的内容全部提交到了服务端,而这些信息已经封装在了multiFile这个对象当中,所以要想获取原始文件名,直接调用这个对象当中的方法就可以了。
3.优化:
如果采用原始文件名来存储是有问题的,此时a用户上传了一张图片叫1.jpg,b用户接着又上传了一张图片叫1.jpg,而这两张图片都需要存储在一个目录下,最终会造成后面上传的图片把前面上传的图片覆盖了。造成这种情况是因为采用的原始文件名存储。而我们要想后面上传的文件不会把前面上传的文件覆盖了,我们就需要保证每一个文件他的名称是唯一的。
4.怎么构造唯一的文件名(不能重复)??
1.可能想到:拿到当前时间的毫秒值来作为文件名,这种并不能保证它是不会重复的,有可能两个用户在同一时间,同时上传了一张图片,此时拿到的当前时间毫秒值就是一样的,文件名也重复了。
2.uuid(通用唯一识别码):长度固定的字符串,是不会重复的。
3.UUID.randomUUID().toString():获取唯一的UUID
@PostMapping("/upload")
public Result upload(String username, Integer age, MultipartFile image) throws IOException {
log.info("文件上传:{}, {}, {}", username, age, image);
//获取原始文件名 1.jpg 123.0.0.jpg
String originalFilename = image.getOriginalFilename();
//构造唯一的文件名(不能重复) - uuid(通用唯一识别码) 25786057-008e-4d16-9c86-a30f655c1d84
//找到最后一个点所处的位置
int index = originalFilename.lastIndexOf(".");
//截取到字符串的尾部
String extname = originalFilename.substring(index);
String newFileName = UUID.randomUUID().toString() + extname;
log.info("新的文件名为:{}", newFileName);
//将文件存储在服务器的磁盘目录中 C:\本地存储
image.transferTo(new File("C:\\本地存储\\" + newFileName));
return Result.success();
}
实现思路:
第一步获取原始文件名,获取到原始文件名之后,我们由原始文件名可以获得文件的后缀,通过字符串截取这种方式就可以获取到文件的拓展名,然后在拓展名的前面拼接上一个UUID唯一标识的字符串,就可以保证构建出来的新的文件名是唯一的。然后接着调用image.transferTO这个方法,将接收到的文件直接转存到某一个磁盘文件当中。
FileSizeLimitExceededException
注意:默认上传文件大小为1M,超过了会报错,如果在项目开发过程中,我要上传视频或者是音频或者是一个大文件呢?(远大于1M)
5.在SpringBoot中,文件上传,默认单个文件允许最大大小为1M。如果需要上传大文件,可以进行如下配置。
#配置单个文件最大上传大小
spring.servlet.multipart.max-file-size=10MB
#配置单个请求最大上传大小(一次请求可以上传多个文件)(用数组或者集合来接收就行了)(多个文件的总大小不能查过100M)
spring.servlet.multipart.max-request-size=100MB
6.本地存储就是将我们上传上来的文件,全部存储在服务器的本地磁盘目录中,但是这种方式子啊项目开发中用的非常少,因为:
1.如果我们将上传的这些文件,全部存储在服务器的磁盘目录中,那这些文件,最终在前端页面当中是没有办法直接访问的,就比如我们刚才把所有文件存放在了 C://本地存储 这个目录下,这个图片我们是没有办法在浏览器当中直接访问到的。
2.如果我们在项目中上传了大量的文件,都存储在服务器的本地磁盘中,而服务器的磁盘容量是有限的,如果服务器的磁盘存储空间满了,是不方便扩容的,特别是一些大型的互联网项目,要存储大量的图片,音频视频等文件,是不可能采用一台服务器来进行存储的。
3.最后一点:假如服务器的磁盘坏了,里面存储的所有数据就全部丢失了,这个损失非常大。
7.本地存储的常用方法(掌握哦):
//获取原始文件名
1.String getOriginalFileName();
//将接收的文件转存到磁盘文件中
2.void transferTo(File dest);
//获取文件的大小,单位:字节
3.long getSize();
//获取文件内容的字节数组
4.byte[] getBytes();
//获取接收到的文件内容的输入流
InputStream getInputStream();
8.现在项目开发中,怎么存储文件呢?
第一种:项目组自己搭建一套文件存储服务来存储上传的文件,比如可以通过FastDFS这种分布式文件系统,或者是通过MinIO这种对象存储服务来搭建集群,从而来解决刚才的问题。这种方式相对繁琐一些,需要自己买服务器,自己搭建。
第二种:使用现成的别的公司提供好的云服务来存储上传的文件,比如像腾讯云、阿里云、华为云、百度云等等,这种使用起来非常方便,而且安全可靠只不过需要支付一定的费用。