`
燕子~~
  • 浏览: 109814 次
  • 性别: Icon_minigender_2
  • 来自: 北京
社区版块
存档分类
最新评论

Struts的FormFile与Commons-FileUpload控件使用心得

阅读更多

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

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

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

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

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

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

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

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

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

      但是这里有两个类,CommonsMultipartRequestHandlerDiskMultipartRequestHandler。到底哪个是处理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 


 

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

  



   // 使用了DiskFileUpload。
 
// (Commons-FileUpload很老版本的一个上传实现类了,还在用?我的显示是Deprecated)

   DiskFileUpload upload 
= new DiskFileUpload();

   
// 上传最大值

   upload.setSizeMax((
int) getSizeMax(ac));

   
// 上传文件在内存中使用的缓冲区大小

   upload.setSizeThreshold((
int) getSizeThreshold(ac));

   
// 存在硬盘的什么地方,一般是默认

   upload.setRepositoryPath(getRepositoryPath(ac)); 


 

接着看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 

    //注意:这个类的类名是FileUploadBase.SizeLimitExceededException是个public//部类。上传的formdata总的数据超出了规定大小

         org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException 

         //注意:也是个内部类。这个才是上传的文件超出了规定大小

         org.apache.commons.fileupload.FileUploadBase.FileSizeLimitExceededException

         其它的,也看看吧:

         org.apache.commons.fileupload.FileUploadBase.FileUploadIOException

         org.apache.commons.fileupload.FileUploadBase.InvalidContentTypeException

         org.apache.commons.fileupload.FileUploadBase.IOFileUploadException

         org.apache.commons.fileupload.FileUploadBase.UnknownSizeException 

         要想获得尽可能仔细的数据就在处理的try/catch块里把上面的异常都catch一下,放到requestattribute里去就OK了。

         另外还有要说的是,最好用commons-fileupload控件的最新版本,因为DiskFileUpload这个类,commons-fileupload已经弃用了,取而代之的是ServletFileUpload类了,所以一定要注意!切记,切记….. 

         这是我写的CommonsMultipartRequestHandler替代类的public void handleRequest(HttpServletRequest request) throws ServletException函数: 

 

 



 public void handleRequest(HttpServletRequest request) throws ServletException

         
...


               
// Get the app config for the current request.

               ModuleConfig ac 
= (ModuleConfig) request.getAttribute(Globals.MODULE_KEY); 


               
// DiskFileItem工厂,主要用来设定上传文件的参数

               DiskFileItemFactory fileItemFactory 
= new DiskFileItemFactory();

               
// 上传文件所用到的缓冲区大小,超过此缓冲区的部分将被写入到磁盘

               fileItemFactory.setSizeThreshold((
intthis.getSizeThreshold(ac));

               
// 上传文件用到的临时文件存放位置

               fileItemFactory.setRepository(
this.getRepository(ac)); 


               
// 使用fileItemFactory为参数实例化一个ServletFileUpload对象

               
// 注意:该对象为commons-fileupload-1.2新增的类.

               
// 对于1.2以下的commons-fileupload版本并不存在此类.

               ServletFileUpload upload 
= new ServletFileUpload(fileItemFactory);

               
// 从session中读取对本次上传文件的最大值的限制

               String maxUploadSize 
= (String) request.getSession().getAttribute(BasicConstants.maxUploadSize);

               
// 获取struts-config文件中controller标签的maxFileSize属性来确定默认上传的限制

               
// 如果struts-config文件中controller标签的maxFileSize属性没设置则使用默认的上传限制250M.

               
long defaultOrConfigedMaxUploadSize = this.getSizeMax(ac); 


               
if (maxUploadSize != null && maxUploadSize != "")

               
...{

                     
// 如果maxUploadSize设定不正确则上传限制为defaultOrConfigedMaxUploadSize的值

                     
// 正确则为maxUploadSize转换成的字节数

                     upload.setSizeMax((
longthis.convertSizeToBytes(maxUploadSize, defaultOrConfigedMaxUploadSize));

               }


               
else

               
...{

                     
// 如果maxUploadSize没设置则使用默认的上传限制

                     upload.setSizeMax(defaultOrConfigedMaxUploadSize);

               }
 


               
// 从session中清空maxUploadSize

               request.getSession().removeAttribute(
"maxUploadSize"); 


               
// Create the hash tables to be populated.

               elementsText 
= new Hashtable();

               elementsFile 
= new Hashtable();

               elementsAll 
= new Hashtable(); 


               
// Parse the request into file items.

               List items 
= null;

               
// ServletFileUpload类来处理表单请求

               
// 抛出的异常为FileUploadException的子异常

               
// 如果捕获这些异常就将捕获的异常放到session中返回.

               
try

               
...{

                     items 
= upload.parseRequest(request);

               }


               
catch (FileUploadBase.SizeLimitExceededException e)

               
...{

                     
// 请求数据的size超出了规定的大小.

                     request.getSession().setAttribute(BasicConstants.baseSizeLimitExceededException, e);

                     
return;

               }


               
catch (FileUploadBase.FileSizeLimitExceededException e)

               
...<

分享到:
评论
1 楼 changqingonly 2008-11-07  
收藏先,谢过啦!

相关推荐

    (转)Struts的FormFile与Commons-FileUpload控件使用心得

    Struts的FormFile与Commons-FileUpload控件使用心得。

    自定义Controller的multipartClass类实现Struts上传

    Struts的FormFile与Commons-FileUpload控件使用心得 详细内容可以参考http://blog.csdn.net/lowkeysk/article/details/8296289

    [浪曦原创]Struts系列 第7讲 Struts的文件上传操作(zk001)

    在Struts中,文件上传主要依赖于`Commons FileUpload`库,这是Apache Commons项目的一部分,专门处理HTTP请求中的多部分数据,也就是通常所说的表单数据。以下是一些关于Struts文件上传的关键知识点: 1. **配置...

    [AB PLC例程源码][MMS_044666]Translation N-A.zip

    AB PLC例程代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!

    kolesar_3cd_01_0716.pdf

    kolesar_3cd_01_0716

    latchman_01_0108.pdf

    latchman_01_0108

    matlab程序代码项目案例:matlab程序代码项目案例MPC在美国高速公路场景中移动的车辆上的实现.zip

    matlab程序代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!

    pimpinella_3cd_01_0716.pdf

    pimpinella_3cd_01_0716

    petrilla_01_0308.pdf

    petrilla_01_0308

    [AB PLC例程源码][MMS_041452]Speed Controls in Plastic Extrusion.zip

    AB PLC例程代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!

    强化学习驱动下DeepSeek技术创新及其对AI发展的影响

    内容概要:本文档由张卓老师讲解,重点探讨DeepSeek的技术革新及强化学习对未来AI发展的重要性。文章回顾了AI的历史与发展阶段,详细解析Transformer架构在AI上半场所起到的作用,深入介绍了MoE混合专家以及MLA低秩注意机制等技术特点如何帮助DeepSeek在AI中场建立优势,并探讨了当前强化学习的挑战和边界。文档不仅提及AlphaGo和小游戏等成功案例来说明强化学习的强大力量,还提出了关于未来人工通用智能(AGI)的展望,特别是如何利用强化学习提升现有LLMs的能力和性能。 适用人群:本资料适宜对深度学习感兴趣的研究人员、开发者以及想要深入了解人工智能最新进展的专业人士。 使用场景及目标:通过了解最新的AI技术和前沿概念,在实际工作中能够运用更先进的工具和技术解决问题。同时为那些寻求职业转型或者学术深造的人提供了宝贵的参考。 其他说明:文中提到了许多具体的例子和技术细节,如DeepSeek的技术特色、RL的理论背景等等,有助于加深读者对于现代AI系统的理解和认识。

    有师傅小程序开源版v2.4.14+前端.zip

    有师傅小程序开源版v2.4.14 新增报价短信奉告 优化部分细节

    [AB PLC例程源码][MMS_047333]Motor Sequence Starter with timers to start.zip

    AB PLC例程代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!

    商城二级三级分销系统(小程序+后台含源码).zip

    商城二级三级分销系统(小程序+后台含源码).zip

    li_3ck_01b_0918.pdf

    li_3ck_01b_0918

    nicholl_3cd_01_0516.pdf

    nicholl_3cd_01_0516

    1995-2022年 网络媒体关注度、报刊媒体关注度与媒体监督相关数据.zip

    媒体关注度是一个衡量公众对某个事件、话题或个体关注程度的重要指标。它主要反映了新闻媒体、社交媒体、博客等对于某一事件、话题或个体的报道和讨论程度。 媒体监督的J-F系数(Janis-Fadner系数)是一种用于测量媒体关注度的指标,特别是用于评估媒体对企业、事件或话题的监督力度。J-F系数基于媒体报道的正面和负面内容来计算,从而为公众、研究者或企业提供一个量化工具,以了解媒体对其关注的方向和强度。 本数据含原始数据、参考文献、代码do文件、最终结果。参考文献中JF系数计算公式。 指标 代码、年份、标题出现该公司的新闻总数、内容出现该公司的新闻总数、正面新闻数全部、中性新闻数全部、负面新闻数全部、正面新闻数原创、中性新闻数原创、负面新闻数原创,媒体监督JF系数。

    [AB PLC例程源码][MMS_040315]Double INC and Double DEC of INT datatype.zip

    AB PLC例程代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!

    [AB PLC例程源码][MMS_047773]Convert Feet to Millimeters.zip

    AB PLC例程代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!

    [AB PLC例程源码][MMS_042349]How to read-write data to-from a PLC using OPC in Visual Basic 6.zip

    AB PLC例程代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!

Global site tag (gtag.js) - Google Analytics