struts2下载文件错误提示误导——结果竟是中文乱码所致

来源:互联网 发布:日本传统音乐知乎 编辑:程序博客网 时间:2024/05/29 07:25

在调试struts2文件下载时,提示错误如下:

java.lang.IllegalArgumentException: Can not find a java.io.InputStream with the name [fileStream] in the invocation stack. Check the <param name="inputName"> tag specified for this action.org.apache.struts2.dispatcher.StreamResult.doExecute(StreamResult.java:237)org.apache.struts2.dispatcher.StrutsResultSupport.execute(StrutsResultSupport.java:186)com.opensymphony.xwork2.DefaultActionInvocation.executeResult(DefaultActionInvocation.java:373)com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:277)

出错误,然后根据错误提示,寻找原因。根据错误栈式顺序,出现在第一行的往往是错误源。

请看第一句,想必大家都能看懂吧,找不到fileStream,这个是inputName属性的值,提示让我检查inputName参数是否符合action

根据错误,一直在提示inputName参数,然后把怀疑重心全放到struts配置文件中。

首先来看一下文件下载的程序:

struts2中是以InputStream的形式返回给系统,客户端是直接访问action,然后actionInputStream的形式返回给系统,然后系统生成文件的http响应的消息头。

文件下载的action

package com.download;import java.io.InputStream;import java.io.UnsupportedEncodingException;import javax.servlet.http.HttpServletResponse;import org.apache.struts2.ServletActionContext;import com.opensymphony.xwork2.ActionSupport;/* * 文件下载 */public class DownloadFile extends ActionSupport {//private InputStream inputStream;private String fileName;public String getFileName() {return fileName;}public void setFileName(String fileName) {        try {this.fileName = fileName;} catch (UnsupportedEncodingException e) {// TODO Auto-generated catch blocke.printStackTrace();}}public InputStream getFileStream() { return ServletActionContext.getServletContext().getResourceAsStream("uploadFile\\"+fileName);}//只有返回return时,才会用到result,然后才会用到result中的参数,即fileInput,//然后才会调用getFileInput方法,对fileInput进行赋值public String execute() throws Exception {return "success";}}

Struts中的配置文件:

 <action name="download" class="com.download.DownloadFile">  <result name="success" type="stream">  <param name="inputName">fileStream</param>  <param name="contentType">application/octet-streams</param>           <param name="contentDisposition">attachment;filename="${fileName}"</param>   </result> </action>

来解释一下配置中下载文件的标签。

inputName:下载文件输出流,文件以流的形式返回。所以action中可以只用到get方式,set方式可以省略。

contentType文件下载的类型。其实就是MIME类型。如:  image/gif(gif格式),application/x-javascript(js格式)

contentDisposition下载文件的处理方式。内联(inline)和附件(attachment)两种方式。是以附件的形式保存(attachment),还是直接在浏览器中显示(inline)。

attachment;filename="${fileName}"这种方式,是以附件形式保存。另一种:filename="${fileName}"则说明是直接在浏览器中显示。

另外还有一个参数,上述配置文件中没有配置:bufferSize下载文件的缓冲大小。

Jsp界面:

<body><a href="download?fileName=Struts2多个文件上传示例.doc">Struts2多个文件上传示例.doc</a></body>


当时一直用中文名的文件做测试,一次用英文做测试,结果成功了,才发现原来是文件中文名的原因。

原来struts中的配置文件是没有错误的,原来错误提示误导我,一直在寻找配置文件的原因。

中文乱码问题,这个问题,对于IT人士并不陌生。

分析:

jsp中有UTF-8进行编码,所以提交请求的url中,完全转换成了UTF-8,此时的提交的fileName也编码成了???.txt(若是上传文本格式的),在某一路径下寻找匹配的文件,当然会找不到。因此返回的文件流为null

解决的办法如下:

提交的请求文件名是用UTF-8进行编码,然后在actionUTF-8进行解码文件名。

代码如下:

  publicvoid setFileName(String fileName) {           try {        this.fileName = new String(fileName.getBytes("ISO-8859-1"),"UTF-8");         System.out.println(fileName);        } catch (UnsupportedEncodingException e) {        // TODO Auto-generated catch block        e.printStackTrace();      }   }

 这种办法就可以解决文件名是中文了。

若是按照以上这种方式写的话,确实能实现,并且能够成功下载。但是仍然会有一个问题。因为下载保存的时候不会保存中相应的类型,我们不知道要保存什么类型,当然也不知道用什么程序打开。

那如何解决呢?办法如下:在系统返回文件生成响应头信息,更改响应头信息。代码如下:

   public InputStream getFileStream() {        HttpServletResponse response = ServletActionContext.getResponse();          try {           response.setHeader("Content-Disposition", "attachment;fileName="                   + java.net.URLEncoder.encode(fileName,"UTF-8"));        } catch (UnsupportedEncodingException e) {           // TODO Auto-generated catch block           e.printStackTrace();        }      return ServletActionContext.getServletContext().getResourceAsStream("uploadFile\\"+fileName);   }

这样就OK了,即解决了中文文件名,又解决了保存相应类型的问题。

看到这种效果,心里才会挺舒服的。

但是,我还有一个疑问,请教路过的人解答。

在上述setFileName方法中,已经用UTF-8格式进行解码了。恢复到提交的中文参数文件名。但是为啥输出的结果仍然是???.doc呢?

this.fileName = new String(fileName.getBytes("ISO-8859-1"),"UTF-8");         System.out.println(fileName); 
原创粉丝点击