我本人在网上找了很多关于文件上传进度获取的文章,普遍基于spring mvc 框架通过 fileupload 实现,对于spring boot 通过 fileupload 实现的帖子非常少,由于小弟学艺不精,虽然 spring boot 和 spring mvc 相差不大,只是配置方式的差别,还是搞了很久,上传此文章的目的是希望自己作为文本保留,以便日后查看备忘,并且希望通过我的例子可以帮助到其他人而已,如果各位大佬发现小弟对于某些知识有误解,还请不吝赐教,先谢谢各位前辈了!
写此篇文章之前我查了很多关于spring mvc 框架通过 fileupload 实现进度条的帖子和文章,在此对各位作者表示感谢!
本功能基于commons fileupload 组件实现
1.首先,不能在程序中直接使用 fileupload.parserequest(request)的方式来获取 request 请求中的 multipartfile 文件对象,原因是因为在 spring 默认的文件上传处理器 multipartresolver 指向的类commonsmultipartresolver 中就是通过 commons fileupload 组件实现的文件获取,因此,在代码中再次使用该方法,是获取不到文件对象的,因为此时的 request 对象是不包含文件的,它已经被commonsmultipartresolver 类解析处理并转型。
commonsmultipartresolver 类中相关源码片段:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
protected multipartparsingresult parserequest(httpservletrequest request) throws multipartexception { string encoding = determineencoding(request); fileupload fileupload = preparefileupload(encoding); try { list<fileitem> fileitems = ((servletfileupload) fileupload).parserequest(request); return parsefileitems(fileitems, encoding); } catch (fileuploadbase.sizelimitexceededexception ex) { throw new maxuploadsizeexceededexception(fileupload.getsizemax(), ex); } catch (fileuploadbase.filesizelimitexceededexception ex) { throw new maxuploadsizeexceededexception(fileupload.getfilesizemax(), ex); } catch (fileuploadexception ex) { throw new multipartexception( "failed to parse multipart servlet request" , ex); } } |
2.由于spring 中的 commonsmultipartresolver 类中并没有加入 processlistener 文件上传进度监听器,所以,直接使用 commonsmultipartresolver 类是无法监听文件上传进度的,如果我们需要获取文件上传进度,就需要继承 commonsmultipartresolver 类并重写 parserequest 方法,在此之前,我们需要创建一个实现了 processlistener 接口的实现类用于监听文件上传进度。
processlistener接口实现类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
import javax.servlet.http.httpsession; import org.apache.commons.fileupload.progresslistener; import org.springframework.stereotype.component; @component public class uploadprogresslistener implements progresslistener{ private httpsession session; public void setsession(httpsession session){ this .session=session; progressentity status = new progressentity(); session.setattribute( "status" , status); } /* * pbytesread 到目前为止读取文件的比特数 pcontentlength 文件总大小 pitems 目前正在读取第几个文件 */ @override public void update( long pbytesread, long pcontentlength, int pitems) { progressentity status = (progressentity) session.getattribute( "status" ); status.setpbytesread(pbytesread); status.setpcontentlength(pcontentlength); status.setpitems(pitems); } } |
progressentity 实体类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
import org.springframework.stereotype.component; @component public class progressentity { private long pbytesread = 0l; //到目前为止读取文件的比特数 private long pcontentlength = 0l; //文件总大小 private int pitems; //目前正在读取第几个文件 public long getpbytesread() { return pbytesread; } public void setpbytesread( long pbytesread) { this .pbytesread = pbytesread; } public long getpcontentlength() { return pcontentlength; } public void setpcontentlength( long pcontentlength) { this .pcontentlength = pcontentlength; } public int getpitems() { return pitems; } public void setpitems( int pitems) { this .pitems = pitems; } @override public string tostring() { float tmp = ( float )pbytesread; float result = tmp/pcontentlength* 100 ; return "progressentity [pbytesread=" + pbytesread + ", pcontentlength=" + pcontentlength + ", percentage=" + result + "% , pitems=" + pitems + "]" ; } } |
最后,是继承 commonsmultipartresolver 类的自定义文件上传处理类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
import java.util.list; import javax.servlet.http.httpservletrequest; import org.apache.commons.fileupload.fileitem; import org.apache.commons.fileupload.fileupload; import org.apache.commons.fileupload.fileuploadbase; import org.apache.commons.fileupload.fileuploadexception; import org.apache.commons.fileupload.servlet.servletfileupload; import org.springframework.beans.factory.annotation.autowired; import org.springframework.web.multipart.maxuploadsizeexceededexception; import org.springframework.web.multipart.multipartexception; import org.springframework.web.multipart.commons.commonsmultipartresolver; public class custommultipartresolver extends commonsmultipartresolver{ @autowired private uploadprogresslistener uploadprogresslistener; @override protected multipartparsingresult parserequest(httpservletrequest request) throws multipartexception { string encoding = determineencoding(request); fileupload fileupload = preparefileupload(encoding); uploadprogresslistener.setsession(request.getsession()); //问文件上传进度监听器设置session用于存储上传进度 fileupload.setprogresslistener(uploadprogresslistener); //将文件上传进度监听器加入到 fileupload 中 try { list<fileitem> fileitems = ((servletfileupload) fileupload).parserequest(request); return parsefileitems(fileitems, encoding); } catch (fileuploadbase.sizelimitexceededexception ex) { throw new maxuploadsizeexceededexception(fileupload.getsizemax(), ex); } catch (fileuploadbase.filesizelimitexceededexception ex) { throw new maxuploadsizeexceededexception(fileupload.getfilesizemax(), ex); } catch (fileuploadexception ex) { throw new multipartexception( "failed to parse multipart servlet request" , ex); } } } |
3.此时,所有需要的类已经准备好,接下来我们需要将 spring 默认的文件上传处理类取消自动配置,并将 multipartresolver 指向我们刚刚创建好的继承 commonsmultipartresolver 类的自定义文件上传处理类。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
import org.springframework.boot.springapplication; import org.springframework.boot.autoconfigure.enableautoconfiguration; import org.springframework.boot.autoconfigure.web.multipartautoconfiguration; import org.springframework.boot.web.servlet.servletcomponentscan; import org.springframework.context.annotation.bean; import org.springframework.context.annotation.componentscan; import org.springframework.context.annotation.configuration; import org.springframework.web.multipart.multipartresolver; import com.example.listener.custommultipartresolver; /* * 将 spring 默认的文件上传处理类取消自动配置,这一步很重要,没有这一步,当multipartresolver重新指向了我们定义好 * 的新的文件上传处理类后,前台传回的 file 文件在后台获取会是空,加上这句话就好了,推测不加这句话,spring 依然 * 会先走默认的文件处理流程并修改request对象,再执行我们定义的文件处理类。(这只是个人推测) * exclude表示自动配置时不包括multipart配置 */ @enableautoconfiguration(exclude = {multipartautoconfiguration.class}) @configuration @componentscan(basepackages = {"com.example"}) @servletcomponentscan(basepackages = {"com.example"}) public class uploadprogressapplication { /* * 将 multipartresolver 指向我们刚刚创建好的继承 commonsmultipartresolver 类的自定义文件上传处理类 */ @bean (name = "multipartresolver" ) public multipartresolver multipartresolver() { custommultipartresolver custommultipartresolver = new custommultipartresolver(); return custommultipartresolver; } public static void main(string[] args) { springapplication.run(uploadprogressapplication. class , args); } } |
至此,准备工作完成,我们再创建一个测试用的 controller 和 html 页面用于文件上传。
controller:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
import org.springframework.stereotype.controller; import org.springframework.web.bind.annotation.requestmapping; import org.springframework.web.bind.annotation.requestmethod; import org.springframework.web.bind.annotation.responsebody; import org.springframework.web.multipart.multipartfile; import org.springframework.web.servlet.modelandview; @controller @requestmapping ( "/uploadprogress" ) public class uploadcontroller { @requestmapping (value = "/showupload" , method = requestmethod.get) public modelandview showupload() { return new modelandview( "/uploadprogressdemo" ); } @requestmapping ( "/upload" ) @responsebody public void uploadfile(multipartfile file) { system.out.println(file.getoriginalfilename()); } } |
html:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<!doctype html> <html> <head> <meta charset= "utf-8" ></meta> <title>测试</title>这里写代码片 </head> <body> 这是文件上传页面 <form action= "/uploadprogress/upload" method= "post" enctype= "multipart/form-data" > <input type= "file" name= "file" /> <br/> <input type= "submit" value= "提交" /> </form> </body> </html> |
经本人测试,确实可以获取文件上传进度,前台页面修改进度条进度可以采用前台页面轮询的方式访问后台,在相应action中通过存储在session中的对象 status 来获取最新的上传进度并返回展示即可。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/qq_27607579/article/details/77914958