Struts2上传下载(转)

转网友总结的一篇struts2的上传,已被不时之需。

[size=xx-large][b]====================================[/b][/size]
文件上传的原理:

  表单元素的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/)。利用这两个框架都能很方便
的实现文件的上传。

[size=xx-large][b]====================================[/b][/size]

Struts2上传文件
增加commons-fileupload-1.2.jar和commons-io-1.3.1.jar到lib

[size=x-large][b]=====[/b][/size]
jsp
[size=x-large][b]=====[/b][/size]
form 的 enctype 设置为 multipart/form-data

[size=x-large][b]==============[/b][/size]
[size=x-large][b] UploadAction [/b][/size]
[size=x-large][b]==============[/b][/size]



private String username;
private String password;
private File file; // 对应文件域
private String fileFileName; // 前面的File属性的名字 + FileName(固定的)
private String fileContent; // 前面的File属性的名字 + Content

// setter... getter...

String execute() throws Exception {

InputStream is = new FileInputStream(file);

String root = ServletActionContext.getRequest().getRealPath("/upload");

File destFile = new File(root, this.getFileFileName());

OutputStream os = new FileOutputStream(destFile);

byte[] buffer = new byte[400];

int length = 0;

while ((length = is.read(buffer)) > 0) {

os.write(buffer, 0, length);
}

is.close();
os.close();

return SUCCESS;
}

[size=x-large][b]==============[/b][/size]
[size=x-large][b] 中文问题 [/b][/size]
[size=x-large][b]==============[/b][/size]
不过我全部用UTF-8并未遇到中文问题
struts2-core包
struts-default.xml ----拦截器的设置
org.apache.struts2.default.properties ----全局属性的设置

33行 strusts.i18n.encoding=UTF-8 默认UTF-8

可以在struts.xml下进行设置

<struts>
设置字符集
<constant name="struts.i18n.encoding" value="gbk"/>

设置上传文件缓存
<constant name="struts.multipart.saveDir" value="c:\"/>
</struts>

其他属性
struts.multipart.parser=jakarta struts2采用那种方式上传
pell
cos

struts.multipart.maxSize=2097152 默认上传文件最大的请求大小2M

struts.action.extension=action 整个url的后缀名

[size=xx-large][b]==============[/b][/size]
[size=xx-large][b] 上传多个文件 [/b][/size]
[size=xx-large][b]==============[/b][/size]

有两种方式:
[size=xx-small]1.数组[/size]
File[] file 文件
String[] fileFileName 文件名
String[] fileContentType 文件类型

[size=xx-small]2.集合[/size]
List<File> file
List<String> fileFileName
List<String> fileContentType

[size=xx-large][b]--------[/b][/size]
[size=xx-large][b]action中:[/b][/size]
[size=xx-large][b]--------[/b][/size]
String execute() {
for(int i = 0; i < file.size(); i++) {
InputStream is = new FileInputStream(file.get(i));
String root = ServletActionContext.getRequest().getRealPath("/upload");
File destFile = new File(root,this.getFileFileName().get(i));
...
}
return SUCCESS;
}


[size=x-large][b]--------[/b][/size]
[size=x-large][b]jsp中:[/b][/size]
[size=x-large][b]--------[/b][/size]
多个file时,file的名字要一致,都要叫file,它会自动set到跟file名对应的List中去

<s:file name="file" />
<s:file name="file" />
<s:file name="file" />

[size=xx-large][b]========================[/b][/size]
[size=xx-large][b] 上传任意个文件 [/b][/size]
[size=xx-large][b]========================[/b][/size]
<td id="more">
<input type="button" value="添加" οnclick="addMore()" />
</td>
[size=x-large][b]--------[/b][/size]
[size=x-large][b] JS:[/b][/size]
[size=x-large][b]--------[/b][/size]


funcation addMore() {
var td = document.getElementById("more");
//生成一个换行符
var br = document.createElement("br");
//创建一个input组件
var input = document.createElement("input");
var button = document.createElement("input");

//指定类型 为 file 为文件上传
input.type = "file";
//指定组件的名字
input.name = "file";

button.type = "button";
button.value = "删除";
//为删除按钮注册一个事件
button.onclick = function() {
//alert("删除按钮");

//删除一行
td.removeChild(br);
td.removeChild(input);
td.removeChild(button);
}

//将创建的组件加到<td>中
td.appendChild(br);
td.appendChild(input);
td.appendChild(button);
}


[size=xx-large][b]=======================[/b][/size]
[size=xx-large][b] 限制上传类型 [/b][/size]
[size=xx-large][b]=======================[/b][/size]
org.apache.struts2.interceptor.FileUploadInterceptor类

Long maximumSize:最大上传大小---每一个文件的大小,不是总和
String allowedTypes:允许的类型

[size=x-large][b]-------------[/b][/size]
[size=x-large][b] struts.xml [/b][/size]
[size=x-large][b]-------------[/b][/size]

<struts>
<action ...>
<result name="input">/upload.jsp</result>
<result .../>

加入一个上传文件的拦截器并设置其属性
<interceptor-ref name="fileUpload">


<param name="maximumSize">409600</param> 单个上传文件最大不能超过400K
<param name="allowedTypes">...</param> mime类型,多个用逗号分开


</interceptor-ref>

** 加入默认的拦截器
<interceptor-ref name="defaultStack" />
</action>
</struts>

注:后缀可以到tomcat\conf\web.xml中找<mime-type>中的字符串

[size=x-large][b]-------------[/b][/size]
[size=x-large][b] upload.jsp [/b][/size]
[size=x-large][b]-------------[/b][/size]

添加<s:fielderror />

[size=x-large][b]-------------[/b][/size]
[size=x-large][b] 更改显示的错误信息[/b][/size]
[size=x-large][b]-------------[/b][/size]

org.apache.struts2中 找到struts-messages.properties

[size=x-large][b]-----------------------[/b][/size]
[size=x-large][b] 上传文件类型不匹配 [/b][/size]
struts.messages.error.content.type.not.allowed=Content-Type not allowed: {0} "{1}" {2}

[size=x-large][b]-----------------------[/b][/size]
上传文件大小超出规定
struts.messages.error.file.too.large=File too large: {0} "{1}" {2}

[size=x-large][b]-----------------------[/b][/size]
上传文件出错
struts.messages.error.uploading=Error uploading: {0}

创建一个全局的属性文件 /src/messages.properties

struts.messages.error.content.type.not.allowed=不支持上传该类型的文件
struts.messages.error.file.too.large=上传文件过大,请重试
struts.messages.error.uploading=上传文件时发生错误

[size=x-large][b]---------[/b][/size]
[size=x-large][b] 国际化 [/b][/size]
[size=x-large][b]---------[/b][/size]
<constant name="struts.custom.i18n.resources" value="messages"/>

messages_en_US.properties
messages_zh_CN.properties

[size=xx-large][b]==============================[/b][/size]
[size=xx-large][b] 下载 [/b][/size]
[size=xx-large][b]==============================[/b][/size]
处理下载的类:org.apache.struts2.dispatcher.StreamResult

[size=x-large][b]== 属性 ==[/b][/size]

String contentType = "text/plain";
String contentLength;
String contentDisposition = "inline";
String inputName = "inputStream";
InputStream inputStream;
int bufferSize = 1024;
[size=x-large][b]== 说明 ==[/b][/size]
[size=x-large][b]contentType[/b][/size]
内容类型,和互联网MIME标准中的规定类型一致,例如text/plain代表纯文本,text/xml表示XML,image/gif代表GIF图片,image/jpeg代表JPG图片

用来做动态文件下载的,事先并不知道未来的文件类型是什么,那么我们可以把它的值设置成为:application/octet-stream;charset=ISO8859-1 ,注意一定要加入charset,否则某些时候会导致下载的文件出错
[size=x-large][b]inputName[/b][/size]
下载文件的来源流,对应着action类中某个类型为Inputstream的属性名,例如取值为inputStream的属性需要编写getInputStream()方法
[size=x-large][b]contentDisposition[/b][/size]
文件下载的处理方式,包括内联(inline)和附件(attachment)两种方式,而附件方式会弹出文件保存对话框,否则浏览器会尝试直接显示文件。取值为:attachment;filename="struts2.txt",表示文件下载的时候保存的名字应为struts2.txt。如果直接写filename="struts2.txt",那么默认情况是代表inline,浏览器会尝试自动打开它,等价于这样的写法:inline; filename="struts2.txt"
[size=x-large][b]bufferSize[/b][/size]
下载缓冲区的大小

# contentType属性和contentDisposition分别对应着HTTP响应中的头Content-Type和Content-disposition头。

如:
HTTP头内容:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-disposition: attachment;filename="struts2.txt"
Content-Type: text/plain
Transfer-Encoding: chunked
Date: Sun, 02 Mar 2008 02:58:25 GMT
[size=x-large][b]----------[/b][/size]
[size=x-large][b] action [/b][/size]
[size=x-large][b]----------[/b][/size]
Class DownloadAction extends ActionSupport {
private String path;
// setter... getter...
//必须返回一个输入流,该流是让用户下载的
public InputStream getDownloadFile() {
//从某个文件获得流 --这里是获得项目root下upload下的文件
//也可以 new FileInputStream("c:/test.text");
return ServletActionContext.getServletContext().getResourceAsStream("/upload/struts2.ppt");
}

public String execute() throws Exception {
return SUCCESS;
}
}

[size=x-large][b]-----------[/b][/size]
[size=x-large][b]struts.xml [/b][/size]
[size=x-large][b]-----------[/b][/size]
<action name="download" class="org.scorpio.jh.struts2.upload.action.DownloadAction">

<!-- 依赖注入文件路径 -->
<param name="path">/download/xhtml.txt</param>

<!-- 设置结果类型为 流 -->
<result name="success" type="stream">

<!-- 设置内容类型 -->
<param name="contentType">text/plain</param>

<!-- 设置下载文件的名字 attachment:作为附件,filename=:指定下载文件名-->
<param name="contentDisposition">attachment;filename="xhtml.txt"</param>

<!-- 设置下载文件的输入流对应的方法 downloadFile对应DownloadAction中的getDownloadFile()-->
<param name="inputName">downloadFile</param>

<!-- 指定下载文件的缓冲大小 -->
<param name="bufferSize">4096</param>
</result>
</action>

[size=xx-large][b]==========================[/b][/size]
[size=xx-large][b] 解决下载文件名中文问题 [/b][/size]
[size=xx-large][b]==========================[/b][/size]
1.在下载action获取文件名的方法中先进行转码然后再返回
path = new String( path.getBytes(), "ISO-8859-1" );

2.xml配置文件动态的获取path的值
<param name="contentDisposition">attachment;filename="${path}"</param>
${path} 用于动态的获取所配置的action中path成员的值,相当于调用getPath()方法
[size=x-large][b]-------[/b][/size]
[size=x-large][b]action [/b][/size]
[size=x-large][b]-------[/b][/size]
private String path;

public String getPath() {
try { // 转换成西欧字符集
path = new String(path.getBytes(), "ISO-8859-1");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return path;
}

public void setPath(String path) {
this.path = path;
}

[size=x-large][b]---------------[/b][/size]
[size=x-large][b] struts.xml [/b][/size]
[size=x-large][b]---------------[/b][/size]
<action name="download" class="org.scorpio.jh.struts2.upload.action.DownloadAction">

<param name="path">/download/wmlscript实例.txt</param>

<result name="success" type="stream">
<param name="contentType">text/plain</param>

<!-- 动态的获取 DownloadAction的path属性 -->
<param name="contentDisposition">attachment;filename="${path}"</param>

<param name="inputName">downloadFile</param>
<param name="bufferSize">4096</param>
</result>
</action>

[size=xx-large][b]=================[/b][/size]
[size=xx-large][b] 安全隐患 [/b][/size]
[size=xx-large][b]=================[/b][/size]

访问者如果精通Struts 2的话,它可能使用这样的带有表单参数的地址来访问:

http://localhost:8080/struts2hello/download3.action?inputPath=/WEB-INF/web.xml,这样的结果就是下载后的文件内容是您系统里面的web.xml的文件的源代码,甚至还可以用这种方式来下载任何其它JSP文件的源码。这对系统安全是个很大的威胁。作为一种变通的方法,读者最好是从数据库中进行路径配置,然后把Action类中的设置inputPath的方法统统去掉,简言之就是删除这个方法定义:
public void setPath(String path) {
this.path = path;
}


而实际情况则应该成为 download.action?fileid=1 类似于这样的形式来进行。或者呢,读者可以在execute()方法中进行路径检查,如果发现有访问不属于download下面文件的代码,就一律拒绝,不给他们返回文件内容。例如,我们可以把刚才类中的execute()方法加以改进,成为这样:

public String execute() throws Exception {
// 文件下载目录路径
String downloadDir = ServletActionContext.getServletContext().getRealPath("/download");
// 文件下载路径
String downloadFile = ServletActionContext.getServletContext().getRealPath(inputPath);
java.io.File file = new java.io.File(downloadFile);
downloadFile = file.getCanonicalPath();// 真实文件路径,去掉里面的..等信息

// 发现企图下载不在 /download 下的文件, 就显示空内容
if(!downloadFile.startsWith(downloadDir)) {
return null;
}
return SUCCESS;
}

这时候如果访问者再企图下载web.xml的内容,它只能得到一个空白页,现在访问者只能下载位于/download目录下的文件
[size=xx-large]其他的一些资料:[/size]

Struts 2中实现文件上传

http://www.blogjava.net/max/archive/2007/03/21/105124.html



Struts 2中实现文件下载(修正中文问题)

http://www.blogjava.net/beansoft/archive/2008/03/03/183468.html



Struts 1文件下载:

http://hi.baidu.com/gisland/blog/item/268caecc7b4eea1301e9288f.html

http://hi.baidu.com/joe_tech/blog/item/164ced16bd0cbe52f2de3235.html

http://www.blogjava.net/max/archive/2007/03/21/105124.html
http://callan.iteye.com/blog/179351
转载自:http://longzijian.iteye.com/blog/336841
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值