【JavaWeb】ServletContext对象详解,文件下载案例

本文深入探讨了ServletContext对象的概念、获取方式及其功能,包括获取MIME类型、作为域对象共享数据和获取文件真实路径。并通过一个文件下载案例,演示了如何使用ServletResponse设置文件的下载方式,解决中文文件名乱码问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

补充一个服务器端的全局对象ServletContext,不常用,但功能强大。



ServletContext对象

1.概念

ServletContext对象代表整个web应用,可以和程序的容器(服务器)来通信。ServletContext全局对象只有唯一一个。

2.获取ServletContext对象

  • request.getServletContext(); 通过request对象获取
  • this.getServletContext(); 通过HttpServlet类中的方法获取

例子:

@WebServlet(name = "servletContextDemo1", urlPatterns = "/servletContextDemo1")
public class servletContextDemo1 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        this.doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        /*
            ServletContext对象获取方式:
         */
        //1. 通过request对象获取
        ServletContext servletContext = request.getServletContext();
        //2. 通过HttpServlet获取
        ServletContext servletContext1 = this.getServletContext();

        System.out.println(servletContext);
        System.out.println(servletContext1);

        //ServletContext全局对象只有唯一一个
        System.out.println(servletContext==servletContext1);//true
    }

浏览器访问servletContextDemo1
在这里插入图片描述

3.ServletContext对象的功能

3.1 获取文件的MIME类型

MIME类型:是在互联网通信过程中定义的一种文件数据类型。

格式: 大类型/小类型。比如,text/html , image/jpeg

获取的方法:

  • String getMimeType(String file); 参数是文件的名称,返回值是MIME类型字符串形式

例子:

@WebServlet(name = "servletContextDemo2", urlPatterns = "/servletContextDemo2")
public class servletContextDemo2 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        this.doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //1.通过HttpServlet获取全局对象
        ServletContext context = this.getServletContext();
        //2.定义文件名称
        String fileName = "1.jpg";//该文件的MIME类型:image/jpeg
        //3.获取文件的MIME类型
        String mimeType = context.getMimeType(fileName);
        System.out.println(mimeType);
    }
}

浏览器访问servletContextDemo2
在这里插入图片描述

3.2 作为域对象:共享数据,范围是全局的

常用的三种方法

  • void setAttribute(String name,Object value); 以键值对的方式设置数据。name唯一标识,value值可以是任意对象。
  • Object getAttribute(String name); 获取键对应的值
  • void removeAttribute(String name); 删除键对应的键值对数据。

代码实现:servletContextDemo3设置共享数据,servletContextDemo4获取共享数据。

@WebServlet(name = "servletContextDemo3", urlPatterns = "/servletContextDemo3")
public class servletContextDemo3 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        this.doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //1.通过HttpServlet获取全局对象
        ServletContext context = this.getServletContext();
        //2.设置共享数据
        context.setAttribute("msg","Hello");
    }
}
@WebServlet(name = "servletContextDemo4", urlPatterns = "/servletContextDemo4")
public class servletContextDemo4 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        this.doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //1.通过HttpServlet获取全局对象
        ServletContext context = this.getServletContext();
        //2.获取共享数据
        Object msg = context.getAttribute("msg");
        System.out.println(msg);
    }
}

浏览器访问servletContextDemo3,再访问servletContextDemo4,控制台打印:

在这里插入图片描述

3.3 获取文件的真实(服务器)路径

ServletContext对象可以获取全局范围下所有文件的真实路径。

  • web目录下文件资源访问路径
  • WEB-INF目录下文件的资源访问路径
  • src目录下文件的资源访问路径

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


代码演示

@WebServlet(name = "servletContextDemo5", urlPatterns = "/servletContextDemo5")
public class servletContextDemo5 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        this.doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //1.通过HttpServlet获取全局对象
        ServletContext context = this.getServletContext();
        //2.获取文件的真实(服务器)路径,可以获取全局范围下所有文件的路径
        //2.1 web目录下资源访问
        String b_realPath = context.getRealPath("/b.txt");
        System.out.println(b_realPath);
        //将文件加载进内存,读取内容
        FileReader reader = new FileReader(b_realPath);
        int len = 0;
        char[] chars = new char[1024];
        while ((len = reader.read(chars))!=-1){
            System.out.println(new String(chars,0,len));
        }

        //2.2 WEB-INF目录下的资源访问
        String c_realPath = context.getRealPath("/WEB-INF/c.txt");
        System.out.println(c_realPath);

        //2.3 src目录下的资源访问:src目录下的资源最后都会存放在/WEB-INF/classes/目下
        String a_realPath = context.getRealPath("/WEB-INF/classes/a.txt");
        System.out.println(a_realPath);
    }
}

b.txt内容

username=zhangsan

浏览器访问servletContextDemo5,控制台打印:

在这里插入图片描述


文件下载案例

一.文件下载需求

  1. 页面显示超链接
  2. 点击超链接后弹出下载提示框
  3. 完成图片文件下载

二.需求分析

  • 超链接指向的资源如果能够被浏览器解析,则会在浏览器中展示,如果不能解析(比如视频),则弹出下载提示框。不满足需求
  • 任何资源都必须弹出下载提示框
  • 使用响应头设置资源的打开方式,以附件的形式打开:content-disposition:attachment;filename=xxx

浏览器访问不同资源的情况:

在这里插入图片描述
点击图片1,超链接访问一张图片资源,可以解析,直接显示。

在这里插入图片描述
点击视频,超链接访问视频资源,不能被解析,则弹出下载提示框。

在这里插入图片描述

三.案例实现步骤

  1. 定义页面,编辑超链接href属性,指向Servlet,传递资源名称filename
  2. 定义Servlet
    1. 获取文件名称
    2. 使用字节输入流加载文件进内存
    3. 指定response的响应头: content-disposition:attachment;filename=xxx
    4. 将数据写出到response输出流

代码实现

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


1.定义页面,download.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>文件下载</title>
</head>
<body>

<a href="img/2.jpg">图片1</a>
<a href="img/1.avi">视频</a>
<hr/>
<a href="/DownLoad/DownLoadServlet?fileName=2.jpg">图片1下载</a>
<a href="/DownLoad/DownLoadServlet?fileName=九尾.jpg">中文图片下载</a>
<a href="/DownLoad/DownLoadServlet?fileName=1.avi">视频下载</a>

</body>
</html>

2.定义Servlet,DownLoadServlet.java

@WebServlet(name = "DownLoadServlet", urlPatterns = "/DownLoadServlet")
public class DownLoadServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        this.doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //1.获取请求参数,文件名称
        String fileName = request.getParameter("fileName");
        //2.使用输入字节流加载文件进内存
        //2.1 找到文件服务器的真实路径
        ServletContext servletContext = this.getServletContext();
        String realPath = servletContext.getRealPath("/img/" + fileName);
        //2.2 使用字节流加载文件
        FileInputStream fis = new FileInputStream(realPath);

        //3.设置response的响应头
        //3.1 设置响应头类型:content-type,告诉浏览器文件的类型
        //获取文件的mime类型
        String mimeType = servletContext.getMimeType(fileName);
        response.setHeader("content-type",mimeType);
        //3.2 设置响应头文件打开方式:content-disposition
        //filename为文件打开时显示的文件的名称
        response.setHeader("content-disposition","attachment;filename="+fileName);

        //4.将输入流的数据写入到输出流中
        ServletOutputStream os = response.getOutputStream();
        byte[] bytes = new byte[1024*8];
        int len = 0;
        while((len = fis.read(bytes))!=-1){
            os.write(bytes,0,len);
        }
        os.close();
        fis.close();
    }
}

运行,浏览器访问download.html

在这里插入图片描述
点击图片1下载,变成弹出下载框形式

在这里插入图片描述
点击视频下载,弹出下载框

在这里插入图片描述
点击中文图片下载,弹出下载框,文件名显示乱码,下面我们解决中文文件乱码问题。

在这里插入图片描述

四.存在的问题

中文文件问题

问题描述:中文的文件名,在弹出的下载提示框中是不能正常显示的。并且不同浏览器展示出来的中文文件名不一样。

乱码问题就需要设置filename编码方式,并且不同的浏览器需要设置编码方式也不同。


解决思路

  1. 获取客户端使用的浏览器版本信息
  2. 根据不同的版本信息,设置filename的编码方式不同

代码实现

提供一个解决filename编码问题的工具类,网上也有许多这样的工具类,使用工具类方法编码文件名即可:

DownLoadUtils.java

public class DownLoadUtils {

    public static String getFileName(String agent, String filename) throws UnsupportedEncodingException {
        if (agent.contains("MSIE")) {
            // IE浏览器
            filename = URLEncoder.encode(filename, "utf-8");
            filename = filename.replace("+", " ");
        } else if (agent.contains("Firefox")) {
            // 火狐浏览器
            BASE64Encoder base64Encoder = new BASE64Encoder();
            filename = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
        } else {
            // 其它浏览器
            filename = URLEncoder.encode(filename, "utf-8");
        }
        return filename;
    }
}

优化后的DownLoadServlet.java

@WebServlet(name = "DownLoadServlet", urlPatterns = "/DownLoadServlet")
public class DownLoadServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        this.doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //1.获取请求参数,文件名称
        String fileName = request.getParameter("fileName");
        //2.使用输入字节流加载文件进内存
        //2.1 找到文件服务器的真实路径
        ServletContext servletContext = this.getServletContext();
        String realPath = servletContext.getRealPath("/img/" + fileName);
        //2.2 使用字节流加载文件
        FileInputStream fis = new FileInputStream(realPath);

        //3.设置response的响应头
        //3.1 设置响应头类型:content-type,告诉浏览器文件的类型
        //获取文件的mime类型
        String mimeType = servletContext.getMimeType(fileName);
        response.setHeader("content-type",mimeType);
        //3.2 设置响应头文件打开方式:content-disposition

        //解决中文文件名问题
        //1.获取user-agent请求头,浏览器信息
        String agent = request.getHeader("user-agent");
        //2.使用工具类方法编码文件名即可
        fileName = DownLoadUtils.getFileName(agent,fileName);
        //filename为文件打开时显示的文件的名称
        response.setHeader("content-disposition","attachment;filename="+fileName);

        //4.将输入流的数据写入到输出流中
        ServletOutputStream os = response.getOutputStream();
        byte[] bytes = new byte[1024*8];
        int len = 0;
        while((len = fis.read(bytes))!=-1){
            os.write(bytes,0,len);
        }
        os.close();
        fis.close();
    }
}

运行,再次点击中文图片下载,弹出下载框,中文文件名正常显示。

在这里插入图片描述
以上,就是一个文件下载的简单案例。


欢迎点赞评论,指出不足,笔者由衷感谢哦!~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值