一、问题说明

现在前端页面为

相应的代码为:(逻辑在downloadButtonClicked方法中实现)

downloadDemo.jsp(路径为src\main\webapp\datadisplay\downloadDemo.jsp)

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>文件下载demo</title>
</head>
<body>
    <input type="hidden" id="path" value="${pageContext.request.contextPath}"/>
    <h3>无跳转文件下载</h3>
    <input type="button" value="下载" id="downloadBtn" onclick="downloadFile('测试下载.txt')"/>
    <script src="http://libs.baidu.com/jquery/1.8.3/jquery.js"></script>
    <script type="text/javascript">
        function downloadFile(resourceName) {
            var url = $("#path").val() + "/datadisplay/testDownload.action?resourceName=" + resourceName;
            downloadButtonClicked(url);
        }
        function downloadButtonClicked(url) {
        }
    </script>
</body>
</html>

二、解决过程

我看到一般的解决方法都是

window.location.href=下载的url

但是我这个页面在downloadButtonClicked方法中如果这样写,一点击下载按钮,页面直接就跳转了

 

我想到最近看的后台管理系统(若依)里的导出excel用的就是window.location.href,那为什么整个页面没有跳转呢?

咱们先debug,看看页面结构再说

看到这里,我突然明白了,这段改的就是iframe的src

 

这就给我提供了一个思路:通过改iframe的src来实现下载时页面不用跳转

但现在我的页面没有iframe,该怎么办?那就给个隐藏的iframe,用来给下载改地址使用,代码如下:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>文件下载demo</title>
</head>
<body>
    <input type="hidden" id="path" value="${pageContext.request.contextPath}"/>
    <h3>无跳转文件下载</h3>
    <input type="button" value="下载" id="downloadBtn" onclick="downloadFile('测试下载.txt')"/>
    <iframe style="display:none;" name="hiddenIframe" id="hiddenIframe"></iframe>
    <script src="http://libs.baidu.com/jquery/1.8.3/jquery.js"></script>
    <script type="text/javascript">
        function downloadFile(resourceName) {
            var url = $("#path").val() + "/datadisplay/testDownload.action?resourceName=" + resourceName;
            downloadButtonClicked(url);
        }
        function downloadButtonClicked(url) {
			// 这里需要加上encodeURI,因为ie不会对中文自动转码
            $("#hiddenIframe").attr("src", encodeURI(url));
        }
    </script>
</body>
</html>

这样就ok了(在chrome、firefox、ie下测试均能正常使用)

 

顺便补充下:1. 我开始是先google搜索了“javascript no redirect page download”,然后找到一个比较近似的结果(https://stackoverflow.com/questions/1066452/easiest-way-to-open-a-download-window-without-navigating-away-from-the-page)。思路就是创建一个虚拟的a标签,该标签指向iframe,然后点击a标签就相当于更改了iframe的src,这个思路已经非常接近我最终用的方法了

在我这边,就是写成

function downloadButtonClicked(url) {
	var elem = document.createElement("a");
	elem.href = url;
	elem.target = "hiddenIframe";
	elem.click();
}

后来没使用这个方法,因为在firefox和ie下没有效果

2. 补充一个之前用过的方法,判断当前页面是否在iframe中

self!=top(返回true,说明在iframe中;false,表示不在iframe中)

https://www.cnblogs.com/zycbloger/p/6196493.html

 

附后台下载代码(我用的是struts2,这个其实跟框架无关,提供下只是方便各位重现):

java代码

package com.kittycoder.datadisplay.action;

import com.opensymphony.xwork2.ActionSupport;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;

/**
 * Created by shucheng on 2019-6-12 下午 20:56
 * 下载action
 */
public class DownloadAction {

    private String resourceName;
    private InputStream inputStream;
    private String downloadFileName;

    // 下载文件
    public String downloadFile() {
        try {
            String content = "测试文件下载";
            ByteArrayInputStream stream = new ByteArrayInputStream(
                    content.getBytes(StandardCharsets.UTF_8));
            setDownloadFileName(resourceName); // 设置下载文件名
            setInputStream(stream); // 设置下载文件流
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ActionSupport.SUCCESS;
    }

    public String getResourceName() {
        return resourceName;
    }

    public void setResourceName(String resourceName) {
        this.resourceName = resourceName;
    }

    public InputStream getInputStream() {
        return inputStream;
    }

    public void setInputStream(InputStream inputStream) {
        this.inputStream = inputStream;
    }

    // 解决下载文件名中文乱码问题
    public String getDownloadFileName() {
        try {
            downloadFileName = new String(downloadFileName.getBytes("gbk"), "iso-8859-1");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return downloadFileName;
    }

    public void setDownloadFileName(String downloadFileName) {
        this.downloadFileName = downloadFileName;
    }
}

struts2配置文件 struts.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>
    <package name="strutsDemo" extends="json-default" namespace="/datadisplay">
        <!-- 测试struts下载 -->
        <action name="testDownload" class="com.kittycoder.datadisplay.action.DownloadAction" method="downloadFile">
            <result name="success" type="stream">
                <param name="contentType">multipart/form-data</param>
                <param name="inputName">inputStream</param>
                <param name="contentDisposition">
                    attachment;filename="${downloadFileName}"
                </param>
                <param name="bufferSize">2048</param>
            </result>
        </action>
    </package>
</struts>

这里配置文件中有个需要注意的地方(不是struts2特有的):contentDisposition设置成attachement,浏览器才能让文件直接就能下载

这个其实就是设置响应头里的Content-Disposition,对servlet、springmvc也是一样的。浏览器里的默认设置为inline(能显示则显示,不能显示则下载),attachement就是以附件形式下载

 

参考链接:

https://stackoverflow.com/questions/1066452/easiest-way-to-open-a-download-window-without-navigating-away-from-the-page

https://www.cnblogs.com/zycbloger/p/6196493.html

更多推荐