关于SringBoot中上传图片
目录
一、关于summernote富文本编辑器
在HTML的原生标签中,适用于输入文本的只有<input type="text" />
和<textarea>
这2种控件,这些控件都只能输入普通的文本,不支持复杂的排版,更加不可以显示图片,如果有“图文混排”的需求,就必须使用富文本编辑器,通常,富文本编辑都提供了文字的排版、插入/上传图片、上传附件等相关(也许某些富文本编辑也缺少一些排版功能),当开发时需要使用富文本编辑器时,可以上网找一个稳定的第三方富文本编辑器来使用。
summernote是一款比较普及的富文本编辑器,当用户使用summernote对输入的内容进行排版后,summernote会基于用户的操作整理出对应的HTML源代码,最终提交表单时,就会把这段HTML源代码提交到服务器并保存,后续,需要显示用户排版的正文,直接将这段HTML源代码插入到页面中即可!
summernote还支持在排版时插入图片!其作法是将图片的数据直接读取出来,并转换为Base64编码。
当尝试插入图片时,summernote将创建一个<img>
标签,并将该图片的Base64编码作为<img>
标签的src
属性的值,即可在网页中显示这张图片(可以随便照一张图片进行测试)。
summernote对图片的默认处理方式就是转换为Base64编码,使得图片是以文本的形式提交到服务器,最终这段文本会被记录在数据库中!
其实,这种做法是非常不合适的!会存在问题:
- 图片已经被转换为Base64编码了,成为“正文”的一部分,不便于管理上传的图片;
- 由于每张图片在转换为Base64编码后,得到的Base64编码都是非常长的字符串,将其直接存储到数据库中,会急剧增加数据库占用的存储空间,不便于数据库的管理!
所以,强烈建议“不要将任何附件存储到数据库中”。
正确的做法是:将图片直接以文件的形式上传到服务器端,在服务器端的表现也就是一个文件,同时,在服务器端的数据库中,记录上传的文件的路径,后续,当需要访问这个文件时,先查数据库得到文件的路径再进行访问即可!
二、基于SpringMVC的文件上传
1.创建项目
创建新的项目(不是原有的子模块项目)演示文件上传的开发过程:
创建web项目:
提示:如果使用的只是SpringMVC的项目,需要额外添加
commons-fileupload
依赖,在SpringBoot项目中不需要。
2.文件上传测试
关于文件上传,如果使用同步上传,在HTML页面部分,需要:
- 上传表单
<form>
标签必须使用POST
类型提交请求,必须配置enctype="multipart/form-data"
; - 使用
<input type="file" />
控件浏览上传的文件。
则在static
下创建index.html
文件,设计上传页面:
在使用控制器处理上传请求时,必须在控制器的处理请求的方法的参数列表中添加MultipartFile
接口类型的参数,它就是封装了上传的文件相关信息的对象,在处理过程中,调用该参数对象的transferTo()
方法,即可将客户端上传的文件保存到服务器的某个位置:
如果使用的是Linux或MacOS系统,可以自行确定用于保存文件的文件夹,打开终端,将文件夹拖拽进去,就可以看到该文件夹的路径,用于以上创建
File
对象的路径值中。
然后,在index.html
中,在<form>
补充配置action
属性值:
完成后,启动项目,即可测试上传,上传的文件会保存为以上控制器中指定的文件!
3.设置上传文件大小的限制
在SpringBoot项目中,默认限制上传的文件不允许超过1M(或10M),如果超过限制大小,上传时会出现错误,提示信息大致是:
org.apache.tomcat.util.http.fileupload.impl.SizeLimitExceededException: the request was rejected because its size (26030676) exceeds the configured maximum (10485760)
可以在任何配置类中添加配置:
以上配置就已经将上传文件的限制调整为50MB,只要实际上传的文件不超过这个大小,就不会出错了!
4.关于上传文件的文件名
以上示例代码中,将上传的文件保存到E:/1.jpg
,则无论上传什么样的文件,都将保存为E
盘下的1.jpg
,所以,即使上传的是一个zip
压缩包,也会保存为1.jpg
,但无法使用图片查看工具打开它!并且,由于保存的文件始终名为1.jpg
,所以,后续上传的文件会覆盖前序上传的文件!所以,目前需要解决的问题有:
- 文件会覆盖;
- 文件的扩展名不准。
先将原代码中File
对象的创建过程进行修改,把问题拆解开来:
如果要解决后续上传的文件会覆盖前序上传的文件的问题,只需要保证每次上传时使用的文件名均不相同即可,可以采用的策略有:
- 使用时间作为文件名的一部分;
- 使用随机数作为文件名的一部分;
- 使用当前登录的用户的唯一标识(例如id、用户名、手机号码、邮箱等)作为文件名的一部分。
- 综合使用以上策略。
UUID可以保证唯一性,它的算法也是基于时间、随机数、芯片的ID来计算得到的!
例如可以:
另外,关于“扩展名不合理”的问题,保存每个上传的文件时,所使用的扩展名应该与其最原始的名称相同,也就是说:客户端在浏览文件时,该文件的扩展名是什么,保存到服务器端时也使用同样的扩展名!
调用MultipartFile
的String getOriginalFilename()
方法即可获取文件的原始文件名(上传的文件在客户端设备中的名称),然后,从中截取扩展名并使用即可:
5.关于MultipartFile的API
关于MultipartFile
的常用API有:
-
String getOriginalFilename()
:获取上传的文件的原始文件名; -
void transferTo(File dest) throws IOException, IllegalStateException
:保存上传的文件; -
boolean isEmpty()
:判断上传的文件是否为空,仅当没有选择需要上传的文件,或选择的文件是0字节的将视为“空文件”,当上传的文件为空时返回true
,否则返回false
; -
long getSize()
:获取上传的文件的大小; -
String getContentType()
:获取上传的文件的MIME类型。
基于以上API,可以制定一些上传时的判断标准,例如:
在控制器中,收到文件的第1时间就执行相关的判断:
就可以阻止客户端提交错误的文件到服务器端!
6.关于保存上传文件的文件夹
注意:上传文件的目的都是为了后续下载这个文件!所以,上传的文件必须是可以被下载的!
在SpringBoot项目中,默认的静态资源目录是resources/static
,如果把文件上传到这个位置,将可以被下载,则启动项目后,可以通过 http://localhost:8080/xxx.jpg 就可以访问这张图片(还是,随便找一张图片即可测试)。
当然,把上传的文件保存到static
文件夹下也是不现实的,当项目开发完成后,可以将项目打包为一个jar文件,服务器上运行的程序就是这个jar文件,但是,很显然用户不可能将图片或其它文件上传到这个jar包中去!
SpringBoot的静态资源目录是可以自定义的,并且可以自定义多个,在application.properties
中,通过spring.resource.static-
属性即可配置静态资源目录!
则先在E(看个人习惯选择)盘创建static-resource
文件夹,用于存放项目的静态资源,然后,在application.properties
中进行配置:
注意:原本的static
文件夹应该依然是静态资源文件夹!
然后,在控制器中,将上传的文件夹设置为以上配置成静态资源的文件夹:
重启项目后,再次上传文件,就可以在E:/static-resource
文件夹中看到上传的文件:
并且,可以通过浏览器直接访问这张图片: