SpringBoot超大文件上传如何实现?
不管什么技术,超大文件上传(超出一次tcp上限)都是要做分片和合并的,无非是自己做还是找控件的差别。
另外,springboot是后台接收,前端实现是由前端框架负责,比如vue。
以下是Vue+Springboot实现大文件上传的二种方式:
1、利用ElementUI的el-upload
优点:
简单方便,可以实现功能
缺点:
上传速度太慢,没有分片单线程上传1个G的文件即使在局域网也很慢
上传显示的进度条不准确,进度已经100%了,但是还需要等很久在服务端才生成完文
2、利用百度的webuploader
优点:
WebUploader是网上比较推荐的方式,分片上传大文件速度很快。
缺点:
必须依赖 jquery
不能 import 导入,只能在 index.html 里包含。
3. 利用vue-uploader
vue-uploader 是基于vue的uploader组件,缺省就是分片上传。
通过npm安装,基本流程参考github上的说明即可。
上传的基本原理就是前端根据文件大小,按块大小分成很多块,然后多线程同时上传多个块,同时调用服务端的上传接口,服务端会生成很多小块小块的文件。
所有块都上传完之后,前端再调用一个服务端的merge接口,服务端把前面收到的所有块文件按顺序组合成最终的文件。
springboot多文件上传
MultipartFile提供了以下方法来获取上传文件的信息:
getOriginalFilename,获取上传的文件名字;
getBytes,获取上传文件内容,转为字节数组;
getInputStream,获取一个InputStream;
isEmpty,文件上传内容为空,或者根本就没有文件上传;
getSize,文件上传的大小。
transferTo(File dest),保存文件到目标文件系统;
同时上传多个文件,则使用MultipartFile数组类来接受多个文件上传:
//多文件上传 @RequestMapping(value = "/batch/upload", method = RequestMethod.POST)
@ResponseBody public String handleFileUpload(HttpServletRequest request){
ListMultipartFile files = ((MultipartHttpServletRequest) request)
.getFiles("file");
MultipartFile file = null;
BufferedOutputStream stream = null;
for (int i = 0; i files.size(); ++i) {
file = files.get(i);
if (!file.isEmpty()) {
try {
byte[] bytes = file.getBytes();
stream = new BufferedOutputStream(new FileOutputStream(
new File(file.getOriginalFilename())));
stream.write(bytes);
stream.close();
} catch (Exception e) {
stream = null;
return "You failed to upload " + i + " = " + e.getMessage();
}
} else {
return "You failed to upload " + i
+ " because the file was empty.";
}
}
return "upload successful";
}
可以通过配置application.properties对SpringBoot上传的文件进行限定默认为如下配置:
spring.servlet.multipart.enabled=true
spring.servlet.multipart.file-size-threshold=0
spring.servlet.multipart.location=
spring.servlet.multipart.max-file-size=1MB
spring.servlet.multipart.max-request-size=10MB
spring.servlet.multipart.resolve-lazily=false
enabled默认为true,既允许附件上传。
file-size-threshold限定了当上传文件超过一定长度时,就先写到临时文件里。有助于上传文件不占用过多的内存,单位是MB或KB,默认0,既不限定阈值。
location指的是临时文件的存放目录,如果不设定,则web服务器提供一个临时目录。
max-file-size属性指定了单个文件的最大长度,默认1MB,max-request-size属性说明单次HTTP请求上传的最大长度,默认10MB.
resolve-lazily表示当文件和参数被访问的时候再被解析成文件。
springboot上传文件写入数据库
首先导入了相应的jar包
!--thymeleaf--dependency
groupIdorg.thymeleaf/groupId
artifactIdthymeleaf-spring5/artifactId/dependencydependency
groupIdorg.thymeleaf.extras/groupId
artifactIdthymeleaf-extras-java8time/artifactId/dependency!--数据库连接--dependency
groupIdmysql/groupId
artifactIdmysql-connector-java/artifactId/dependency!--mybatis整合springboot--dependency
groupIdorg.mybatis.spring.boot/groupId
artifactIdmybatis-spring-boot-starter/artifactId
version2.1.2/version/dependency!--druid数据源--dependency
groupIdcom.alibaba/groupId
artifactIddruid/artifactId
version1.1.22/version/dependency1234567891011121314151617181920212223242526272829
对数据源,mybatis,和上传文件进行配置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource username: root password: shw123zxc url: jdbc:mysql://localhost:3306/mybatis?useSSL=trueuseUnicode=truecharacterEncoding=UTF-8serverTimezone=UTC driver-class-name: com.mysql.cj.jdbc.Driver servlet:
multipart:
max-request-size: 10MB #上传文件的最大总大小
max-file-size: 10MB#上传单个文件的最大大小mybatis:
type-aliases-package: cn.codewei.pojo mapper-locations: classpath:/mapper/*.xml1234567891011121314
然后写一个文件上传的html,注意表单的==enctype属性要设置为multipart/form-data==
!DOCTYPE htmlhtml lang="en"head
meta charset="UTF-8"
titleTitle/title/headbody
h1文件上传/h1
form method="post" enctype="multipart/form-data" action="/upload"
input type="file" name="file"
input type="submit" value="上传"
/form/body/html1234567891011121314
然后写一个Mapper和对应的Mapper.xml和service
@Mapper@Repositorypublic interface PhotoMapper {
// 向数据库中添加图片
public int addPhoto(Photo photo);
// 从数据库中取出图片
public Photo getPhotoById(@Param("id") int id);}123456789
?xml version="1.0" encoding="UTF-8" ?!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
""mapper namespace="cn.codewei.mapper.PhotoMapper"
insert id="addPhoto" parameterType="photo"
insert into image values (#{id},#{photo},#{photo_name},#{photo_type}) /insert
select id="getPhotoById" resultType="photo"
select * from image where id=#{id} /select/mapper123456789101112
在Controller中进行调用
上传
@Autowiredprivate PhotoService photoService;@Autowiredprivate Photo photo;@PostMapping("/upload")@ResponseBodypublic String upload(@RequestParam("file") MultipartFile file, HttpServletRequest request) throws IOException {
byte[] bytes = file.getBytes();
photo.setPhoto(bytes);
photo.setPhoto_name(file.getOriginalFilename());
photo.setPhoto_type(".jpg");
photoService.addPhoto(photo);
return "上传成功!";}123456789101112131415161718
取出,在页面中显示
@RequestMapping("/getPhoto")public String getImage(HttpServletResponse response) throws IOException {
Photo photo = photoService.getPhotoById(1);
byte[] photo1 = photo.getPhoto();
ServletOutputStream os = response.getOutputStream();
os.write(photo1);
os.close();
return "";}123456789
!DOCTYPE htmlhtml lang="en"head
meta charset="UTF-8"
titleTitle/title/headbody
h1首页/h1
img src="/getPhoto" width="200px" height="200px"/body/html
SpringBoot文件上传的使用以及原理
这是因为上传的内容超出了 SpringBoot 默认配置的上传文件的大小 1MB
通过该注解可以指导,在配置类中修改 spring.servlet.multipart 下的配置项即可
可以看到有一个 max-file-size 的配置项,默认是"1MB",说明修改该配置项为想要限制的大小即可,这里我改成10MB,而 max-request-size 是多文件上传时,总的一次提交的最大大小,默认是10MB,我改成100MB
可以看到,在选择使用哪个解析器去处理请求(也就是根据映射关系,找到请求的 url 对应的用 @RequestMapping 注解过的方法)之前,会先调用 checkMultipart() 检查一下当前的请求是否是一个文件上传的请求
前面已经分析了,文件上传字段的注解是 @RequestPart ,而相应的解析器是 RequestPartMethodArgumentResolver ,所以我们需要先找到该解析器的执行流程先
总体原理就是根据注解的类型以及注解中的参数,构造出一个映射,这个映射是以注解 @RequestPart 中的 name 为key,而上传的文件为value,根据这个映射就可以给相应的参数赋值,这样我们就可以从 MultipartFile 对象中调用相应方法对上传的文件做想要的操作了
Vue + SpringBoot 上传 Excel 文件
Step2: 引用组件,指定上传方法
这里对 axios 做了封装,可以直接调用 api 中对应的方法:
Controller 层接收请求:
Service 层处理 Excel 文件,取出数据做相应的业务处理。
到此,Vue 上传文件到后端完成,效果如下: