千家信息网

Struts2上传文件该怎样理解

发表于:2025-11-07 作者:千家信息网编辑
千家信息网最后更新 2025年11月07日,这篇文章主要为大家分析了Struts2上传文件该怎样理解的相关知识点,内容详细易懂,操作细节合理,具有一定参考价值。如果感兴趣的话,不妨跟着跟随小编一起来看看,下面跟着小编一起深入学习"Struts2
千家信息网最后更新 2025年11月07日Struts2上传文件该怎样理解

这篇文章主要为大家分析了Struts2上传文件该怎样理解的相关知识点,内容详细易懂,操作细节合理,具有一定参考价值。如果感兴趣的话,不妨跟着跟随小编一起来看看,下面跟着小编一起深入学习"Struts2上传文件该怎样理解"的知识吧。

Struts2框架底层默认用的是apache的commons-fileupload组件对上传文件进行接受处理。

通过struts.multipart.maxSize属性来对文件大小进行限定时,将直接影响到commons-fileupload组件的文件大小设定,默认是2M。当上传文件超过了这个尺寸时,将从commons-fileupload组件中抛出SizeLimitExceededException异常。Struts2上传文件拦截器捕获到这个异常后,将直接把该异常信息设置为Action级别的错误信息。

经过我的测试和对源代码的Debug,发现确实如孙鑫书中所言,如果上传文件大于2M时,在页面上就出现了一堆英文的错误信息,大致是:the request was rejected because its size....exceeds the configured maximum...并且在fieUpload中将来自MultiPartRequestWrapper型request对象的错误信息给加到了Action的错误中。

这时候,你在ApplicationResources.properties中自定义的上传文件过大的错误信息根本不起作用。原因就如书上所言,在底层commons-fileupload组件中就把异常给抛出来了文件根本没被上传,所以到了fileUpload拦截器时,根据取不到文件,当然也就没法对文件的类型和大小进行判断了。

然而,这个异常直接带来两个问题:

1、在页面上显示了英文的错误信息。这样的信息显然不是我们想要的。

2、由于错误的产生,原来页面上输入的其他文本内容也都不见了,也就是说params注入失败。

带着这两个问题,我们来探寻一下Struts2对于请求的处理过程。

注:这并不是一篇关于Struts2请求过程的介绍,主要是为了解决以上两个问题,才引起的简单分析。

首先当然我们要拿FilterDispatcher开刀。

在doFilter方法中调用了prepareDispatcherAndWrapRequest方法,为了包装出Struts2自己的request对象,在prepareDispatcherAndWrapRequest方法中调用Dispatcher类的wrapRequest方法,在这个方法里,会根据请求内容的类型(提交的是文本的,还是multipart/form-data格式),决定是使用tomcat的HttpServletRequestWrapper类分离出请求中的数据,还是使用Struts2的MultiPartRequestWrapper来分离请求中的数据。

注:向服务器请求时,数据是以流的形式向服务器提交,内容是一些有规则东东,我们平时在jsp中用request内置对象取parameter时,实际上是由tomcat的HttpServletRequestWrapper类分解好了的,无需我们再分解这些东西了。

当然,在这里,我们研究的是上传文件的情况,所以,由于form中设定的提交内容是媒体格式的,所以,Dispatcher类的wrapRequest方法会将请求交由MultiPartRequestWrapper类来处理。

MultiPartRequestWrapper这个类是Struts2的类,并且继承了tomcat的HttpServletRequestWrapper类,也是我们将用来代替HttpServletRequest这个类的类,看名字也知道,是对多媒体请求的包装类。

Struts2本身当然不会再造个轮子,来解析请求,而是交由Apache的commons-fileupload组件来解析了。

在MultiPartRequestWrapper的构造方法中,会调用MultiPartRequest(默认为JakartaMultiPartRequest类)的parse方法来解析请求。

在Struts2的JakartaMultiPartRequest类的parse方法中才会真正来调用commons-fileupload组件的ServletFileUpload类对请求进行解析,至此,Struts2已经实现了将请求转交commons-fileupload组件对请求解析的全过程。剩下的就是等commons-fileupload组件对请求解析完毕后,拿到分解后的数据,根据field名,依次将分解后的field名和值放到params(HashMap类型)里,同时JakartaMultiPartRequest类重置了HttpServletRequest的好多方法,比如熟知的getParameter、getParameterNames、getParameterValues,实际上都是从解析后得到的那个params对象里拿数据,在这个过程,commons-fileupload组件也乖乖的把上传的文件分析好了,JakartaMultiPartRequest也毫不客气的把分解后的文件一个一个的放到了files(HashMap类型)中,实际上此时,commons-fileupload组件已经所有要上传的文件上传完了。

至此,Struts2实现了对HttpServletRequest类的包装,当回到MultiPartRequestWrapper类后,再取一下上述解析过程中发生的错误,然后把错误加到了自己的errors列表中了。同样我们会发现在MultiPartRequestWrapper类中,也把HttpServletRequest类的好多方法重载了,毕竟是个包装类嘛,实际上对于上传文件的请求,在Struts2后期的处理中用到的request都是MultiPartRequestWrapper类对象,比如我们调用getParameter时,直接调用的是MultiPartRequestWrapper的getParameter方法,间接调的是JakartaMultiPartRequest类对象的getParameter方法。

注:从这里,我们就可以看出,JakartaMultiPartRequest是完全设计成可以替换的类了。

然后继续向回返,到了Dispatcher类的wrapRequest方法,直接把MultiPartRequestWrapper对象返回了,我们就终于回到了FilterDispatcher类的prepareDispatcherAndWrapRequest方法,此时,我们拿到了完全解析好了的request对象(MultiPartRequestWrapper类),该对象又进一步被返回到了FilterDispatcher类的doFilter方法,也就是回到了出发点,至此,doFilter中拿到的request对象就是一个将请求中的数据分解好的了HttpServletRequest对象,我们完全可以用getParameter方法取其中的数据了,同时,我们也可以用getFiles得到文件数组了。

doFilter方法中,会进一步调用actionMapper的getMapping方法对url进行解析,找出命名空间和action名等,以备后面根据配置文件调用相应的拦截器和action使用。

关于doFilter方法中下一步对Dispatcher类的serviceAction方法的调用,不再描述,总之在action被调用之前,会首先走到fileUpload拦截器(对应的是FileUploadInterceptor类),在这个拦截器中,会先看一下request是不是 MultiPartRequestWrapper,如果不是,就说明不是上传文件用的request,fildUpload拦截器会直接将控制权交给下一个拦截器;如果是,就会把request对象强转为MultiPartRequestWrapper对象,然后调用hasErrors方法,看看有没有上传时候产生的错误,有的话,就直接加到了Action的错误(Action级别的)中了。

另外,在fileUpload拦截器中会将MultiPartRequestWrapper对象中放置的文件全取出来,把文件、文件名、文件类型取出来,放到request的parameters中,这样到了params拦截器时,就可以轻松的将这些内容注入到Action中了,这也就是为什么fileUpload拦截器需要放在params拦截器前面的理由。在文件都放到request的parameters对象里之后,fileUpload拦截器会继续调用其他拦截器直到Action等执行完毕,他还要做一个扫尾的工作:把临时文件夹中的文件删除(这些文件是由commons-fileupload组件上传的,供你在自己的Action中将文件copy到指定的目录下,当action执行完了后,这些临时文件当然就没用了)。

你好,你还在看吗?呵呵,是不是太多了,也太乱了,没办法,Struts2就是这样的调用的。也不知道Struts2有没有公开其Sequence图,我是想画一个,不过,太懒,还是看着代码说说吧。

如果上面看烦了,也完全可以不看了,直接看下面的。

在上面一番分析之后,文件上传的全过程就结束了。
我们回到我们的问题上来。

先看***个:

1、在页面上显示了英文的错误信息。这显然不是我们想要的。

没办法了,commons-fileupload组件没想到国际化,在FileUploadInterceptor拦载器中,也没想着国际化,直接放到Action的错误中了,就没他事了,三种做法:

(1)在错误显示之前,把这条错误给换掉,应该难度不大,我没做留给你做了。

(2)或者重写一下JakartaMultiPartRequest这个类,把捕捉到的异常信息换成自己的,然后,通过Struts2的配置文件,把我们重写的这个parser换上去用。

(3)直接改commons-fileupload组件的类,换成中文的。

我具体说一下第(3)种做法:找到FileUploadBase类,把902行~908行改一下。
FileUploadException ex =
new SizeLimitExceededException(
"the request was rejected because"
+ " its size (" + pCount
+ ") exceeds the configured maximum"
+ " (" + pSizeMax + ")",
pCount, pSizeMax);
=>
FileUploadException ex = new SizeLimitExceededException(
"服务器拒绝了您的请求,原因可能是向服务器提交的数据发生了丢失。", pCount, pSizeMax);

把914行~918行改一下。
throw new SizeLimitExceededException(
"the request was rejected because its size ("
+ requestSize
+ ") exceeds the configured maximum ("
+ sizeMax + ")",
=>
throw new SizeLimitExceededException("服务器拒绝了您的请求,原因是提交数据量过大(通常是由于上传文件过大),请返回上页重试。"
+ " (***字节数:" + sizeMax / 1024
+ "K)", requestSize, sizeMax);


再看一下第二个问题。

2、由于错误的产生,原来页面上输入的内容也全部不见了,也就是说params注入失败。
关于这个问题我在javaeye上搜索到一篇文章(使用的commons-fileupload组件的jar包似乎比较老)。
http://www.javaeye.com/topic/197345

虽然按照此文,当上传失败时,能够将其他输入内容显示出来,但是这样做的结果是全部的文件肯定会上传到服务器上,也就是说,虽然是页面上报了文件因为太大,请求被拒绝的错,但是文件依然会被上传到服务器上,commons-fileupload组件根本没会去拦文件的上传。

在这里要说明一下,如果你不抛出这个异常,请求的流会继续向服务器上传,只有当整个流上传完了之后,commons-fileupload组件才能正确的分析出文件部分、文本部分。所以,在这里抛出异常是不得已的作法,如果不抛异常,后果是虽然页面报错,但文件还是会被传到服务器的上,这一步根本没挡住输入流的上传,如果没挡住的话,大家想想会有什么后果?

所以,综上所述,对于第二个问题,如果出现了这个异常,我们根本无法让原来输入的内容还显示出来的,因为commons-fileupload组件并没有解析全部的输入内容,直接给出异常了,到了params拦截器中,request里就是空的,根本取不到parameter,所以也就无法注入到Action中了。这种情况下,只能显示一个告知用户由于提交数据量过大,服务器拒绝了请求的错误信息,比较好的方法是,直接跳到一个专门的页面,提示用户,然后让用户点返回来再次输入,否则用户会感觉上传文件大就大吧,怎么连我输入的其他一些内容也没给保存住。当然,如果能用Ajax来上传文件,对客户的操作体验可能是极佳的,但是,这样可能会导致服务器上有些挂空的文件(上传后从来没被用过),需要想法清除的。

整个分析下来,我们说第二个问题基本上是无法避免的。

关于"Struts2上传文件该怎样理解"就介绍到这了,更多相关内容可以搜索以前的文章,希望能够帮助大家答疑解惑,请多多支持网站!

文件 方法 组件 错误 对象 拦截器 内容 服务器 服务 信息 数据 问题 页面 输入 根本 分析 也就是 类型 实际 实际上 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 win7数据库引擎服务失败 遗孀神山四个服务器选哪个 初级中学网络安全亮点 软件开发主流哪门语言 上海曲茂网络技术有限公司 linux 中转服务器 江苏诚信软件开发专业服务 宁波构建智慧小区软件开发 黑色沙漠没做完季节服务器 阳泉软件开发大概费用 网络安全层次体系包括网络层 互联网科技有限公司名称 科学技术研究所大数据库 厦门小程序软件开发有限公司 我的世界2b2t服务器最早的样子 数据库检查表 广东省海洋产业系统专利数据库 开源数据库抽取 斗战神数据库 北京新东方网络技术有限公司 魔兽怀旧服散人选哪个服务器 福建公安网络安全通报 数据库导入文件速度 中建二局oa服务器端口 html导出数据库图片路径 软件开发主流哪门语言 媒体服务器连接超时怎么解决 安徽一安网络技术有限公司 黑魂1重制版联机服务器 王者荣耀全部服务器维修
0