在使用了 Struts2 框架的系统中,对于处理像下面这种表单上传文件时:
1 2 3 4 5 |
<form action="..." enctype="multipart/form-data"> 文件:<input type="file" name="upload"><br> 描述:<input type="text" name="desc"></br> <input type="submit" value="提交"> </form> |
自然而然的想法就是在 Action 中声明变量 File upload 和 String desc,请求提交到这个 Action 后,在 execute() 方法中就能直接使用 upload 和 desc 了,它们已被 Struts2 框架(org.apache.struts2.interceptor.FileUploadInterceptor 监听器) 赋上了相应的值了。
因为维护的是一个古老的项目,请求都是直接提交给 jsp。在这个项目中套上了 Struts2 已是不易了。原来项目是用的 jspSmartUpload 来处理上传文件的,Struts2 一上 jspSmartUpload 便不能正常工作了,因为 Struts2 的过滤器 org.apache.struts2.dispatcher.FilterDispatcher 拦截的是所有的请求,在交把请求交给 jspSmartUpload 之前请求 request 就已被处理过了,即使是把 struts2-core-2.x.x.jar 中的 struts-default.xml fileUpload 取消了也是如此。
暂时又不想再新加一个 Action,声明 upload:File 和 desc:String 直接接收参数,这样改动的话实在是大,现在 struts.xml 和 struts.properties 文件还是空的呢。所以姑且在原来那个 jsp 中处理吧。
最早做过 jsp 文件上传的人都知道,给 form 加上 enctype="multipart/form-data" 属性后,request.getParameter("desc") 取输入框的值就失灵了,因为页面请求数据是以流的形式发送给服务器的,所以 jspSmartUpload 用了它自己的 Request, com.jspsmart.upload.SmartUpload.getRequest().getParameter("desc") 来接收文本框数据,但对于 Struts2 处理过的 request jspSmartUpload 就无能为力了。
那么在 Struts2 中的 jsp 如何获取到 enctype="multipart/form-data" 表单传递过来的文本输入和文件呢?
·获取文本框的值
,仍然可用 request.getParameter("desc"),因为此时的 request 是由 org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper 实现的。
对比一下不同时候 request 的具体实现类(Tomcat 环境中)
form enctype | multipart/form-data | application/x-www-form-urlencoded |
Struts2 | org.apache.struts2.dispatcher.multipart .MultiPartRequestWrapper |
org.apache.struts2.dispatcher .StrutsRequestWrapper |
Struts1 | org.apache.struts.upload .MultipartRequestWrapper |
org.apache.coyote.tomcat5 .CoyoteRequestFacade |
无框架 | org.apache.coyote.tomcat5 .CoyoteRequestFacade |
org.apache.coyote.tomcat5 .CoyoteRequestFacade |
·获取上传来的文件
用就要对 request 作个转型,才能调用到相应的方法
1 2 3 4 5 6 |
MultiPartRequestWrapper mpRequest = (MultiPartRequestWrapper)request; File[] files = mpRequest.getFiles("upload"); //文件现在还在临时目录中 String[] fileNames = mpRequest.getFileNames("upload"); //然后就可以处理你的业务了 |
其他方法可以查看 MultiPartRequestWrapper API,MultiPartRequestWrapper 是继承自 org.apache.struts2.dispatcher.StrutsRequestWrapper 的。
最后,用了 Struts2 来上传文件,最好在 web.xml 中加上 ActionContextCleanUp 过滤器以避免一些未不预知的异常。
1 2 3 4 5 6 7 8 9 |
<filter> <filter-name>struts-cleanup</filter-name> <filter-class>org.apache.struts2.dispatcher.ActionContextCleanUp</filter-class> </filter> <filter-mapping> <filter-name>struts-cleanup</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> |
网上有人说是要加 ActionContextCleanUp 过滤器的,ActionContextCleanUp 的代码注释是它易于同 SiteMesh 的整合,至于为何与文件上传扯上关系,我以后也会关注的。
对了还要在项目中引入 commons-fileupload-x.x.x.jar 和 commons-io-x.x.jar 包,其他没有什么特别的配置,默认即可。相信本文的实用性不强,不会有人用 jsp 来处理这些事情,参考价值可能还有一些。
本文链接 https://yanbin.blog/manual-struts2-file-upload/, 来自 隔叶黄莺 Yanbin Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。
楼主的文章都是精品
真的是精品
能有更具体的吗,我这几天都在研究这个,怎么将SmartUpload整合在ssh中,谢谢楼主!
你用了 Struts2 的话,就没必要,也很难用上 JspSmartUpload,因为 Struts2 比以往的 Struts1 不一样的,不再用 ActionServlet 来映射 *.do 的请求,而是用一个 FilterDispatcher 来拦截所有的 /* 的请求,所以无论你用什么形式的网址访问,你的 multipart/form-data 的表单提交的数据都会被 Struts2 处理加工一番,而 JspSmartUpload 想要的是最原始的 Request,因此给 Struts2 嚼过一次的 Request,再让 JspSmartUpload 再 initialize(pageContext) 时,其时 Request 中的数据已不是它所期望的结构了,所以会全乱套的。
所以既然用了 Struts2 就用它提供的文件上传功能吧。
但如果你还在用 Struts1 的话,还有些机会用上 SmartUpload,因为 Struts1 处理的是 *.do 请求,所以只要你的上传页面不要提交给 *.do 的 URL 进行处理就可以像你以前那般使用 SmartUpload 了。
最后仍然不建议用 JspSmartUpload 了,Struts1 的文件上传功能也很不错的,Struts2 对于上传文可是提供了三种组件的选择。在 Struts1 中你也可以手工来处理文件的上传。何况 Struts2 在拦截所有请求的同时还给你加了一个字符集过滤器,这对我们开发中文件的系统是个福音,不用自己加个 CharacterEncodingFilter 了,可以解决上传时文件名的乱码问题。
这也是 Struts2 拦截所有请求而不只是 *.do 的原因,同时也是为什么 Struts2 选择了 Filter 而不是像 Struts1 的 ActionServlet 来映射 URL 的缘故,因为 Servlet 做不到,Filter 才能组成成 Filter 链。
谢谢楼主,以前的系统是使用jsp+javabean实现的,现在是整合到struts2.0+hibernate3.2+spring2.5,改成struts2.0改动比较大,需要修改页面比较多,还有没有其他的方法;上传文件的代码都写在jsp中,如改成struts2.0需要跳转action,有例子没,谢谢楼主。
我改了一个 jsp 的项目,用上了 Struts2 ,先不要大动干戈,并非一用上 Struts2 就得跳到 action 去。反正 Struts2 都是拦截所有请求,沿用原来一些东西,仍然可以暂时在 jsp 里改动。
至于 spring 和 hibernate 的加入,不用引响到 web 的架构,如果不觉得难看的话,在哪里 getBean() 或取到 getHibernateTemplate() 都可以先忍奈。
是说可以在jsp中定义所需要上传文件的基本信息,直接写方法。有相关例子没,就是实现文件上传,谢谢楼主。
就是
MultiPartRequestWrapper mpRequest = (MultiPartRequestWrapper)request;
File[] files = mpRequest.getFiles("upload"); //文件现在还在临时目录中
String[] fileNames = mpRequest.getFileNames("upload");
request.getParameter("desc");
加了 Struts2 的 Filter 不用作任何处理了。
<%
MultiPartRequestWrapper mpRequest = (MultiPartRequestWrapper)request;
//File[] file = mpRequest.getFiles("upload"); //文件现在还在临时目录中
String[] fileNames = mpRequest.getFileNames("upload");
System.out.println(mpRequest.getFiles("upload").length);
int k=0;
for(int i=0;i<mpRequest.getFiles("upload").length;i++){
System.out.println(mpRequest.getFiles("upload")[i]);
try{
FileInputStream fis = new FileInputStream(mpRequest.getFiles("upload")[i]);
FileOutputStream fos = new FileOutputStream("E:/apache-tomcat-5.5.25/apache-tomcat-5.5.25/webapps/aiqcs");
byte[] buf = new byte[1024];
int j = 0;
while ((j = fis.read(buf)) != -1) {
fos.write(buf, 0, j);
k++;
}
fis.close();
fos.close();
}
catch(Exception e){
System.out.println(e);
}
}
%>
File[] file = mpRequest.getFiles("upload"); //文件现在还在临时目录中
在这句话报Type mismatch:cannot convert from File[] to File[]
System.out.println(mpRequest.getFiles("upload")[i]);打印的是临时地址:E:\apache-tomcat-5.5.25\apache-tomcat-5.5.25\work\Catalina\localhost\aiqcs\upload__4422d98_11a2e68a292__8000_00000102.tmp
FileOutputStream fos 报:java.io.FileNotFoundException: E:\apache-tomcat-5.5.25\apache-tomcat-5.5.25\webapps\aiqcs (拒绝访问。)
mail����.txt;出现乱码问题
现在是中文乱码问题,struts2.0的filter不是可以实现,在好好看看,谢谢楼主!
struts.properties 或 struts.xml 中设置常量
struts.i18n.encoding=GBK
指定你要的字符集,默认是 UTF-8
现在有个字符编码冲突问题,在用ssh实现的模块中使用的字符格式是utf-8,老系统整合在ssh框架下,实现的模块功能也整合在老系统下,老系统使用的是字符格式是GB2312,有没有办法解决这个冲突,谢谢楼主。
要不特殊处理,要不就是你现在的框架也用 GBK,其实用 UTF-8 只是一种愿望,如果不会有实际的需求去支持更多字符就 GBK 足矣,UTF-8 要比 GBK 多些存存储空间,也加大的网络传输。
楼主有无试过用COS在Struts2中成功实现上传啊?我试了好多方法都不行
有机会给我邮件,聊下~~
vinscheng@163.com
楼主的文章确实是精品啊!
不过有这样一个问题,原来一个系统是struts1开发的,整合了struts2后,原来struts1开发的文件上传功能(未用smartupload组件)用不了了!难道是struts1和struts2的兼容问题?或者是楼主所说的request被struts2处理过了,struts1用不了了?整合之后,原来struts1的其他功能都可以用。
我的邮件是290582054@qq.com。
再一次感谢楼主!
@guosk
是的,Struts2 的 org.apache.struts2.dispatcher.FilterDispatcher 拦截了所有的请求,所以如果你还想用 struts1 的文件上传功能,那么可以在配置文件中把 Struts2 的 org.apache.struts2.interceptor.FileUploadInterceptor 拦截器关掉。