本文将为大家谈谈对Struts2上传文件的理解,并结合实际工作中出现的异常,进行讲解。

孙鑫的书《Struts2 深化详解》509页是关于约束Struts2上传文件的***长度的内容。 其间谈到fileUpload拦截器仅仅当文件上传到服务器上之后,才进行的文件类型和巨细判别。Struts2结构底层默许用的是apache的commons-fileupload组件对上传文件进行承受处理。

浅谈对Struts2上传文件的了解(struts2 文件上传)  struts2上传 文件 第1张

经过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来上传文件,对客户的操作体会可能是***的,可是,这样可能会导致服务器上有些挂空的文件(上传后历来没被用过),需求主意铲除的。

整个剖析下来,咱们说第二个问题基本上是无法防止的。

【修改引荐】

  1. 在Eclipse中开发struts应用程序
  2. 手把手教你在Eclipse中装备开发Struts
  3. Eclipse下开发struts完好处理乱码问题
  4. Struts相关布景介绍
  5. 运用Easy Struts for Eclipse开发Struts
转载请说明出处
知优网 » 浅谈对Struts2上传文件的了解(struts2 文件上传)

发表评论

您需要后才能发表评论