Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1471550
  • 博文数量: 254
  • 博客积分: 8696
  • 博客等级: 中将
  • 技术积分: 2961
  • 用 户 组: 普通用户
  • 注册时间: 2008-04-03 16:46
文章分类

全部博文(254)

文章存档

2015年(4)

2014年(18)

2013年(16)

2012年(8)

2011年(25)

2010年(2)

2009年(74)

2008年(107)

分类: Java

2009-08-27 20:21:46

<%--
有些朋友询问使用 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 );
%>
阅读(3106) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~