作者: BeanSoft@126.com 整理: 2011-2-2 来源: http://www.beansoft.biz/

<%–
有些朋友询问使用 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.* "   %> </p>

</span><%!
   
/**
     *  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()); </p>

            String eTag </span>= req.getHeader( " If-None-Match " ); </p>

            </span>if ( eTag !=   null )
            {
               
if ( eTag.equals(thisTag) )
                {
                   
return   true ;
                }
            } </p>

            </span>//
           
//   Next, try if-modified-since
           
//
            DateFormat rfcDateFormat =   new SimpleDateFormat( " EEE, dd MMM yyyy HH:mm:ss z " );
            Date lastModified
=   new Date(file.lastModified()); </p>

            </span>try
            {
               
long ifModifiedSince = req.getDateHeader( " If-Modified-Since " ); </p>

                </span>// log.info("ifModifiedSince:"+ifModifiedSince);
                if ( ifModifiedSince !=   1 )
                {
                   
long lastModifiedTime = lastModified.getTime(); </p>

                    </span>// log.info("lastModifiedTime:" + lastModifiedTime);
                    if ( lastModifiedTime <= ifModifiedSince )
                    {
                       
return   true ;
                    }
                }
               
else
                {
                   
try
                    {
                        String s
= req.getHeader( " If-Modified-Since " ); </p>

                        </span>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.
            }
        } </p>

        </span>return   false ;
    }
%> </p>

</span><%
   
// String filePath = "c:/文档.doc";
   
// 如果是 WEB APP 下的相对路径文件, 请使用下列代码:
    String filePath = application.getRealPath( " 测试文档.htm " );
   
boolean isInline =   false ; // 是否允许直接在浏览器内打开(如果浏览器能够预览此文件内容,
   
// 那么文件将被打开, 否则会提示下载) </p>

    </span>// 清空缓冲区, 防止页面中的空行, 空格添加到要下载的文件内容中去
   
// 如果不清空的话在调用 response.reset() 的时候 Tomcat 会报错
   
// java.lang.IllegalStateException: getOutputStream() has already been called for
   
// this response,
    out.clear(); </p>

    </span>// }

   
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 ;
            } </p>

            </span>// 从服务器的配置来读取文件的 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 " ;
            } </p>

            response.setContentType( mimetype );

            </span>// IE 的话就只能用 IE 才认识的头才能下载 HTML 文件, 否则 IE 必定要打开此文件!
            String ua = request.getHeader( " User-Agent " ); // 获取终端类型
            if (ua ==   null ) ua =   " User-Agent: Mozilla/4.0 (compatible; MSIE 6.0;) " ;
           
boolean isI
E
= ua.toLowerCase().indexOf( " msie " ) !=   1 ; // 是否为 IE

           
if (isIE &&   ! isInline) {
                mimetype
=   " application/x-msdownload " ;
            } </p>

            </span>// 下面我们将设法让客户端保存文件的时候显示正确的文件名, 具体就是将文件名
           
// 转换为 ISO8859-1 编码
            String downFileName =   new String(f.getName().getBytes(), " ISO8859-1 " ); </p>

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

            </span>// 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 ; </p>

            </span>//
            try {
                output
=   new BufferedOutputStream(response.getOutputStream());
                input
=   new BufferedInputStream( new FileInputStream(f)); </p>

                </span>int n = ( 1 );
               
while ((n = input.read(buffer, , 4096 )) >   1 ) {
                    output.write(buffer,
, n);
                }
                response.flushBuffer();
            }
           
catch (Exception e) {
            }
// 用户可能取消了下载
            finally {
               
if (input !=   null ) input.close();
               
if (output !=   null ) output.close();
            } </p>

        }
        </span>return ;
    }
catch (Exception ex) {
     
// ex.printStackTrace();
    }
   
// 如果下载失败了就告诉用户此文件不存在
    response.sendError( 404 );
%> </div>

</div> </p></div> </p></div>

转载请注明:WebLogic Android 博客 » JSP 文件下载的相对完整代码(解决中文问题和Weblogic报错)