关闭

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

标签: strutsactionstringexceptionjspdownload
3360人阅读 评论(7) 收藏 举报
分类:

在调试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 block
			e.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); 
12
1

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:1097180次
    • 积分:14627
    • 等级:
    • 排名:第796名
    • 原创:178篇
    • 转载:9篇
    • 译文:1篇
    • 评论:1649条
    博客专栏
    最新评论