Struts2文件上传与下载
1. 文件上传的原理:
表单元素的
enctype
属性指定的是表单数据的编码方式,该属性有
3
个值:
1)
application/x-www-form-urlencoded
:这是默认编码方式,它只处理表单域里的
value
属性值,采用这种编码方式的表单会将表单域的值处理成
URL
编码方式。
2)
multipart/form-data
:这种编码方式的表单会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定文件的内容也封装到请求参数里。
3)
text/plain
:这种方式主要适用于直接通过表单发送邮件的方式。
文件上传是
web
应用经常用到的一个知识。原理是,通过为表单元素设置
enctype=”multipart/form-data”
属性,让表单提交的数据以二进制编码的方式提交,在接收此请求的
Servlet
中用二进制流来获取内容,就可以取得上传文件的内容,从而实现文件的上传。
在
Java
领域中,有两个常用的文件上传项目:一个是
Apache
组织
Jakarta
的
Common-FileUpload
组件
(http://commons.apache.org/fileupload/)
,另一个是
Oreilly
组织的
COS
框架
(http://www.servlets.com/cos/)
。利用这两个框架都能很方便的实现文件的上传。
2. Struts2的文件上传:
Struts2
并未提供自己的请求解析器,也就是就
Struts2
不会自己去处理
multipart/form-data
的请求,它需要调用其他请求解析器,将
HTTP
请求中的表单域解析出来。但
Struts2
在原有的上传解析器基础上做了进一步封装,更进一步简化了文件上传。
Struts2
默认使用的是
Jakarta
的
Common-FileUpload
框架来上传文件,因此,要在
web
应用中增加两个
Jar
文件:
commons-fileupload-1.2.jar
和
commons-io-1.3.1.jar
。它在原上传框架上做了进一步封装,简化了文件上传的代码实现,取消了不同上传框架上的编程差异。
如果要改成其它的文件上传框架,可以修改
struts.multipart.parser
常量的值为
cos/pell
,默认值是
jakata
。并在
classpath
中增加相应上传组件的类库。
2.1. 步骤一:创建带上传表单域的页面
<%@
page
language
=
"java"
contentType
=
"text/html; charset=UTF-8"
%>
<
html
>
<
head
>
<
title
>
Struts2 File Upload
</
title
>
</
head
>
<
body
>
<
form
action
=
"fileUpload.action"
method
=
"POST"
enctype
=
"multipart/form-data"
>
文件标题:
<
input
type
=
"text"
name
=
"title"
size
=
"50"
/><
br
/>
选择文件:
<
input
type
=
"file"
name
=
"upload"
size
=
"50"
/><
br
/>
<
input
type
=
"submit"
value
=
"
上传
"
/>
</
form
>
</
body
>
</
html
>
|
此页面特殊之处只是把表单的
enctype
属性设置为
multipart/form-data
。
2.2. 步骤二:创建处理上传请求的Action类
package
org.qiujy.web.struts2;
import
java.io.BufferedInputStream;
import
java.io.BufferedOutputStream;
import
java.io.File;
import
java.io.FileInputStream;
import
java.io.FileOutputStream;
import
java.io.InputStream;
import
java.io.OutputStream;
import
org.apache.struts2.ServletActionContext;
import
com.opensymphony.xwork2.ActionSupport;
/**
*
处理文件上传的
Action
类
*
@author
qiujy
*
@version
1.0
*/
public
class
FileUploadAction
extends
ActionSupport {
private
static
final
int
BUFFER_SIZE
= 16 * 1024;
//
文件标题
private
String
title
;
//
上传文件域对象
private
File
upload
;
//
上传文件名
private
String
uploadFileName
;
//
上传文件类型
private
String
uploadContentType
;
//
保存文件的目录路径
(
通过依赖注入
)
private
String
savePath
;
//
以下省略
getter
和
setter......
//
自己封装的一个把源文件对象复制成目标文件对象
private
static
void
copy(File src, File dst) {
InputStream in =
null
;
OutputStream out =
null
;
try
{
in =
new
BufferedInputStream(
new
FileInputStream(src),
BUFFER_SIZE
);
out =
new
BufferedOutputStream(
new
FileOutputStream(dst),
BUFFER_SIZE
);
byte
[] buffer =
new
byte
[
BUFFER_SIZE
];
int
len = 0;
while
((len = in.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
}
catch
(Exception e) {
e.printStackTrace();
}
finally
{
if
(
null
!= in) {
try
{
in.close();
}
catch
(IOException e) {
e.printStackTrace();
}
}
if
(
null
!= out) {
try
{
out.close();
}
catch
(IOException e) {
e.printStackTrace();
}
}
}
}
@Override
public
String execute()
throws
Exception {
//
根据服务器的文件保存地址和原文件名创建目录文件全路径
String dstPath = ServletActionContext.getServletContext()
.getRealPath(
this
.getSavePath())
+
"\\"
+
this
.getUploadFileName();
System.
out
.println(
"
上传的文件的类型:
"
+
this
.getUploadContentType());
File dstFile =
new
File(dstPath);
copy(
this
.
upload
, dstFile);
return
SUCCESS
;
}
}
|
上面这个
Action
类中,提供了
title
和
upload
两个属性来分别对应页面的两个表单域属性,用来封装表单域的请求参数。
但是,值得注意的是,此
Action
中还有两个属性:
uploadFileName
和
uploadContentType
,这两个属性分别用于封装上传文件的文件名、文件类型。这是
Struts2
设计的独到之处:
Strut2
的
Action
类直接通过
File
类型属性直接封装了上传文件的文件内容,但这个
File
属性无法获取上传文件的文件名和文件类型,所以
Struts2
就直接将文件域中包含的上传文件名和文件类型的信息封装到
uploadFileName
和
uploadContentType
属性中,也就是说
Struts2
针对表单中名为
xxx
的文件域,在对应的
Action
类中使用
3
个属性来封装该文件域信息
:
l
类型为
File
的
xxx
属性:用来封装页面文件域对应的文件内容。
l
类型为
String
的
xxxFileName
属性:用来封装该文件域对应的文件的文件名。
l
类型为
String
的
xxxContentType
属性:用来封装该文件域应用的文件的文件类型。
另外,在这个
Action
类中还有一个
savePath
属性,它的值是通过配置文件来动态设置的,这也是
Strut2
设计中的一个依赖注入特性的使用。
2.3. 步骤三:配置
struts.xml
文件:
<!
DOCTYPE
struts
PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd"
>
<
struts
>
<
package
name
=
"fileUploadDemo"
extends
=
"struts-default"
>
<
action
name
=
"fileUpload"
class
=
"org.qiujy.web.struts2.FileUploadAction"
>
<!--
动态设置
Action
中的
savePath
属性的值
-->
<
param
name
=
"savePath"
>
/upload
</
param
>
<
result
name
=
"success"
>
/showupload.jsp
</
result
>
</
action
>
</
package
>
</
struts
>
|
在这个文件中跟以前配置唯一不同的是给
action
配置了一个
<param …/>
元素,用来为该
Action
的
savePath
属性动态注入值。
web.xml
中的配置跟以前的应用一样。说明一点:好多网络文章说
Struts2
上传时要在
web.xml
中配置一个名为
ActionContextUp
的过滤器,说是有一些莫名的错误,可是是我用了
Struts2
新版本
2.0.9GA
版,测了
n
次,没出现什么问题,所以没配置。
2.4. 运行调试:
运行前要在根目录下创建一个名为
upload
的文件夹,用来存放上传后的文件。
上传结果:
3. 文件类型及错误输出:
Struts2
提供了一个文件上传的拦截器
(
名为
fileUpload
)
,通过配置这个拦截器能轻松地实现文件类型的过滤。
在上例中,若要配置上传的文件只能是一些普通的图片文件格式:
image/bmp
、
image/png
、
image/gif
、
image/jpeg
、
image/jpg
等,则可在
struts.xml
文件中按如下方式配置:
<!
DOCTYPE
struts
PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd"
>
<
struts
>
<
constant
name
=
"struts.custom.i18n.resources"
value
=
"messages"
/>
<
package
name
=
"fileUploadDemo"
extends
=
"struts-default"
>
<
action
name
=
"fileUpload"
class
=
"org.qiujy.web.struts2.FileUploadAction"
>
<
interceptor-ref
name
=
"fileUpload"
>
<!--
配置允许上传的文件类型,多个用
","
分隔
-->
<
param
name
=
"allowedTypes"
>
image/bmp,image/png,image/gif,image/jpeg,image/jpg
,image/x-png, image/pjpeg
</
param
>
<!--
配置允许上传的文件大小,单位字节
-->
<
param
name
=
"maximumSize"
>
102400
</
param
>
</
interceptor-ref
>
<
interceptor-ref
name
=
"defaultStack"
/>
<!--
动态设置
Action
中的
savePath
属性的值
-->
<
param
name
=
"savePath"
>
/upload
</
param
>
<
result
name
=
"input"
>
/index.jsp
</
result
>
<
result
name
=
"success"
>
/showupload.jsp
</
result
>
</
action
>
</
package
>
</
struts
>
|
如果上传文件失败,系统返回到
input
对应的页面,要在
input
对应的页面输出文件过滤失败信息,可以在
input
对应的页面中增加
<s:fielderror/>
来显示错误信息。
运行调试:
结果:
显然,这样的提示不太友好,应用使用国际化信息。在国际化资源文件中添加如下三句:
#
更改上传文件类型不允许的提示信息
struts.messages.error.content.type.not.allowed=
文件上传失败:你要上传的文件类型不允许
#
更改上传文件太大的提示信息
struts.messages.error.file.too.large=
文件上传失败:你要上传的文件太大
#
文件上传其它错误信息
struts.messages.error.uploading=
文件上传失败:发生内部错误
|
别忘了要用
native2ascii.exe
进行编码转换哦。再运行调试:
另外,在控制台会看到一条消息:
Unable to find 'struts.multipart.saveDir' property setting. Defaulting to javax.servlet.context.tempdir
Removing file upload D:\tomcat6.0.13\work\Catalina\localhost\fileload_struts2\upload__4b616fd1_115a3d5d9dc__7fff_00000005.tmp
|
第一个说是找不以
struts.multipart.saveDir
,即没有指定临时文件夹,这个很好解决,只需指定一个
struts.multipart.saveDir
常量值为某个目录来解决。第二个说正在删除一个临时文件,这个临时文件是上传过程中产生的,属正常。
4. 多文件上传:
Struts2
也可以很方便地实现多文件上传。
在输入表单域增加多个文件域:
multifileupload.jsp
<%@
page
language
=
"java"
contentType
=
"text/html; charset=UTF-8"
%>
<%@
taglib
uri
=
"/struts-tags"
prefix
=
"s"
%>
<
html
>
<
head
>
<
title
>
多文件上传
</
title
>
</
head
>
<
body
>
<
font
color
=
"red"
><
s:fielderror
/></
font
>
<
form
action
=
"multiFileUpload.action"
method
=
"POST"
enctype
=
"multipart/form-data"
>
文件标题:
<
input
type
=
"text"
name
|