论坛首页 Java企业应用论坛

(原)download后回调刷新页面思路

浏览 2950 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2010-03-06   最后修改:2010-03-06
企业级应用中,经常有要下载***文件的功能。为了减少服务器负担。经常在按下提交按钮的时候,让整张页面处于不可用的状态,以减少重复提交。现在比较流行的做法是用一个大的DIV罩住整个页面。等刷新的时候,DIV因为没有加载,所以页面复原。

这个时候,问题就来了。

看以下代码
response.reset();//可以加也可以不加
response.setContentType("application/x-download");//设置为下载application/x-download
 

String fileNameDisplay = "***.文件名";
fileNameDisplay = URLEncoder.encode(fileNameDisplay,"UTF-8");
    response.addHeader("Content-Disposition","attachment;filename=" + fileNameDisplay);

String fileNameDownload = this.getClass().getClassLoader().getResource("/").getPath() + fileNameDisplay;

OutputStream output = null;
FileInputStream fis = null;
try {
    output  = response.getOutputStream();
    fis = new FileInputStream(fileNameDownload);

    byte[] b = new byte[1024];
    int i = 0;

    while((i = fis.read(b)) > 0)
    {
        output.write(b, 0, i);
    }
    output.flush();
}
catch(Exception e)
{
    System.out.println("Error!");
    e.printStackTrace();
}
finally {
    if(fis != null) {
        fis.close();
        fis = null;
    }
    if(output != null) {
        output.close();
        output = null;
    }
}

上面的是很典型的download代码

但是在download的过程中,由于强制将文件流写入response,加上调用了out.close();原来的response将不会去刷新页面。

解决方法一:(适用范围IE7+)此方法在IE6下有此属性,但是测试无效
将download Form的target指向一个iframe。(如果是dialog画面,也可以改变base的target)并且加上以下代码

<iframe id="iframe" name="iframe" width="0px" height="0px"></frame>

注意,这里id和name必须都设,这样才能在IE和Firefox下都支持

var iframe = document.getElementById('iframe');
iframe.onreadystatechange = function() {
    if (iframe.readyState = "interactive") {
        // 这里写还原页面的代码
    }
}

readyState有4种状态
loading     Object is loading its data.
loaded      Object has finished loading its data.
interactive User can interact with the object even though it is not fully loaded.
complete    Object is completely initialized.

当执行out.close()的时候,IE7下刚好执行到interactive,但是在IE6下就无效
在其他浏览器下,网上很多人推荐监听iframe的onload句柄。但是一旦out.close,就不触发onload,所以此法无效

方法二(跟浏览器无关)
思路:
企业级应用下载最花时间的是查询和生成文件操作。所以把这些功能和download分开

先在服务器端生成好一个文件。(这段时间页面上显示遮罩DIV)
加上以下代码
// 在session中放入同步令牌
session.setAttribute(DOWNLOAD_TOKEN, 随机数字);


然后不download,直接回来刷新页面
接下来在页面的onload里执行以下代码

<script type="text/javascript">

// 这里的serverFilePath=你服务器上用于download的路径+文件名(需要在web.xml或者(如果是struts,则要在struts-config.xml里配置))
function downloadFile(serverFilePath) {
    var iframe = document.getElementById('iframe');
    if (iframe) {
        iframe.src = serverFilePath;
    } else {
        window.open(serverFilePath);
    }
}
</script>

<body onload="downloadFile('${serverFilePath}')">
   <input type="hidden" value="${DOWNLOAD_TOKEN}"/>
</body>


然后在download的那个Servlet里,判断同步令牌里的数字是否一样。
一样则先
session.remove(DOWNLOAD_TOKEN);
然后download
最后删除文件
虽然问题还是有的,但是由于是用看不见的iframe,所以不用担心重复刷新。
   发表时间:2010-03-06  
好復雜哦。
提供的是下載功能,直接通過<a href='文件url連接'>方式指向文件的url給用戶進行下載不就好了嗎?

如果是大量的下載,通過FileInputStream方式下載對服務器的壓力還是挺大的.
如果可以,直接把文件放到web目錄下,直接由web服務器進行處理.

另外,既然是文件下載,一定牽扯到服務器帶寬的占用,建議還是把下載分流到其他的ip上去.我前公司的下載也是采用了這種方式.
0 请登录后投票
   发表时间:2010-03-06  
谢谢你的回复。

如果用<a href 会让服务器端目录结构直接暴露在外边。如果将下载目录放在WEB-INF中,则安全性太高,外界无法直接连到文件。

如果在架构层面上用上同步令牌,可以在一定程度上解决这个问题
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics