`
zhanghong
  • 浏览: 90696 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Struts2文件上传(二) 深入FileUploadInterceptor

阅读更多

    Struts2框架本身没有文件上传的功能模块,而是利用现在流行的几个文件上传开源框架,如Common-FileUpload和COS等。Struts2利用拦截器将这些文件上传的框架巧妙的集成进来,不能不被称为一个优秀的拿来主义者。由于拦截器的使用,我们使用Struts2实现文件上传变的非常容易,似乎什么也没发生,文件已经上传到服务器了,但如果仅仅是使用这个功能,可能永远不知道Struts2为你做了多少事情。最近有点闲,分析了下下Struts2源码,才弄清楚其中的真相,笔记一下,以免遗忘。

     Struts2利用request解析器来集成其他的文件上传框架,Struts2提供了默认的request解析器JakartaMultiPartRequest,在default.properties的struts.multipart.parser参数就是配置request解析器,默认为jakarta也就是JakartaMultiPartRequest。当然,你也可以设置成cos,不过Struts2没有提供适配cos的request解析器,你得自己实现,然后配置到自己的应用。JakartaMultiPartRequest也就是利用Common-FileUpload来对request进行解析,然后保存解析结果。具体工作就是利用Common-FileUpload的ServletFileUpload对request进行解析,得到所有的FileItem的list,然后对这个list进行分析。如果是文件上传表单,则以表单的name属性分组,以表单name属性为key,对应的FileItem列表为Value保存到一个Map中。JakartaMultiPartRequest的工作已经完成,当然,这个Map中保存的所有的FileItem,框架已经将文件保存到一个临时目录里了,这个临时目录你也可以配置,参数为struts.multipart.saveDir,还要配置一个文件上传总大小,参数为struts.multipart.maxSize。

     接着就是FileUploadInterceptor的工作了,他的工作也非常简单。首先进行验证,如文件上传大小限制,上传类型限制验证等。然后以表单名来构造三个参数,例如:你的文件上传表单name为upload,则这三个参数为:upload,uploadContentType,uploadFileName。然后保存到ActionContext的PARAMETERS中,当然如果表单很多,而且表单名又不同,他就会产生不同表单名对应的参数。最后系统的ParametersInterceptor拦截器会将ActionContext的getParameters()得到的各个参数映射赋值给Action的各个属性,这就是为什么我们在开发文件上传的时候一定要在Action中提供与表单名相同的File对象(如果一个表单名又多个上传文件,这是可以是File数组或是File的List),文件名+ContentType,和文件名+FileName 这三种参数。

     框架为我们所做的就是这些了,剩下的就是文件拷贝了。现在我们来注意下Action的这几个参数,其中File对象(当然也可能是数组或List),这时他们已经指向系统临时目录里的某个文件,或是系统的内存里的数据了。在我们传输数据时,实际上是从这个临时文件或内存将数据库拷贝到上传目录里去的,当执行完Action之后,FileUploadInterceptor会将临时目录里所有临时文件删除,这也是为什么上传文件完成后会有一些日志显示说删除了一些临时文件的原因。

     现在实现一个简单的文件上传,首先熟悉下几个参数配置:

1.struts.multipart.parser  配置request解析器,Struts2默认为jakarta 也就是JakartaMultiPartRequest,我们也 可以自己开发自己的解析器。

2.struts.multipart.saveDir  上传文件的临时保存目录,我们知道Common-FileUpload需要提供一个临时目录的。如果没有设置,则是ServletContext.getAttribute("javax.servlet.context.tempdir")对应的目录,对应于Common-FileUpoad中的repository参数。

3.struts.multipart.maxSize 这个是配置文件上传总大小,单位为B,默认大小为2097152b,对应于Common-FileUpload中的sizeMax参数。

    在配置FileUploadInterceptor时候也有几个参数:

1.maximumSize  这是设置允许上传的单个文件的大小,如果某个文件大小大于这个大小,则会产生一个错误保存到Action中,错误的i18n的key为struts.messages.error.file.too.large

2.allowedTypesSet 这是设置允许上传文件的类型,多个类型以逗号“,”隔开,如果某个文件的类型没在这个设置之类,则会产生一个错误保存到Action中,错误的i18n的的key为struts.messages.error.content.type.not.allowed

3.allowedExtensionsSet这是设置允许上传文件的后缀,多个类型以逗号“,”隔开,如果某个文件的后缀没在这个设置之类,则会产生一个错误保存到Action中,错误的i18n的的key为struts.messages.error.file.extension.not.allowed

 

struts.xml配置示例:

<struts>
         //配置文件保存的临时目录
	<constant name="struts.multipart.saveDir" value="C:\Documents and Settings\bond\My Documents\temp"></constant>
	
        //配置上传总大小
        <constant name="struts.multipart.maxSize" value="1024102400"></constant>
	
	<package name="strutsDemo" extends="struts-default">
	
		<action name="Upload" method="upload" class="com.bond.action.LoginAction">
		//文件上传的保存目录
                <param name="savePath">/upload</param>
			<result name="success">/success.jsp</result>
			<result name="error">/failure.jsp</result>
			<interceptor-ref name="fileUpload">
                                 //单个文件允许的大小
				<param name="maxinumSize">10240000000</param>
                                 //允许上传的文件类型,可以到%Tomcat_home%/conf下的web.xml文件中找到所有文件类型的类型名
				<param name="allowedTypesSet">application/zip,application/pdf,image/gif</param>
			</interceptor-ref>
			<interceptor-ref name="defaultStack"></interceptor-ref>
		</action>
	</package>
</struts>

 这里我们配置了fileUpload拦截器,我们还必须吧dufaultStack加上,由于defaultStack中已经包含了fileUpload拦截器,所以fileUpload拦截器会执行俩遍,所以我们会在日志信息中看到俩次清除临时文件的记录。

 

 UploadAction:

public class UploadAction extends ActionSupport {
        //必须的参数,参数名与表单名相同,如果一个表单名对应多个上传文件,
        //则必须为数组或List
	private File[] upload;
        //必须的参数,格式:表单名+ContentType,表示上传文件类型
	private String[] uploadContentType;
        //必须的参数,格式:表单名+FileName,表示上传的文件名
	private String[] uploadFileName;
        //文件保存目录
	private String savePath;

	public LoginAction() {
	}

	public String upload() throws Exception {
		for (int i=0;i<getUpload().length;i++) {
			FileInputStream in = new FileInputStream(getUpload()[i]);
			FileOutputStream out = new FileOutputStream(getSavePath()+"\\"+getUploadFileName()[i]);
                       //将数据拷贝到上传目录,这里没有必要使用缓冲流,因为IOUtils工具类已经使用了缓存
			IOUtils.copy(in, out);
		}
		return SUCCESS;
	}
。。。。。。get/set方法。。。。

 页面表单示例:

<!-- method一定要为post,enctype一定要为 multipart/form-data,表单名一定要和Action中的参数名相同-->
<s:form method="post" id="loginForm" action="Upload"
	enctype="multipart/form-data">
<table style="border: 1px solid;" align="center">
	<thead>
		<tr>
			<td style="text-align: center" colspan="2">文件上传</td>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>用户名:</td>
			<td><input type="text" name="username"></input></td>
		</tr>
		<tr>
			<td>密码:</td>
			<td><input type="text" name="password"></input></td>
		</tr>
		<tr>
			<td colspan="2"><input type="file" name="upload" /></td>
		</tr>
		<tr>
			<td colspan="2"><input type="file" name="upload" /></td>
		</tr>
		<tr>
			<td colspan="2"><input type="file" name="upload" /></td>
		</tr>
		<tr>
			<td><input type="button" value="Upload" id="upload" /></td>
			<td><input type="button" value="Cancel" id="cancelUpload" /></td>
		</tr>
	</tbody>
</table> 

 这样,一个简单的文件上传就实现了,但是感觉文件上传无声无息,特别上传大文件,等了很长时间才知道有没有上传成功,要是有上传进度条能及时显示上传进度,这样的文件上传的功能才能算完善了,上传进度条的功能下篇再写。

5
0
分享到:
评论
2 楼 vanlin 2009-08-21  
知道了,,我不该自作主张把 interceptor-ref 位置弄反了

<action name="upload" method="upload" class="net.cdred.action.UploadAction">
<result name="success">/upload-result.jsp</result>
<result name="input">/upload.jsp</result>
<result name="error">/upload.jsp</result>
                        <interceptor-ref name="fileUpload">
<param name="maximumSize">1048576</param>
<param name="allowedExtensions">.doc,.txt</param>
</interceptor-ref>
<interceptor-ref name="LoginInterceptor_stack"></interceptor-ref>

</action>

这就对了
1 楼 vanlin 2009-08-21  
我遇到一个文题

2009-8-21 21:26:06 com.opensymphony.xwork2.util.logging.commons.CommonsLogger error
严重: File extension not allowed: file "欢迎扫描.jpg" "upload_39dc73ec_1233d21a9af__8000_00000008.tmp" image/jpeg
upload_39dc73ec_1233d21a9af__8000_00000008.tmp  e:\upload_39dc73ec_1233d21a9af__8000_00000008.tmp
欢迎扫描.jpg
image/jpeg
---resultCode :success
2009-8-21 21:26:06 com.opensymphony.xwork2.util.logging.commons.CommonsLogger info
信息: Removing file file e:\upload_39dc73ec_1233d21a9af__8000_00000008.tmp
2009-8-21 21:26:06 com.opensymphony.xwork2.util.logging.commons.CommonsLogger info
信息: Removing file file e:\upload_39dc73ec_1233d21a9af__8000_00000008.tmp



很明显它也知道不应该上传,,可是还是上传了.
		<action name="upload" method="upload" class="net.cdred.action.UploadAction">
			<result name="success">/upload-result.jsp</result>
			<result name="input">/upload.jsp</result>
			<result name="error">/upload.jsp</result>
			<interceptor-ref name="LoginInterceptor_stack"></interceptor-ref>
			<interceptor-ref name="fileUpload">
				<param name="maximumSize">1048576</param>
				<param name="allowedExtensions">.doc,.txt</param>
			</interceptor-ref>
		</action>

相关推荐

    Java框架篇-struts之文件上传和下载

     在Struts中的文件上传是通过预先定义的拦截文件上传拦截器这是可通过org.apache.struts2.interceptor.FileUploadInterceptor类的defaultStack中的一部分。仍然可以使用在struts.xml中设置各种参数,我们将在下

    SCN

    修改: package com.opensymphony.webwork.interceptor.FileUploadInterceptor 类line88 to line 93 修复bug:upload empty file cause nullponit exception 博文链接:...

    webwork-2.1.7.jar

    修改: package com.opensymphony.webwork.interceptor.FileUploadInterceptor 类line88 to line 93 修复bug:upload empty file cause nullponit exception 博文链接:...

    基于matlab实现实现了基于项目的协同过滤代码,MATLAB实现.rar

    基于matlab实现实现了基于项目的协同过滤代码,MATLAB实现.rar

    各地区年末城镇登记失业人员及失业率.xls

    数据来源:中国劳动统计NJ-2023版

    企业固定资产信息管理系统设计与实现.doc

    企业固定资产信息管理系统设计与实现.doc

    node-v11.14.0-darwin-x64.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    node-v8.9.1-sunos-x64.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    node-v12.10.0-linux-armv7l.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    基于VB实现的学生成绩管理系统(源代码+系统+开题报告+答辩PPT).zip

    【作品名称】:基于VB实现的学生成绩管理系统(源代码+系统+开题报告+答辩PPT) 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。

    银行信贷管理系统设计与实现-(毕业设计)1.docx

    银行信贷管理系统设计与实现-(毕业设计)1.docx

    基于VB实现的银行代扣代发工资系统(源代码+系统+开题报告).zip

    【作品名称】:基于VB实现的银行代扣代发工资系统(源代码+系统+开题报告) 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。

    (更新至2022年)全国镇分年龄、性别的人口数.xls

    数据来源:中国人口与就业统计NJ-2023版

    基于Java的考试管理系统

    java,大学课后作业

    数据更新至2020年分地区发电装机容量增速(风电).xls

    数据来源:中国电力统计NJ-2021版

    基于VB实现的网上餐饮管理系统设计(论文+源代码+开题报告+英文文献).zip

    【作品名称】:基于VB实现的网上餐饮管理系统设计(论文+源代码+开题报告+英文文献) 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。

    基于matlab实现烟花算法进行函数最小-最大值寻优,对十多个测试函数进行了寻优,效果良好,代码附带详细说明.rar

    基于matlab实现烟花算法进行函数最小_最大值寻优,对十多个测试函数进行了寻优,效果良好,代码附带详细说明.rar

    数据更新至2020年分地区单机6000千瓦及以上 水力发电机组分类情况(合计).xls

    数据来源:中国电力统计NJ-2021版

    基于VB实现的商场管理系统设计(源代码+系统).zip

    【作品名称】:基于VB实现的商场管理系统设计(源代码+系统) 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。

Global site tag (gtag.js) - Google Analytics