解决Struts2下载中文文件乱码问题 图片看不了?点击切换HTTP 返回上层
通过《Struts2文件下载实例》的学习,读者已经学会了如何使用 Struts2 框架实现文件下载,但是细心的读者会发现,如果上传一个中文名称的文件(如文本文件.txt),再次下载此文件时,页面会报出 500 错误,如图 1 所示。

图 1 中文文件下载报错
之所以出现图 1 中的错误,是因为所要下载的文件不存在,导致 inputStream 为 null,所以报出了 500 错误。这里读者一定会很费解,明明上传了一个新文件,并可以确认文件在文件夹中是存在的,那么为什么还会报出此错误呢?
如果在 SimpleDownLoadAction 类的第 21 行代码中设置断点,并采用 Debug 模式调试执行程序,会发现传递到 Action 中的中文名称变成了乱码,如图 2 所示。

图 2 中文乱码
从图 2 中可以看到,页面中传递的“测试.txt”已经变为“æµè¯.txt”,这说明在传递过程中,中文名称发生了乱码。然而在实际应用中,下载中文文件是不可避免的。下面本节将通过一个具体的案例讲解如何使用 Struts2 框架下载中文文件。
上述代码中,声明了 filename 和 contentType 两个属性,分别代表所要下载文件的名称和类型。
在 filename 属性的 getter() 方法中,通过 encodeDownloadFilename(String name,String agent) 方法对不同浏览器传过来的名称进行编码,在其 setter() 方法中,对其文件名称又进行了一次编码,使文件名称统一为 UTF-8 编码格式。
通过 contentType 属性的 getContentType() 方法获取了文件的类型,并在 getFileDownload() 方法中定义了要下载的文件路径,并返回一个输入流。
在上述配置代码中,${contentType} 和 ${filename} 会在项目运行时,将 action 中的对象属性动态地填充在 ${} 中间部分,相当于 action.getContentType() 和 action.getFilename(),通过此种方式动态地获取文件的类型和名称。

图 3 中文文件下载

图 1 中文文件下载报错
之所以出现图 1 中的错误,是因为所要下载的文件不存在,导致 inputStream 为 null,所以报出了 500 错误。这里读者一定会很费解,明明上传了一个新文件,并可以确认文件在文件夹中是存在的,那么为什么还会报出此错误呢?
如果在 SimpleDownLoadAction 类的第 21 行代码中设置断点,并采用 Debug 模式调试执行程序,会发现传递到 Action 中的中文名称变成了乱码,如图 2 所示。

图 2 中文乱码
从图 2 中可以看到,页面中传递的“测试.txt”已经变为“æµè¯.txt”,这说明在传递过程中,中文名称发生了乱码。然而在实际应用中,下载中文文件是不可避免的。下面本节将通过一个具体的案例讲解如何使用 Struts2 框架下载中文文件。
1)创建文件下载页面
在项目的 WebContent 目录中创建一个名称为 filedownload.jsp 的文件,在文件中添加一个中文链接,其代码如下所示:<s:a href="filedownload?filename=测试.txt" name="test">测试.txt</s:a>
2)创建 Action 类
在 com.mengma.action 包中新建一个名称为 FileDownLoadAction 的类,该类是用于下载文件的 Action,编辑后如下所示。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | package com.mengma. action ; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import org.apache.struts2.ServletActionContext; import sun.misc.BASE64Encoder; import com.opensymphony.xwork2.ActionSupport; public class FileDownLoadAction extends ActionSupport { private String filename; // 代表下载文件的名称 private String contentType; // 下文件的 MimeType /** * 获取文件的名称 */ public String getFilename() throws IOException { // 对不同浏览器传过来的文件名进行编码 return encodeDownloadFilename(filename, ServletActionContext .getRequest().getHeader( "User-Agent" )); } public void setFilename(String filename) throws UnsupportedEncodingException { // 对文件名称编码 filename = new String(filename.getBytes( "iso8859-1" ), "utf-8" ); this.filename = filename; } /** * 获取文件的类墩 */ public String getContentType() { return ServletActionContext.getServletContext().getMimeType(filename); } public void setContentType(String contentType) { this.contentType = contentType; } // 定义了返回InputStream的方法,该方法作为被下载文件的入口 public InputStream getFileDownload() { // 要下载的文件的路径 String filepath = "/upload/" + filename; return ServletActionContext.getServletContext().getResourceAsStream( filepath); } /* * 对不同浏览器传过來的文件名称进行转码 * @param name 文件名窗; * @param agenr浏览器 * @ return 转码后的名称 */ public String encodeDownloadFilename(String name , String agent) throws IOException { if (agent. contains ( "Firefox" )) { // 火孤浏览器 name = "=?UTF-8?B?" + new BASE64Encoder().encode( name .getBytes( "utf-8" )) + "?=" ; } else { // IE及其他浏览器 name = URLEncoder.encode( name , "utf-8" ); } return name ; } } |
在 filename 属性的 getter() 方法中,通过 encodeDownloadFilename(String name,String agent) 方法对不同浏览器传过来的名称进行编码,在其 setter() 方法中,对其文件名称又进行了一次编码,使文件名称统一为 UTF-8 编码格式。
通过 contentType 属性的 getContentType() 方法获取了文件的类型,并在 getFileDownload() 方法中定义了要下载的文件路径,并返回一个输入流。
3)修改配置文件
在 struts.xml 文件中,增加 FileDownLoadAction 的配置信息,其代码如下所示:1 2 3 4 5 6 7 8 9 10 11 12 | < action name = "filedownload" class= "com.mengma.action.FileDownLoadAction" > <result type= "stream" > <! --文件类型 --> <param name = "contentType" >${contentType}</param> <! --指定文件名 --> <param name = "contentDisposition" > attachment;filename=${filename} </param> <! --输入流入口 --> <param name = "inputName" >filedownload</param> </result> </ action > |
4)运行程序并查看结果
在浏览器的地址栏中输入地址 http://localhost:8080/struts2Demo06/filedownload.jsp,成功访问后,单击页面中的“测试.txt”链接,其效果如图 3 所示。
图 3 中文文件下载