Ajax file upload 文件上传有许多的插件支持,且都有相应的 PHP 服务端示范,可是在将代码应用到 Struts2 上时却总是不尽如意。网上也只找到一些不完全的解决方案。这里给出我的解决,因为已经有个样子了。在项目的后期再进行完善吧。
Struts2 上实现 Ajax file upload 的困难:
1. Struts2 对文件上传是通过 file upload 拦截器实现的,具体引入方法见[url=http://struts.apache.org/2.1.8.1/docs/file-upload.html]这里[/url]。然而 File Upload 拦截器似乎对于 XHR 过来的文件上传请求无法响应,具体原因未去探究。也希望知道的人给个提示,谢谢。
2. 实现无页面刷新的文件上传通常是通过隐藏 iFrame 实现的。即在有文件上传的 form 中添加一个 target 属性,并指向一个隐藏 iFrame。这样可以实现页面无刷新,form 提交后的返回信息会填入到指定的 iframe 中。然而问题在于 iframe 只接收 contentType 为 HTML 和 XML 响应,对于其他类型的响应会以浏览器文件下载的形式提示下载。
为解决以上问题,思路如下:
1. 先编写正常的文件上传 form,而不用 XHR。并添加一个隐藏 iframe。将 form 的 target 指向隐藏 iframe。
2. 配置 action 的返回值类型为 text/html,用 包装 JSON 数据。在接收数据时再对其进行解析转换为 JSON
具体实现:
使用到的工具包:
[url=http://jquery.malsup.com/form]jquery.form.js[/url]
[url=http://struts.apache.org/2.1.8/docs/json-plugin.html]Struts 2 的 JSON 插件[/url]
在实现文件上传的过程中无意间看到 jquery.form.js 上有对文件上传中遇到的问题2进行了[url=http://jquery.malsup.com/form/#file-upload]描述[/url],也看到了它给出的解决方案,于是决定用它来简化开发。而 Struts2 的 JSON 插件本来是为了实现 JSON 传输的,发现它可以为 JSON 数据自动添加包装,且[url=http://struts.apache.org/2.1.8/docs/json-plugin.html#JSONPlugin-Wrapping]描述[/url]中明确表明是为了实现文件上传的。呵呵,有意思的巧合。
编写 JSP:
编写 Action:
[b]注意[/b]
getter 和 setter 的设置问题。因为 JSON 插件会将所有的 getter 方法转换为 JSON 输出,所以应尽量避免不必要的 getter 方法的存在。尤其是类似 getFile():InputStream 的方法,因为这样会把整个文件变为一堆乱码输出到页面,页面运行速度极慢。
配置 XML:
这里对于结果进行了特殊处理,将结果的 contentType 设置成了 "text/html" 以便 iframe 可以正常接收。而将 JSON 封装在了 中,便于 JS 在前端进行处理。
这样对于 Struts2 的文件上传就改造完成了。现在可以实现无刷新页面上传啦
Struts2 上实现 Ajax file upload 的困难:
1. Struts2 对文件上传是通过 file upload 拦截器实现的,具体引入方法见[url=http://struts.apache.org/2.1.8.1/docs/file-upload.html]这里[/url]。然而 File Upload 拦截器似乎对于 XHR 过来的文件上传请求无法响应,具体原因未去探究。也希望知道的人给个提示,谢谢。
2. 实现无页面刷新的文件上传通常是通过隐藏 iFrame 实现的。即在有文件上传的 form 中添加一个 target 属性,并指向一个隐藏 iFrame。这样可以实现页面无刷新,form 提交后的返回信息会填入到指定的 iframe 中。然而问题在于 iframe 只接收 contentType 为 HTML 和 XML 响应,对于其他类型的响应会以浏览器文件下载的形式提示下载。
为解决以上问题,思路如下:
1. 先编写正常的文件上传 form,而不用 XHR。并添加一个隐藏 iframe。将 form 的 target 指向隐藏 iframe。
2. 配置 action 的返回值类型为 text/html,用 包装 JSON 数据。在接收数据时再对其进行解析转换为 JSON
具体实现:
使用到的工具包:
[url=http://jquery.malsup.com/form]jquery.form.js[/url]
[url=http://struts.apache.org/2.1.8/docs/json-plugin.html]Struts 2 的 JSON 插件[/url]
在实现文件上传的过程中无意间看到 jquery.form.js 上有对文件上传中遇到的问题2进行了[url=http://jquery.malsup.com/form/#file-upload]描述[/url],也看到了它给出的解决方案,于是决定用它来简化开发。而 Struts2 的 JSON 插件本来是为了实现 JSON 传输的,发现它可以为 JSON 数据自动添加包装,且[url=http://struts.apache.org/2.1.8/docs/json-plugin.html#JSONPlugin-Wrapping]描述[/url]中明确表明是为了实现文件上传的。呵呵,有意思的巧合。
编写 JSP:
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="jquery.form.js"></script>
<s:form action="doUpload" method="post" enctype="multipart/form-data">
<s:file name="upload" label="File"/>
<s:submit/>
</s:form>
<script type="text/javascript">
$('form').ajaxForm({
dataType: 'json',
success: function(data) { /* do something you want */}
});
</script>
编写 Action:
[b]注意[/b]
getter 和 setter 的设置问题。因为 JSON 插件会将所有的 getter 方法转换为 JSON 输出,所以应尽量避免不必要的 getter 方法的存在。尤其是类似 getFile():InputStream 的方法,因为这样会把整个文件变为一堆乱码输出到页面,页面运行速度极慢。
package cream;
import java.io.File;
import com.opensymphony.xwork2.ActionSupport;
public class UploadAction extends ActionSupport {
private File file;
private String contentType;
private String filename;
private String message;
public void setUpload(File file) {
this.file = file;
}
public void setUploadContentType(String contentType) {
this.contentType = contentType;
}
public void setUploadFileName(String filename) {
this.filename = filename;
}
public String execute() {
//...
return SUCCESS;
}
// getter with necessary
public String getMessage() {
return this.message;
}
}
配置 XML:
<action name="doUpload" class="cream.UploadAction">
<result type="json">
<param name="wrapPrefix"><![CDATA[<textarea>]]></param>
<param name="wrapSuffix"><![CDATA[</textarea>]]></param>
<param name="contentType">text/html</param>
</result>
</action>
这里对于结果进行了特殊处理,将结果的 contentType 设置成了 "text/html" 以便 iframe 可以正常接收。而将 JSON 封装在了 中,便于 JS 在前端进行处理。
这样对于 Struts2 的文件上传就改造完成了。现在可以实现无刷新页面上传啦