3.2K Star 8.8K Fork 3.6K

GVPJFinal / JFinal

 / 详情

中文文件名的文件下载时,文件名乱码

已完成
创建于  
2016-01-15 11:34

在使用 renderFile 进行下载操作的时候,发现文件名是乱码的,文件的内容是ok的,查看了一下源码,发现是 FileRender 里强制转换成了 GBK,但是我的文件名是存在编码为 UTF-8 的数据库里的,个人猜想是这个原因导致乱码的,但是源码的设计使得很难扩展,求思路。
部分源码截图

评论 (9)

其实这个将 GBK 转成 ISO8859-1 就是为了支持中文名的,测试是可以支持utf-8也可以支持,出现这个问题原因暂时不明,建议自建一个 MyFileRender 然后覆盖 render 方法,将这个地方改一下,用的时候这么用: render(new MyFileRender(...)),解决问麻烦过来反馈一下,另外解决中文问题后要再试试英文文件名,目前 jfinal 的做法就是为了支持中英文

自己重写了一个 render 结果就ok了。代码如下:

public class MyFileRender extends Render {

    private static final String DEFAULT_FILE_CONTENT_TYPE = "application/octet-stream";
    private File file;
    private ServletContext servletContext;

    public MyFileRender(String fileName) {
        if(StrKit.isBlank(fileName)) {
            throw new IllegalArgumentException("fileName can not be blank.");
        } else {
            fileName = fileName.trim();
            String fullFileName;
            String baseDownloadPath = InternShipManagementConfig.FILE_HOST;
            if(!fileName.startsWith("/") && !fileName.startsWith("\\")) {
                fullFileName = baseDownloadPath + File.separator + fileName;
            } else if(baseDownloadPath.equals("/")) {
                fullFileName = fileName;
            } else {
                fullFileName = baseDownloadPath + fileName;
            }

            this.file = new File(fullFileName);
        }
        this.servletContext = JFinal.me().getServletContext();
    }
     
    public MyFileRender(File file) {
        this.file = file;
        this.servletContext =  JFinal.me().getServletContext();
    }
 
    @Override
    public void render() {
         
        if (file == null || !file.isFile() || file.length() > Integer.MAX_VALUE) {
            RenderFactory.me().getErrorRender(404).setContext(request, response).render();
            return ;
        }
        //源码中的代码
        //response.addHeader("Content-disposition", "attachment; filename=" + file.getName());
        //修改后的代码 解决中文乱码问题
        try {
            response.addHeader("Content-disposition", 
                "attachment; filename=" + new String(file.getName().getBytes("utf-8"), "ISO8859-1"));
        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
        }
        String contentType = servletContext.getMimeType(file.getName());
        if (contentType == null) {
            contentType = DEFAULT_FILE_CONTENT_TYPE;        // "application/octet-stream";
        }
         
        response.setContentType(contentType);
        response.setContentLength((int)file.length());
        InputStream inputStream = null;
        OutputStream outputStream = null;
        try {
            inputStream = new BufferedInputStream(new FileInputStream(file));
            outputStream = response.getOutputStream();
            byte[] buffer = new byte[1024];
            for (int n = -1; (n = inputStream.read(buffer)) != -1;) {
                outputStream.write(buffer, 0, n);
            }
            outputStream.flush();
        }
        catch (Exception e) {
            throw new RenderException(e);
        }
        finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

这是我在网上找到的重写 render 的代码,其中我就只是修改了 encoding,new String(file.getName().getBytes("utf-8"), "ISO8859-1")) 就改了这句,把 UTF8 转为 ISO8859-1。(其中的 baseDownloadPath 不知道在 constants.setBaseDownloadPath 后怎么去 get
出来,所以这里用了自己定义的一个全局变量,顺便请教一下)

我觉得是不是可以提供一个设置 encoding 的方法呢?感觉这样会更加方便开发者想要去定制

@MadisonRong 麻烦测试一下这种解决方案下中文文件名是否支持? jfinal 当前的实现本质上是为了支持中文

他说这种方案能解决中文文件名,他的文件名是从数据库拿出来的,数据库是使用UTF-8编码,所以用GBK获取文件名会乱码。 而jfinal源码可能是直接读取系统的文件名,所以用了GBK,这是我的猜测

@JFinal 楼上表达了我的意思了,我的文件名的那个字符串是从一个编码为 UTF-8 的数据库里读取出来的,我也猜想可能是这个原因导致我在用 jFinal 的 renderFile 的时候中文文件名会乱码。经过测试,我这样做法,中英文都ok。

@MadisonRong 这里已做出改进,encodeFileName() 方法已改为 protected方便继承扩展,并且代码改为了:return new String(fileName.getBytes(getEncoding()), "ISO8859-1");使用系统设置的encoding,应该可以了,下一版本会更新这里,感谢反馈。

@MadisonRong @whyyy 现在可以通过升级到 jfinal 2.2 来解决问题了:http://www.oschina.net/news/70001/jfinal-2-2

状态更改为 已关闭

@JFinal 嗯,收到微信的推送了,有看到更新

登录 后才可以发表评论

状态
负责人
里程碑
Pull Requests
关联的 Pull Requests 被合并后可能会关闭此 issue
分支
开始日期   -   截止日期
-
置顶选项
优先级
参与者(3)
840 jfinal 1580661334 21206 madisonrong 1578915370 89849 whyyy 1578917022
Java
1
https://gitee.com/jfinal/jfinal.git
git@gitee.com:jfinal/jfinal.git
jfinal
jfinal
JFinal

搜索帮助

344bd9b3 5694891 D2dac590 5694891