Select解决中文文件下载问题

刚刚学完在Servlet中解决下载中文文件的知识,稍稍总结一下。


首先贴上HTML代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>文件下载</title>
</head>
<body>
    <h1>通过服务器端编码的方式实现文件下载</h1>
    <a href="/download?filename=a.jpg">a.jpg</a><br>
    <a href="/download?filename=a.flv">a.flv</a><br>
    <a href="/download?filename=a.mp3">a.mp3</a><br>
    <a href="/download?filename=a.mp4">a.mp4</a><br>
    <a href="/download?filename=a.txt">a.txt</a><br>
    <a href="/download?filename=a.zip">a.zip</a><br>
    <a href="/download2?filename=美女.jpg">美女.jpg</a><br>

</body>
</html>

因为通过a便签的形式进行链接转跳,并且包含了参数filename。因此可以在java代码中使用下列代码获取:

 String filename = request.getParameter("filename"); 


但是因此产生了一个问题,获取的参数是中文,但是Tomcat的编码不支持中文,因此会将参数解析为乱码。

此时点击下载标签会出现500错误。

因此,对filename参数重新编码如下:

 //解决中文参数的乱码问题
        filename = new String(filename.getBytes("ISO8859-1"),"UTF-8");//美女.jpg

此时,文件下载代码如下:
//设置下载类型  -- 需要根据服务器的资源后缀名进行获取,因此使用filename变量
        response.setContentType(this.getServletContext().getMimeType(filename));
        //设置header。通知客户端以附件的形式打开,而不需要解析
        response.setHeader("Content-Disposition","attachment;filename="+filenameEncoder);

        //获取文件的绝对路径
        String path = this.getServletContext().getRealPath("download/" + filename);

        //获取文件输入流
        InputStream in = new FileInputStream(path);

        //获取文件输出流
        ServletOutputStream out = response.getOutputStream();

        //向客户端输出文件
        int len = 0;
        byte[] buff = new byte[1024];
        while ((len = in.read(buff)) != -1){
            out.write(buff,0,len);
        }

        //关闭连接
        in.close();         //需要手动关闭,因为是自己new的
//      out.close();        //在开发中一般不需要手动关闭此连接,因为容器会自动检测并关闭

代码中的filenameEncoder下面会进行说明


此时,客户端会将文件进行下载,但是文件名依然是乱码或者其他现象。

那是因为不同客户端会使用他们默认的解码方式对文件名进行解码,导致文件下载出错。

因此我们需要手动修改响应头中的User-Agent来指定解码方式。

代码如下:

  String filenameEncoder = "";
        String agent = request.getHeader("User-Agent");

        if (agent.contains("MSIE")) {
            // IE浏览器
            filenameEncoder = URLEncoder.encode(filename, "utf-8");
            filenameEncoder = filenameEncoder.replace("+", " ");
        } else if (agent.contains("Firefox")) {
            // 火狐浏览器
            BASE64Encoder base64Encoder = new BASE64Encoder();
            filenameEncoder = "=?utf-8?B?"
                    + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
        } else {
            // 其它浏览器
            filenameEncoder = URLEncoder.encode(filename, "utf-8");
        }

完成以上操作后,中文文件下载问题解决。

完整代码:

package com.liweijian.content;

import sun.misc.BASE64Encoder;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;

/**
 * @Author:Liweijian
 * @Description: 解决中文文件下载
 * @Date:Create in 20:14 2017/11/16 0016
 */
@WebServlet(name = "DownloadServlet2")
public class DownloadServlet2 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //获取传递进来的filename参数
        String filename = request.getParameter("filename"); //????.jpg

            //解决中文参数的乱码问题
            filename = new String(filename.getBytes("ISO8859-1"),"UTF-8");//美女.jpg

        //因为客户端会对该文件名进行默认解码,所以可能导致下载的文件名出错。
        //因此,需要使用相应的客户端编码格式进行编码
        String filenameEncoder = "";
        String agent = request.getHeader("User-Agent");

        if (agent.contains("MSIE")) {
            // IE浏览器
            filenameEncoder = URLEncoder.encode(filename, "utf-8");
            filenameEncoder = filenameEncoder.replace("+", " ");
        } else if (agent.contains("Firefox")) {
            // 火狐浏览器
            BASE64Encoder base64Encoder = new BASE64Encoder();
            filenameEncoder = "=?utf-8?B?"
                    + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
        } else {
            // 其它浏览器
            filenameEncoder = URLEncoder.encode(filename, "utf-8");
        }


        //设置下载类型  -- 需要根据服务器的资源后缀名进行获取,因此使用filename变量
        response.setContentType(this.getServletContext().getMimeType(filename));
        //设置header。通知客户端以附件的形式打开,而不需要解析
        response.setHeader("Content-Disposition","attachment;filename="+filenameEncoder);

        //获取文件的绝对路径
        String path = this.getServletContext().getRealPath("download/" + filename);

        //获取文件输入流
        InputStream in = new FileInputStream(path);

        //获取文件输出流
        ServletOutputStream out = response.getOutputStream();

        //向客户端输出文件
        int len = 0;
        byte[] buff = new byte[1024];
        while ((len = in.read(buff)) != -1){
            out.write(buff,0,len);
        }

        //关闭连接
        in.close();         //需要手动关闭,因为是自己new的
//      out.close();        //在开发中一般不需要手动关闭此连接,因为容器会自动检测并关闭
    }
}


说明 这个控件实现相当简单,基于jQuery实现,只编写一些基本功能,满足一般使用。提供原代码,可以根据自己的项目要求修改,只在IE6、IE7、IE8、IE9中测试。有问题联系邮箱:zliuyao2010@163.com 初始化构造 构造方法在:input表单添加class="e_select"属性 属性说明:class="e_select" 构造下拉框 属性说明:etop="0" 控件下图片位置,默认可以不用添加此属性。 属性说明:edata="{,普通:普通AA,模糊:模糊,右边模糊:右边模糊}" or {"":"","男":"男1","女":"女1","其他":"其他1"} 下拉框控件中的值,注意:支持两种赋值,json格式以及键值对形式,PS:若下拉列表中有空值键对用英文的“,”,json格式用:"":""。 属性说明:echange="echange" 选择下拉值的回调方法名称,PS:只要输入方法名称,调用方法中有两个参数key(键) 和 value(值) 例如:function echange(key,value) {alert(key + " " + value);} 动态赋值 function setValue() { jQuery("#text1").val("").attr("data","");//赋值请清空原来的值(很重要) jQuery("#text1").attr("edata",'{"":"","男":"男1","女":"女1","其他":"其他1"}'); } 获取值 function getValue() { alert("key:"+document.getElementById("text1").value + " value:" + document.getElementById("text1").data); } 事件 function echange(key,value) { alert("key:"+key + " " + "value:"+value); } 测试 省: 市: 区: 普通模糊右边模糊普通模糊右边模糊普通模糊右边模糊
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值