文件下载案例实现

文件下载案例实现

首先测试一下在html中什么样的文件设置超链接后点击可以直接下载

1.html测试

Html代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<ul>
    <li><a href="resource/sky.jpg">图片</a></li>
    <li><a href="resource/Test.txt">txt文档</a></li>
    <li><a href="resource/test.docx">doc文档</a></li>

</ul>

</body>
</html>

结果:
在这里插入图片描述
点击图片:
在这里插入图片描述

点击txt文档:
在这里插入图片描述
点击doc文档

在这里插入图片描述
所以对于图片、txt、html等文档可以直接在浏览器中渲染,不会出现下载另存为的选项,而对于浏览器渲染不了的doc文档,则会出现下载选项;

原因是:浏览器接收到响应报文以后,会尽可能的进行渲染处理,如果处理不了才会让用户下载保存。
要想不论什么类型的内容,都弹出另存为对话框,则需要改变浏览器的行为。依据是 HTTP协议。


HTTP协议指出,当响应报文包含以下头部信息时:
//Content-Dispositiont头字段说明类型。attachment附件
Content-Disposition:attachment;filename=文件名

Content-Type: application/octet-stream  //核心另存为

2.测试ContentType

目录结构:
在这里插入图片描述

因为点击之后文件要进行响应头的设置,所以需要使用Servlet,
Html文件修改需要下载文件的链接地址:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<ul>
    <li><a href="/download?filepath=resource/sky.jpg">图片</a></li>
    <li><a href="/download?filepath=resource/Test.txt">txt文档</a></li>
    <li><a href="resource/test.docx">doc文档</a></li>
</ul>

</body>
</html>

web.xml文件配置:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <servlet>
        <servlet-name>download</servlet-name>
        <servlet-class>com.example.servlet.DownloadServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>download</servlet-name>
        <url-pattern>/download</url-pattern>
    </servlet-mapping>
</web-app>

servlet代码:

public class DownloadServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //拿到超链接传递过来的参数地址
        String filepath = req.getParameter("filepath");

        //设置响应头contentType
        resp.setContentType("application/octet-stream");


        //利用地址拿到对应的文件,因为不在同级目录,所以需要使用ServletContext来获取
        ServletContext servletContext = this.getServletContext();
        InputStream inputStream = servletContext.getResourceAsStream("/" + filepath);


        //利用字节流来进行输出另存为
        ServletOutputStream outputStream = resp.getOutputStream();
        byte [] buffer = new byte[1024];
        int len = -1;
        while ((len = inputStream.read(buffer))!=-1){
            outputStream.write(buffer,0,len);
        }

    }
}

点击测试结果:
在这里插入图片描述
这里有一个问题是点击后默认下载的的文件名称是download,为了修改默认文件名为原始文件名,需要设置
Content-Disposition:attachment;filename=文件名

//获取文件原始名称
        filepath.lastIndexOf("/");
        String name = filepath.substring(filepath.lastIndexOf("/")+1);
//设置响应头contentType
        resp.setContentType("application/octet-stream");
        resp.setHeader("Content-Disposition","attachment;filename="+name);

完整代码:

public class DownloadServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //拿到超链接传递过来的参数地址
        String filepath = req.getParameter("filepath");
        
        //获取文件原始名称
        filepath.lastIndexOf("/");
        String name = filepath.substring(filepath.lastIndexOf("/")+1);

        //设置响应头contentType
        resp.setContentType("application/octet-stream");
        resp.setHeader("Content-Disposition","attachment;filename="+name);
        
        //利用地址拿到对应的文件,因为不在同级目录,所以需要使用ServletContext来获取
        ServletContext servletContext = this.getServletContext();
        InputStream inputStream = servletContext.getResourceAsStream("/" + filepath);

        //利用字节流来进行输出另存为
        ServletOutputStream outputStream = resp.getOutputStream();
        byte [] buffer = new byte[1024];
        int len = -1;
        while ((len = inputStream.read(buffer))!=-1){
            outputStream.write(buffer,0,len);
        }
    }
}

显示结果:
在这里插入图片描述
在这里插入图片描述

3.中文乱码

如果文件原始名为中文会出现乱码问题:
在这里插入图片描述

3.1不同的浏览器处理方式还不同。

  • 非火狐的浏览器 文件名采用 URL编码
  • 火狐浏览器 文件名采用 Base64编码

想要判断浏览器类型可以通过请求头中的User-Agent
在这里插入图片描述

3.2处理非火狐

name = URLEncoder.encode(name);
显示结果:
在这里插入图片描述
处理火狐

            //如果是火狐浏览器,采用base64编码格式
            //格式:=?utf-8?B?Base64字符串?=

            //拿到转换成base64的字符串
            String s = Base64.getEncoder().encodeToString(name.getBytes());
            //拼接
            name = "=?utf-8?B?"+s+"?=";

4.完整代码

在这里插入图片描述
html代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<ul>
    <li><a href="/download?filepath=resource/sky.jpg">图片</a></li>
    <li><a href="/download?filepath=resource/Test.txt">txt文档</a></li>
    <li><a href="/download?filepath=resource/资料.txt">资料</a></li>
    <li><a href="resource/test.docx">doc文档</a></li>

</ul>

</body>
</html>

web.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <servlet>
        <servlet-name>download</servlet-name>
        <servlet-class>com.example.servlet.DownloadServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>download</servlet-name>
        <url-pattern>/download</url-pattern>
    </servlet-mapping>
</web-app>

DownloadServlet 代码

package com.example.servlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.URLEncoder;
import java.util.Base64;

public class DownloadServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //判断浏览器的类型
        String userAgent = req.getHeader("User-Agent");
        boolean isFireFox = false;
        if(userAgent!=null && userAgent.contains("FireFox")){
            //采用火狐Base64编码格式
            isFireFox = true;
        }


        //拿到超链接传递过来的参数地址
        String filepath = req.getParameter("filepath");

        //获取文件原始名称
        filepath.lastIndexOf("/");
        String name = filepath.substring(filepath.lastIndexOf("/")+1);


        if (isFireFox){
            //如果是火狐浏览器,采用base64编码格式
            //格式:=?utf-8?B?Base64字符串?=

            //拿到转换成base64的字符串
            String s = Base64.getEncoder().encodeToString(name.getBytes());
            //拼接
            name = "=?utf-8?B?"+s+"?=";

        }else {
            name = URLEncoder.encode(name);

        }



        //设置响应头contentType
        resp.setContentType("application/octet-stream");
        resp.setHeader("Content-Disposition","attachment;filename="+name);

        //利用地址拿到对应的文件,因为不在同级目录,所以需要使用ServletContext来获取
        ServletContext servletContext = this.getServletContext();
        InputStream inputStream = servletContext.getResourceAsStream("/" + filepath);

        //利用字节流来进行输出另存为
        ServletOutputStream outputStream = resp.getOutputStream();
        byte [] buffer = new byte[1024];
        int len = -1;
        while ((len = inputStream.read(buffer))!=-1){
            outputStream.write(buffer,0,len);
        }
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值