来自:http://www.iteye.com/topic/212566
  前一段时间刚来公司,看到一个项目中以前有人写的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包的描述:
    (见附件)
    从上图我们可以看出有有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。

看这几行:

Java代码  
  1. protected String multipartClass =
  2. "org.apache.struts.upload.CommonsMultipartRequestHandler";
  3. public String getMultipartClass()
  4. {
  5. return (this.multipartClass);
  6. }
  7. public void setMultipartClass(String multipartClass)
  8. {
  9. if (configured)
  10. {
  11. throw new IllegalStateException("Configuration is frozen");
  12. }
  13. this.multipartClass = multipartClass;
  14. }

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

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

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

Java代码  
  1. public static final long DEFAULT_SIZE_MAX = 250 * 1024 * 1024;
  2. public static final int DEFAULT_SIZE_THRESHOLD = 256 * 1024;

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

Java代码  
  1. public void handleRequest(HttpServletRequest request) throws ServletException

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

Java代码  
  1. // 使用了DiskFileUpload。
  2. // (Commons-FileUpload很老版本的一个上传实现类了,还在用?我的显示是Deprecated)
  3. DiskFileUpload upload = new DiskFileUpload();
  4. // 上传最大值
  5. upload.setSizeMax((int) getSizeMax(ac));
  6. // 上传文件在内存中使用的缓冲区大小
  7. upload.setSizeThreshold((int) getSizeThreshold(ac));
  8. // 存在硬盘的什么地方,一般是默认
  9. pload.setRepositoryPath(getRepositoryPath(ac));

接着看handleRequest如何处理request的:

Java代码  
  1. // Parse the request into file items.
  2. List items = null;
  3. try
  4. {
  5. items = upload.parseRequest(request);
  6. }
  7. //这里是关键:上传过程中出了超出最大值的异常了,如何处理?
  8. catch (DiskFileUpload.SizeLimitExceededException e)
  9. {
  10. // Special handling for uploads that are too big
  11. request.setAttribute(
  12. MultipartRequestHandler.ATTRIBUTE_MAX_LENGTH_EXCEEDED,
  13. Boolean.TRUE);
  14. return;
  15. }
  16. //出了其他异常,如enctype不对,磁盘空间不足怎么办?
  17. catch (FileUploadException e)
  18. {
  19. log.error("Failed to parse multipart request", e);
  20. throw new ServletException(e);
  21. }

这次一目了然了:

Struts根本没有把上传过程中出的超出最大值的异常带到Action,而是把它放到了rquest的Attribute里。
   而出了其他异常如enctype不对,磁盘空间不足怎么办?很遗憾,Struts没有去处理它,而是log了一下,抛给了上一层了。

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

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

Java代码  
  1. //所有上传异常的父类
  2. org.apache.commons.fileupload.FileUploadException
  3. //注意:这个类的类名是FileUploadBase.SizeLimitExceededException是个public内
  4. //部类。上传的formdata总的数据超出了规定大小
  5. org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException
  6. //注意:也是个内部类。这个才是上传的文件超出了规定大小
  7. org.apache.commons.fileupload.FileUploadBase.FileSizeLimitExceededException
  8. //其它的,也看看吧:
  9. org.apache.commons.fileupload.FileUploadBase.FileUploadIOException
  10. org.apache.commons.fileupload.FileUploadBase.InvalidContentTypeException
  11. org.apache.commons.fileupload.FileUploadBase.IOFileUploadException
  12. org.apache.commons.fileupload.FileUploadBase.UnknownSizeException

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

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

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

Java代码  
  1. public void handleRequest(HttpServletRequest request) throws ServletException
  2. {
  3. // Get the app config for the current request.
  4. ModuleConfig ac = (ModuleConfig) request.getAttribute(Globals.MODULE_KEY);
  5. // DiskFileItem工厂,主要用来设定上传文件的参数
  6. DiskFileItemFactory fileItemFactory = new DiskFileItemFactory();
  7. // 上传文件所用到的缓冲区大小,超过此缓冲区的部分将被写入到磁盘
  8. fileItemFactory.setSizeThreshold((int) this.getSizeThreshold(ac));
  9. // 上传文件用到的临时文件存放位置
  10. fileItemFactory.setRepository(this.getRepository(ac));
  11. // 使用fileItemFactory为参数实例化一个ServletFileUpload对象
  12. // 注意:该对象为commons-fileupload-1.2新增的类.
  13. // 对于1.2以下的commons-fileupload版本并不存在此类.
  14. ServletFileUpload upload = new ServletFileUpload(fileItemFactory);
  15. // 从session中读取对本次上传文件的最大值的限制
  16. String maxUploadSize = (String)request.getSession().
  17. getAttribute(BasicConstants.maxUploadSize);
  18. // 获取struts-config文件中controller标签的maxFileSize属性来确定默认上传的限制
  19. // 如果struts-config文件中controller标签的maxFileSize属性没设置则使用默认的上传限制250M.
  20. long defaultOrConfigedMaxUploadSize = this.getSizeMax(ac);
  21. if (maxUploadSize != null && maxUploadSize != "")
  22. {
  23. // 如果maxUploadSize设定不正确则上传限制为defaultOrConfigedMaxUploadSize的值
  24. // 正确则为maxUploadSize转换成的字节数
  25. upload.setSizeMax((long) this.convertSizeToBytes(
  26. maxUploadSize, defaultOrConfigedMaxUploadSize));
  27. }
  28. else
  29. {
  30. // 如果maxUploadSize没设置则使用默认的上传限制
  31. upload.setSizeMax(defaultOrConfigedMaxUploadSize);
  32. }
  33. // 从session中清空maxUploadSize
  34. request.getSession().removeAttribute("maxUploadSize");
  35. // Create the hash tables to be populated.
  36. elementsText = new Hashtable();
  37. elementsFile = new Hashtable();
  38. elementsAll = new Hashtable();
  39. // Parse the request into file items.
  40. List items = null;
  41. // ServletFileUpload类来处理表单请求
  42. // 抛出的异常为FileUploadException的子异常
  43. // 如果捕获这些异常就将捕获的异常放到session中返回.
  44. try
  45. {
  46. items = upload.parseRequest(request);
  47. }
  48. catch (FileUploadBase.SizeLimitExceededException e)
  49. {
  50. // 请求数据的size超出了规定的大小.
  51. request.getSession().setAttribute(
  52. BasicConstants.baseSizeLimitExceededException, e);
  53. return;
  54. }
  55. catch (FileUploadBase.FileSizeLimitExceededException e)
  56. {
  57. // 请求文件的size超出了规定的大小.
  58. request.getSession().setAttribute(
  59. BasicConstants.baseFileSizeLimitExceededException, e);
  60. return;
  61. }
  62. catch (FileUploadBase.IOFileUploadException e)
  63. {
  64. // 文件传输出现错误,例如磁盘空间不足等.
  65. request.getSession().setAttribute(
  66. BasicConstants.baseIOFileUploadException, e);
  67. return;
  68. }
  69. catch (FileUploadBase.InvalidContentTypeException e)
  70. {
  71. // 无效的请求类型,即请求类型enctype != "multipart/form-data"
  72. request.getSession().setAttribute(
  73. BasicConstants.baseInvalidContentTypeException, e);
  74. return;
  75. }
  76. catch (FileUploadException e)
  77. {
  78. // 如果都不是以上子异常,则抛出此总的异常,出现此异常原因无法说明.
  79. request.getSession().setAttribute(
  80. BasicConstants.FileUploadException, e);
  81. return;
  82. }
  83. // Partition the items into form fields and files.
  84. Iterator iter = items.iterator();
  85. while (iter.hasNext())
  86. {
  87. FileItem item = (FileItem) iter.next();
  88. if (item.isFormField())
  89. {
  90. addTextParameter(request, item);
  91. }
  92. else
  93. {
  94. addFileParameter(item);
  95. }
  96. }
  97. }

其它部分均未做什么大改变。

好了,替代类写好了,我们怎么去用呢?

这样:在struts-config文件中写配置:

Xml代码  
  1. <</span>controller>
  2. <</span>set-property property="multipartClass"
  3. value="com.amplesky.commonmodule.struts.AmpleskyMultipartRequestHandler" />
  4. <</span>set-property property="maxFileSize" value="15M" />
  5. <</span>set-property property="memFileSize" value="5M" />
  6. </</span>controller>

好了!现在我们再用FormFile上传文件,可以在上传之前动态设置或者从配置文件设置上传文件的大小,一旦上传过程中出现了异常,就会被写入request的attributs里。当进入action的时候,通过在Action里获取异常就可以判断上传过程中出了什么问题了,而且在上传过程中文件一旦超出了规定大小,或者磁盘大小不足的情况会立即中断上传的。这样我们的功能就实现了。

最后,感慨一下,

1.感觉commons-fileupload还是挺好用的,但是FormFile的使用不大好,基本上误导能力很强,网上关于FormFile的资料说明很少,以上这些都是我自己摸索出来的。

2.Struts 1都到了1.3版本了,但是对于FormFile的实现依然使用commons-fileupload-1.0版本的DiskFileUpload类,可 见更新也不怎么样。其实我觉得这是apache大部分开源工具的一个通病:更新确实不怎么快,commons框架里边的源代码和jar包不一致,还有很多 是2004或者2003年的…要命的是居然不支持javase5的新特性????

3. 认为把异常放到request的attributs里不好,曾经尝试过抛出异常然后通过配置exception-controller来抓去异常处理,但 是抓不到,怎么都抓不到,后来翻了大半天源码才发现:struts在处理异常请求的时候将出现的ServletException和IOExcepton 都交给了上层去处理了,根本不会抛出来。所以这两种异常是抓不到的。

Struts的FormFile与Commons-FileUp…相关推荐

  1. java struts2 excel上传_文件上传下载——通过struts的FormFile上传单个excel文件

    通过struts的FormFile上传单个excel文件 思路: 1.通过struts的FormFile获取File(这个文件的路径是"客户端的选择的路径地址") 2.将客户端的文 ...

  2. 巧建Spring Web的Maven项目来解决java.lang.NoClassDefFoundError: org/apache/commons/fileup

    有很多同学都会遇到下面这种错误 java.lang.NoClassDefFoundError: org/apache/commons/fileupload/FileItemFactory 这个错误很简 ...

  3. java中formfile,基于Struts FormFile上传文件

    基于Struts文件上传(FormFile)详解 Struts中FormFile用于文件进行上传 1.在jsp文件中进行定义 名字: 头像: 2.在Form表单中定义FormFile /* * Gen ...

  4. java formfile_基于Struts文件上传(FormFile)详解

    Struts中FormFile用于文件进行上传 1.在jsp文件中进行定义 名字: 头像: 2.在Form表单中定义FormFile /* * Generated by MyEclipse Strut ...

  5. 一个简单的struts的例子

    index.jsp 代码 <%@ page language="java" import="java.util.*" pageEncoding=" ...

  6. 关于文件上传,我要向struts提点意见

    前两天,公司一同事要做一个包含有文件上传的功能模块,问我采取哪种技术比较好.由于项目的技术架构是ssi,于是就建议他直接使用struts提供的FormFile.可是在他动手开发的过程中,却遇到了一些实 ...

  7. 深入全面阐释Struts 2的方方面面

    <深入浅出Struts 2> 一.Struts概述 Struts是一个用来开发Model 2应用程序的框架.这个框架可以提高开发工作的速度,因为它提供的下面这些功能解决了Web应用程序开发 ...

  8. 在Struts 2中实现文件上传

    前一阵子有些朋友在电子邮件中问关于Struts 2实现文件上传的问题, 所以今天我们就来讨论一下这个问题. 实现原理 Struts 2是通过Commons FileUpload文件上传.Commons ...

  9. 在struts框架下实现文件的上传

    由于jspsmartupload上传文件,当前端页面没有file控件时,后端用jspsmartupload控件upload时将会走入一个死循环.现在采用struts自己提供的功能实现文件的上传. 1. ...

最新文章

  1. 前端入门(水球特效,css)
  2. 《塞洛特傳說》道具系统
  3. python单元测试工具_Python的单元测试工具——unittest小结
  4. 技术主管和架构师的职责
  5. Tunnel Warfare(HDU1540+线段树+区间合并)
  6. 为什么C4C UI上看不到新建按钮
  7. [深度学习] 一篇文章理解 word2vec
  8. c语言编译前端,c语言编译器前端的设计与实现.doc
  9. Ubuntu 10.10用LibreOffice替换OpenOffice
  10. 工作工资不高,很普通的一个我
  11. 很多人创业是为了自由
  12. (7)数据结构-基本队列实现
  13. 关于STC-ISP软件程序烧录失败率高的解决办法
  14. 颜色名称及色样表(HTML版)
  15. 计算机应用程序设计师,2018年上半年软件设计师真题+答案解析上午选择+下午案例完整版(全国计算机软考).pdf...
  16. 解决winrm4j中文乱码问题和执行脚本文件
  17. 魅族魅蓝6简单打开usb调试模式的经验
  18. 如何开启计算机cpu虚拟化,如何开启cpu虚拟化_VMware Workstation 中如何开启CPU 的虚拟化支持?...
  19. 1031. 高一学堂 (at)
  20. 如何修改MySQL监听IP地址

热门文章

  1. 对于operation操作的理解
  2. 计算机房消防应急预案,计算中心机房火灾应急预案
  3. UE-C++进阶之路 | Epic 大钊 视频学习记录(侵删)
  4. ubuntu上python编辑器_Ubuntu中安装python编辑器Ulipad
  5. 一分钟带你了解GMS安卓市场行业的发展
  6. mat 转 Qimage
  7. CSS层叠样式表之选择器
  8. Day314.外观模式享元模式 -Java设计模式
  9. 数据库存储图片,且前台从后台拿到图片进行展示
  10. 红图新媒体讲述如何进入互联网,新媒体行业?