JSP中文件下载

<%--   
 
有些朋友询问使用 JSP Smart 下载文件的时候报错, 这里给出一个测试过的不  
 
需要使用 JSP Smart 的 JSP 页面中进行文件下载的代码(改 Servlet 或者  
 
JavaBean 的话自己改吧), 支持中文附件名(做了转内码处理). 事实上只要向  
 
out 输出字节就被认为是附件内容, 不一定非要从文件读取原始数据, 从数据  
 
库中读取也可以的.  
 
测试结果: Tomcat 5.0, 5.5, Resin 3.0.18 , Weblogic 8.1, 9.2 测试通过, 无异常产生   
 
--%>   
 
<% @ page contentType = " text/html; charset=GBK "  pageEncoding = " GBK "   %>   
 
<% @ page  import = " java.io.*, java.util.*, java.text.* "   %>   
 
 
 
<%!   
 
     /**  
 
     *  If returns true, then should return a 304 (HTTP_NOT_MODIFIED) 
 
      */   
 
     public   static   boolean  checkFor304( HttpServletRequest req,  
 
                                       File file )  
 
    {  
 
         //   
 
         //   We'll do some handling for CONDITIONAL GET (and return a 304)  
 
         //   If the client has set the following headers, do not try for a 304.  
 
         //   
 
         //     pragma: no-cache  
 
         //     cache-control: no-cache  
 
         //  
 
 
 
         if (  " no-cache " .equalsIgnoreCase(req.getHeader( " Pragma " ))  
 
             ||   " no-cache " .equalsIgnoreCase(req.getHeader( " cache-control " )))  
 
        {  
 
             //  Wants specifically a fresh copy   
 
        }  
 
         else   
 
        {  
 
             //   
 
             //   HTTP 1.1 ETags go first  
 
             //  
 
            String thisTag  =  Long.toString(file.lastModified());  
 
 
 
            String eTag  =  req.getHeader(  " If-None-Match "  );  
 
 
 
             if ( eTag  !=   null  )  
 
            {  
 
                 if ( eTag.equals(thisTag) )  
 
                {  
 
                     return   true ;  
 
                }  
 
            }  
 
 
 
             //   
 
             //   Next, try if-modified-since  
 
             //  
 
            DateFormat rfcDateFormat  =   new  SimpleDateFormat( " EEE, dd MMM yyyy HH:mm:ss z " );  
 
            Date lastModified  =   new  Date(file.lastModified());  
 
 
 
             try   
 
            {  
 
                 long  ifModifiedSince  =  req.getDateHeader( " If-Modified-Since " );  
 
 
 
                 // log.info("ifModifiedSince:"+ifModifiedSince);   
 
                 if ( ifModifiedSince  !=   - 1  )  
 
                {  
 
                     long  lastModifiedTime  =  lastModified.getTime();  
 
 
 
                     // log.info("lastModifiedTime:" + lastModifiedTime);   
 
                     if ( lastModifiedTime  <=  ifModifiedSince )  
 
                    {  
 
                         return   true ;  
 
                    }  
 
                }  
 
                 else   
 
                {  
 
                     try   
 
                    {  
 
                        String s  =  req.getHeader( " If-Modified-Since " );  
 
 
 
                         if ( s  !=   null  )  
 
                        {  
 
                            Date ifModifiedSinceDate  =  rfcDateFormat.parse(s);  
 
                             // log.info("ifModifiedSinceDate:" + ifModifiedSinceDate);   
 
                             if ( lastModified.before(ifModifiedSinceDate) )  
 
                            {  
 
                                 return   true ;  
 
                            }  
 
                        }  
 
                    }  
 
                     catch  (ParseException e)  
 
                    {  
 
                         // log.warn(e.getLocalizedMessage(), e);   
 
                    }  
 
                }  
 
            }  
 
             catch ( IllegalArgumentException e )  
 
            {  
 
                 //  Illegal date/time header format.  
 
                 //  We fail quietly, and return false.  
 
                 //  FIXME: Should really move to ETags.   
 
            }  
 
        }  
 
 
 
         return   false ;  
 
    }  
 
%>   
 
 
 
<%   
 
     //  String filePath = "c:/文档.doc";  
 
     //  如果是 WEB APP 下的相对路径文件, 请使用下列代码:   
 
    String filePath  =  application.getRealPath( " 测试文档.htm " );  
 
     boolean  isInline  =   false ; //  是否允许直接在浏览器内打开(如果浏览器能够预览此文件内容,  
 
     //  那么文件将被打开, 否则会提示下载)  
 
 
 
     //  清空缓冲区, 防止页面中的空行, 空格添加到要下载的文件内容中去  
 
     //  如果不清空的话在调用 response.reset() 的时候 Tomcat 会报错  
 
     //  java.lang.IllegalStateException: getOutputStream() has already been called for  
 
     //  this response,   
 
    out.clear();  
 
 
 
     //  {{{ BEA Weblogic 必读  
 
     //  修正 Bea Weblogic 出现 "getOutputStream() has already been called for this response"错误的问题  
 
     //  关于文件下载时采用文件流输出的方式处理:  
 
     //  加上response.reset(),并且所有的%>后面不要换行,包括最后一个;  
 
     //  因为Application Server在处理编译jsp时对于%>和<%之间的内容一般是原样输出,而且默认是PrintWriter,  
 
     //  而你却要进行流输出:ServletOutputStream,这样做相当于试图在Servlet中使用两种输出机制,  
 
     //  就会发生:getOutputStream() has already been called for this response的错误  
 
     //  详细请见《More Java Pitfill》一书的第二部分 Web层Item 33:试图在Servlet中使用两种输出机制 270  
 
     //  而且如果有换行,对于文本文件没有什么问题,但是对于其它格式,比如AutoCAD、Word、Excel等文件  
 
     // 下载下来的文件中就会多出一些换行符0x0d和0x0a,这样可能导致某些格式的文件无法打开,有些也可以正常打开。  
 
     //  同时这种方式也能清空缓冲区, 防止页面中的空行等输出到下载内容里去   
 
    response.reset();  
 
     //  }}}   
 
 
 
     try  {  
 
        java.io.File f  =   new  java.io.File(filePath);  
 
         if  (f.exists()  &&  f.canRead()) {  
 
             //  我们要检查客户端的缓存中是否已经有了此文件的最新版本, 这时候就告诉  
 
             //  客户端无需重新下载了, 当然如果不想检查也没有关系   
 
             if ( checkFor304( request, f ) )  
 
            {  
 
                 //  客户端已经有了最新版本, 返回 304   
 
                response.sendError( HttpServletResponse.SC_NOT_MODIFIED );  
 
                 return ;  
 
            }  
 
 
 
             //  从服务器的配置来读取文件的 contentType 并设置此contentType, 不推荐设置为  
 
             //  application/x-download, 因为有时候我们的客户可能会希望在浏览器里直接打开,  
 
             //  如 Excel 报表, 而且 application/x-download 也不是一个标准的 mime type,  
 
             //  似乎 FireFox 就不认识这种格式的 mime type   
 
            String mimetype  =   null ;  
 
            mimetype  =  application.getMimeType( filePath );  
 
             if ( mimetype  ==   null  )  
 
            {  
 
                mimetype  =   " application/octet-stream;charset=ISO8859-1 " ;  
 
            }  
 
 
 
            response.setContentType( mimetype );  
 
 
 
             //  IE 的话就只能用 IE 才认识的头才能下载 HTML 文件, 否则 IE 必定要打开此文件!   
 
            String ua  =  request.getHeader( " User-Agent " ); //  获取终端类型   
 
             if (ua  ==   null ) ua  =   " User-Agent: Mozilla/4.0 (compatible; MSIE 6.0;) " ;  
 
             boolean  isIE  =  ua.toLowerCase().indexOf( " msie " )  !=   - 1 ; //  是否为 IE   
 
 
 
             if (isIE  &&   ! isInline) {  
 
                mimetype  =   " application/x-msdownload " ;  
 
            }  
 
 
 
 
 
             //  下面我们将设法让客户端保存文件的时候显示正确的文件名, 具体就是将文件名  
 
             //  转换为 ISO8859-1 编码   
 
            String downFileName  =   new  String(f.getName().getBytes(),  " ISO8859-1 " );  
 
 
 
            String inlineType  =  isInline  ?   " inline "  :  " attachment " ; //  是否内联附件  
 
 
 
             //  or using this, but this header might not supported by FireFox  
 
             // response.setContentType("application/x-download");   
 
            response.setHeader ( " Content-Disposition " , inlineType  +   " ;filename=/ ""  
 
             +  downFileName  +   " / "" );   
 
 
 
            response.setContentLength(( int ) f.length()); //  设置下载内容大小   
 
 
 
             byte [] buffer  =   new   byte [ 4096 ]; //  缓冲区   
 
            BufferedOutputStream output  =   null ;  
 
            BufferedInputStream input  =   null ;  
 
 
 
             //  
 
             try  {  
 
                output  =   new  BufferedOutputStream(response.getOutputStream());  
 
                input  =   new  BufferedInputStream( new  FileInputStream(f));  
 
 
 
                 int  n  =  ( - 1 );  
 
                 while  ((n  =  input.read(buffer,  0 ,  4096 ))  >   - 1 ) {  
 
                    output.write(buffer,  0 , n);  
 
                }  
 
                response.flushBuffer();  
 
            }  
 
             catch  (Exception e) {  
 
            }  //  用户可能取消了下载   
 
             finally  {  
 
                 if  (input  !=   null ) input.close();  
 
                 if  (output  !=   null ) output.close();  
 
            }  
 
 
 
        }  
 
         return ;  
 
    }  catch  (Exception ex) {  
 
       // ex.printStackTrace();   
 
    }  
 
     //  如果下载失败了就告诉用户此文件不存在   
 
    response.sendError( 404 );  
 
%>  

<%--

有些朋友询问使用 JSP Smart 下载文件的时候报错, 这里给出一个测试过的不

需要使用 JSP Smart 的 JSP 页面中进行文件下载的代码(改 Servlet 或者

JavaBean 的话自己改吧), 支持中文附件名(做了转内码处理). 事实上只要向

out 输出字节就被认为是附件内容, 不一定非要从文件读取原始数据, 从数据

库中读取也可以的.

测试结果: Tomcat 5.0, 5.5, Resin 3.0.18 , Weblogic 8.1, 9.2 测试通过, 无异常产生

--%>

<% @ page contentType = " text/html; charset=GBK "  pageEncoding = " GBK "   %>

<% @ page  import = " java.io.*, java.util.*, java.text.* "   %>

 

<%!

     /**

     *  If returns true, then should return a 304 (HTTP_NOT_MODIFIED)

      */

     public   static   boolean  checkFor304( HttpServletRequest req,

                                       File file )

    {

         //

         //   We'll do some handling for CONDITIONAL GET (and return a 304)

         //   If the client has set the following headers, do not try for a 304.

         //

         //     pragma: no-cache

         //     cache-control: no-cache

         //

 

         if (  " no-cache " .equalsIgnoreCase(req.getHeader( " Pragma " ))

             ||   " no-cache " .equalsIgnoreCase(req.getHeader( " cache-control " )))

        {

             //  Wants specifically a fresh copy

        }

         else

        {

             //

             //   HTTP 1.1 ETags go first

             //

            String thisTag  =  Long.toString(file.lastModified());

 

            String eTag  =  req.getHeader(  " If-None-Match "  );

 

             if ( eTag  !=   null  )

            {

                 if ( eTag.equals(thisTag) )

                {

                     return   true ;

                }

            }

 

             //

             //   Next, try if-modified-since

             //

            DateFormat rfcDateFormat  =   new  SimpleDateFormat( " EEE, dd MMM yyyy HH:mm:ss z " );

            Date lastModified  =   new  Date(file.lastModified());

 

             try

            {

                 long  ifModifiedSince  =  req.getDateHeader( " If-Modified-Since " );

 

                 // log.info("ifModifiedSince:"+ifModifiedSince);

                 if ( ifModifiedSince  !=   - 1  )

                {

                     long  lastModifiedTime  =  lastModified.getTime();

 

                     // log.info("lastModifiedTime:" + lastModifiedTime);

                     if ( lastModifiedTime  <=  ifModifiedSince )

                    {

                         return   true ;

                    }

                }

                 else

                {

                     try

                    {

                        String s  =  req.getHeader( " If-Modified-Since " );

 

                         if ( s  !=   null  )

                        {

                            Date ifModifiedSinceDate  =  rfcDateFormat.parse(s);

                             // log.info("ifModifiedSinceDate:" + ifModifiedSinceDate);

                             if ( lastModified.before(ifModifiedSinceDate) )

                            {

                                 return   true ;

                            }

                        }

                    }

                     catch  (ParseException e)

                    {

                         // log.warn(e.getLocalizedMessage(), e);

                    }

                }

            }

             catch ( IllegalArgumentException e )

            {

                 //  Illegal date/time header format.

                 //  We fail quietly, and return false.

                 //  FIXME: Should really move to ETags.

            }

        }

 

         return   false ;

    }

%>

 

<%

     //  String filePath = "c:/文档.doc";

     //  如果是 WEB APP 下的相对路径文件, 请使用下列代码:

    String filePath  =  application.getRealPath( " 测试文档.htm " );

     boolean  isInline  =   false ; //  是否允许直接在浏览器内打开(如果浏览器能够预览此文件内容,

     //  那么文件将被打开, 否则会提示下载)

 

     //  清空缓冲区, 防止页面中的空行, 空格添加到要下载的文件内容中去

     //  如果不清空的话在调用 response.reset() 的时候 Tomcat 会报错

     //  java.lang.IllegalStateException: getOutputStream() has already been called for

     //  this response,

    out.clear();

 

     //  {{{ BEA Weblogic 必读

     //  修正 Bea Weblogic 出现 "getOutputStream() has already been called for this response"错误的问题

     //  关于文件下载时采用文件流输出的方式处理:

     //  加上response.reset(),并且所有的%>后面不要换行,包括最后一个;

     //  因为Application Server在处理编译jsp时对于%>和<%之间的内容一般是原样输出,而且默认是PrintWriter,

     //  而你却要进行流输出:ServletOutputStream,这样做相当于试图在Servlet中使用两种输出机制,

     //  就会发生:getOutputStream() has already been called for this response的错误

     //  详细请见《More Java Pitfill》一书的第二部分 Web层Item 33:试图在Servlet中使用两种输出机制 270

     //  而且如果有换行,对于文本文件没有什么问题,但是对于其它格式,比如AutoCAD、Word、Excel等文件

     // 下载下来的文件中就会多出一些换行符0x0d和0x0a,这样可能导致某些格式的文件无法打开,有些也可以正常打开。

     //  同时这种方式也能清空缓冲区, 防止页面中的空行等输出到下载内容里去

    response.reset();

     //  }}}

 

     try  {

        java.io.File f  =   new  java.io.File(filePath);

         if  (f.exists()  &&  f.canRead()) {

             //  我们要检查客户端的缓存中是否已经有了此文件的最新版本, 这时候就告诉

             //  客户端无需重新下载了, 当然如果不想检查也没有关系

             if ( checkFor304( request, f ) )

            {

                 //  客户端已经有了最新版本, 返回 304

                response.sendError( HttpServletResponse.SC_NOT_MODIFIED );

                 return ;

            }

 

             //  从服务器的配置来读取文件的 contentType 并设置此contentType, 不推荐设置为

             //  application/x-download, 因为有时候我们的客户可能会希望在浏览器里直接打开,

             //  如 Excel 报表, 而且 application/x-download 也不是一个标准的 mime type,

             //  似乎 FireFox 就不认识这种格式的 mime type

            String mimetype  =   null ;

            mimetype  =  application.getMimeType( filePath );

             if ( mimetype  ==   null  )

            {

                mimetype  =   " application/octet-stream;charset=ISO8859-1 " ;

            }

 

            response.setContentType( mimetype );

 

             //  IE 的话就只能用 IE 才认识的头才能下载 HTML 文件, 否则 IE 必定要打开此文件!

            String ua  =  request.getHeader( " User-Agent " ); //  获取终端类型

             if (ua  ==   null ) ua  =   " User-Agent: Mozilla/4.0 (compatible; MSIE 6.0;) " ;

             boolean  isIE  =  ua.toLowerCase().indexOf( " msie " )  !=   - 1 ; //  是否为 IE

 

             if (isIE  &&   ! isInline) {

                mimetype  =   " application/x-msdownload " ;

            }

 

 

             //  下面我们将设法让客户端保存文件的时候显示正确的文件名, 具体就是将文件名

             //  转换为 ISO8859-1 编码

            String downFileName  =   new  String(f.getName().getBytes(),  " ISO8859-1 " );

 

            String inlineType  =  isInline  ?   " inline "  :  " attachment " ; //  是否内联附件

 

             //  or using this, but this header might not supported by FireFox

             // response.setContentType("application/x-download");

            response.setHeader ( " Content-Disposition " , inlineType  +   " ;filename=/ ""

             +  downFileName  +   " / "" );

 

            response.setContentLength(( int ) f.length()); //  设置下载内容大小

 

             byte [] buffer  =   new   byte [ 4096 ]; //  缓冲区

            BufferedOutputStream output  =   null ;

            BufferedInputStream input  =   null ;

 

             //

             try  {

                output  =   new  BufferedOutputStream(response.getOutputStream());

                input  =   new  BufferedInputStream( new  FileInputStream(f));

 

                 int  n  =  ( - 1 );

                 while  ((n  =  input.read(buffer,  0 ,  4096 ))  >   - 1 ) {

                    output.write(buffer,  0 , n);

                }

                response.flushBuffer();

            }

             catch  (Exception e) {

            }  //  用户可能取消了下载

             finally  {

                 if  (input  !=   null ) input.close();

                 if  (output  !=   null ) output.close();

            }

 

        }

         return ;

    }  catch  (Exception ex) {

       // ex.printStackTrace();

    }

     //  如果下载失败了就告诉用户此文件不存在

    response.sendError( 404 );

%> 发表于 @ 2008年06月26日 11:31:00 | 评论( 2 ) | 编辑| 举报| 收藏

旧一篇:JSP中的中文字符处理(转贴) | 新一篇:java经典题目---1(转贴) fulianglove 发表于2008年6月26日 12:40:50  IP:举报
简单点的:
<%
response.setContentType(fileminitype);
response.setHeader("Location",filename);
response.setHeader("Cache-Control", "max-age=" + cacheTime);
response.setHeader("Content-Disposition", "attachment; filename=" + filename); //filename应该是编码后的(utf-8)
response.setContentLength(filelength);
OutputStream outputStream = response.getOutputStream();
InputStream inputStream = new FileInputStream(filepath);
byte[] buffer = new byte[1024];
int i = -1;
while ((i = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, i);
}
outputStream.flush();
outputStream.close();
inputStream.close();
outputStream = null;

%>


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/fulianglove/archive/2008/06/26/2588085.aspx

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值