读书人

【转】struts1.2 文件下传处理(引自ja

发布时间: 2012-11-18 10:51:21 作者: rapoo

【转】struts1.2 文件上传处理(引自javablog)

前一段时间刚来公司,看到一个项目中以前有人写的struts代码。是使用了FormFile来处理关于文件上传的模块。但是用力一段时间后,发现出问题了。写完的这个模块,上传文件是没有问题的,但是当服务器的空间较小的时候,穿一个比较大的文件就出问题了,文件还没有上传完,就抛出一个错误的页面,报告上传模块出了问题,而且是Tomcat默认的出错页面。

??????于是想办法,修改,查看源代码,发现原来写这段代码的人是默认等文件上传完以后进入Action了才判断文件大小是否超出了限制。

??????但是,默认配置下使用struts的FormFile比较特殊,FormFile是struts包对外的一个接口,而且org.apache.struts.upload包是使用的commons-fileupload-1.0进行的封装。如果使用了它来实现文件上传的功能,则必须是FormFile对象在被初始化以后才能使用,那什么时候它才是被初始化的呢?

??????答案是:在进入Action之前就已经初始化好了!

??????因此,原先的设计:在Action中判断文件大小是根本不能在上传过程中起到提示作用的,因为这时候文件已经上传完了。而且这个设计还有一个确定就是不能捕获上传过程中出现的任何问题。也就是说:在Action里我们得到的FormFile对象是上传的一个结果,而不是一个未上传好就可以使用的对象!

??????那如何控制FormFile上传的过程呢?显然,在Action里处理已经不能奏效了,想想别的办法,让我们翻看一下Struts的源代码找找灵感吧。?

??????这是struts1.1的org.apache.struts.upload包的描述:

【转】struts1.2 文件下传处理(引自javablog)

?从上图我们可以看出有有CommonsMultipartRequestHandler和DiskMultipartRequestHandler两个类实现了MultipartRequestHandler接口。

??????大家都知道,Commons-fileupload控件在上传的时候,使用的enctype为:enctype="multipart/form-data",因此不难看出MultipartRequestHandler的实现就是来处理enctype="multipart/form-data"这样的post请求的。

??????但是这里有两个类,CommonsMultipartRequestHandler和DiskMultipartRequestHandler。到底哪个是处理FormFile的上传的呢?这个问题应该从org.apache.struts.config包里来找。

org.apache.struts.config包是用来处理struts配置文件的数据的包。找到org.apache.struts.config. ControllerConfig

??????看这几行:

?



??/**

?????*?The?fully?qualified?Java?class?name?of?the?MultipartRequestHandler

?????*?class?to?be?used.

?????*/

????protected?String?multipartClass?=

????????"org.apache.struts.upload.CommonsMultipartRequestHandler";?


????public?String?getMultipartClass()?{

????????return?(this.multipartClass);

????}?
????public?void?setMultipartClass(String?multipartClass)?{

????????if?(configured)?{

????????????throw?new?IllegalStateException("Configuration?is?frozen");

????????}

????????this.multipartClass?=?multipartClass;

???}?


?

这几行的意思很明白,如果没有在配置文件中配置MultipartRequestHandler实现类的绝对路径,那就使用org.apache.struts.upload.CommonsMultipartRequestHandler类默认处理

???^_^,这就是关键了:struts是默认使用org.apache.struts.upload.CommonsMultipartRequestHandler类来处理FormFile指定的上传文件的

???马上转到org.apache.struts.upload.CommonsMultipartRequestHandler来看看:

?



/**

???*默认文件上传的大小是250M

???*/

???public?static?final?long?DEFAULT_SIZE_MAX?=?250?*?1024?*?1024;?

???/**

???*上传文件在内存中使用的缓冲区大小,超过次数值的数据写入硬盘。

???*/

???public?static?final?int?DEFAULT_SIZE_THRESHOLD?=?256?*?1024;?

?还有,最最重要的实现方法:

/**

???*?Parses?the?input?stream?and?partitions?the?parsed?items?into?a?set?of

???*?form?fields?and?a?set?of?file?items.?In?the?process,?the?parsed?items

???*?are?translated?from?Commons?FileUpload?<code>FileItem</code>?instances

???*?to?Struts?<code>FormFile</code>?instances.

???*

???*?@param?request?The?multipart?request?to?be?processed.

???*

???*?@throws?ServletException?if?an?unrecoverable?error?occurs.

??????????????就是这个函数处理上传文件的request,把request交给

??????????????Commons?FileUpload?控件处理,并解析FileItem转换成Struts的FormFile。

???*/

???public?void?handleRequest(HttpServletRequest?request)

???????????????throws?ServletException?

再看看这个函数内部是怎么实现的吧?

【转】struts1.2 文件下传处理(引自javablog)???//?使用了DiskFileUpload。
【转】struts1.2 文件下传处理(引自javablog)?//?(Commons-FileUpload很老版本的一个上传实现类了,还在用?我的显示是Deprecated)
【转】struts1.2 文件下传处理(引自javablog)
【转】struts1.2 文件下传处理(引自javablog)???DiskFileUpload?upload?=?new?DiskFileUpload();
【转】struts1.2 文件下传处理(引自javablog)
【转】struts1.2 文件下传处理(引自javablog)???//?上传最大值
【转】struts1.2 文件下传处理(引自javablog)
【转】struts1.2 文件下传处理(引自javablog)???upload.setSizeMax((int)?getSizeMax(ac));
【转】struts1.2 文件下传处理(引自javablog)
【转】struts1.2 文件下传处理(引自javablog)???//?上传文件在内存中使用的缓冲区大小
【转】struts1.2 文件下传处理(引自javablog)
【转】struts1.2 文件下传处理(引自javablog)???upload.setSizeThreshold((int)?getSizeThreshold(ac));
【转】struts1.2 文件下传处理(引自javablog)
【转】struts1.2 文件下传处理(引自javablog)???//?存在硬盘的什么地方,一般是默认
【转】struts1.2 文件下传处理(引自javablog)
【转】struts1.2 文件下传处理(引自javablog)???upload.setRepositoryPath(getRepositoryPath(ac));?
【转】struts1.2 文件下传处理(引自javablog)
【转】struts1.2 文件下传处理(引自javablog)
【转】struts1.2 文件下传处理(引自javablog)

?

接着看handleRequest如何处理request的:

?

?



?????//?Parse?the?request?into?file?items.

???????????List?items?=?null;

???????????try?{

???????????????items?=?upload.parseRequest(request);

???????????}??????????//这里是关键:上传过程中出了超出最大值的异常了,如何处理?

?????catch?(DiskFileUpload.SizeLimitExceededException?e)?{?

???????????????//?Special?handling?for?uploads?that?are?too?big.

???????????????request.setAttribute(

???????????????????????MultipartRequestHandler.ATTRIBUTE_MAX_LENGTH_EXCEEDED,

???????????????????????Boolean.TRUE);

???????????????return;

???????????}?

???????????????//出了其他异常,如enctype不对,磁盘空间不足怎么办?

???catch?(FileUploadException?e)?{

???????????????log.error("Failed?to?parse?multipart?request",?e);

???????????????throw?new?ServletException(e);

???????????}

?

?这次一目了然了:

?????????Struts根本没有把上传过程中出的超出最大值的异常带到Action,因为那是不可能的,而是把它放到了rquestAttribute

?????????而出了其他异常如enctype不对,磁盘空间不足怎么办?很遗憾,Struts没有去处理它,而是log了一下,抛给了上一层了。?

?????????那我一定要获得这些全部异常咋办呢?没办法,自己定制一个MultipartRequestHandler吧,那样就能彻底解决上传过程中的控制问题了!

?????????在此之前,我们得先去最新版的commons-fileupload控件看看上传过程中可能抛出多少异常?

?????????//所有上传异常的父类

?????????org.apache.commons.fileupload.FileUploadException?

读书人网 >软件架构设计

热点推荐