Skip to content

ServletContext

ServletContext

ServletContext是什么

java
Servlet用于与Web容器(Tomcat)通信的一组方法、每个Web应用都有一个上下文,有且只有一个

ServletContext的获取方式

  • GenericServlet.getServletContext()

    tex
    this为GenericServlet的派生类
  • request.getServletContext()

    java
    this.getServletContext();
    getServletContext();// 推荐使用方式
    request.getServletContext();

ServletContext的作用

获得Web应用资源下的文件路径【重点】

相关API
  • String getRealPath(String path)

    获取真实路径

    如果 path 当中的文件,不存在的话,还是会返回

  • InputStream getResourceAsStream(String path)

    从资源当中获取一个输入流

    如果 path 当中的文件,不存在的话,返回值是 null

案例
  • 利用 getRealPath 及 getResourceAsStream,改进文件下载 Servlet
实现
  • index.html
xml
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h2>Servlet Download</h2>
<a href="download_sample?filename=file.txt">file.txt</a><br>
<a href="download_sample?filename=file.zip">file.zip</a><br>
<a href="download_sample?filename=搞笑.gif">搞笑.gif</a><br>
</body>
</html>
  • DownloadServlet.java
java
package com.futureweaver.web;

import org.apache.commons.io.IOUtils;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;

@WebServlet("/download_sample")
public class DownloadServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 获取前端发过来的文件名参数
        String filename = request.getParameter("filename");
      
        // 告诉浏览器下载文件的文件名
        response.setHeader("Content-Disposition", "attachment; filename=" + filename);

        // 获取字节输出流
        OutputStream out = response.getOutputStream();
      
        // 获取文件的输入流对象
        InputStream in = this.getServletContext().getResourceAsStream("/WEB-INF/" + filename);
        System.out.println("Download:");
        System.out.println(this.getServletContext().getRealPath("/WEB-INF/" + filename));
        System.out.println();

        // 利用IOUtils进行读取、写入
        IOUtils.copy(in, out);

        // 关闭流对象
        in.close();
        out.close();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}
下载中文文件错误解决
java
response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("中文", "utf-8") + ".gif");
小结
  • String getRealPath(String path)

    获取文件的绝对路径

    获取真实路径

    坑:只是单纯的字符串拼接,不做"文件是否存在"的检查

  • InputStream getResourceAsStream(String path)

    获取资源作为流(输入流)

    坑: 如果文件路径不正确的话,返回的是null

获得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">
    <!-- 设置参数 -->
    <context-param>
        <param-name>username</param-name>
        <param-value>root</param-value>
    </context-param>

    <context-param>
        <param-name>password</param-name>
        <param-value>pwd</param-value>
    </context-param>
</web-app>
相关API
  • String getInitParameter(String name)
  • Enumeration<String> getInitParameterNames()
实现
java
package com.futureweaver.web;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name = "InitParamServlet")
public class InitParamServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 读取参数
        ServletContext servletContext = this.getServletContext();
        System.out.println("username: " + servletContext.getInitParameter("username"));
        System.out.println("password: " + servletContext.getInitParameter("password"));
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}
小结
  • 设置全局初始化参数

    在web.xml,

    <context-param>

    <param-name>

    <param-value>

  • 获取全局初始化参数

    String(value) getInitParameter(String name)

【扩展】Servlet获取初始化参数

参数设置
  • web.xml
xml
    <servlet>
        <servlet-name>InitParamServlet</servlet-name>
        <servlet-class>com.futureweaver.web.InitParamServlet</servlet-class>

        <!-- Servlet初始化参数配置 -->
        <init-param>
            <param-name>name</param-name>
            <param-value>zhangsan</param-value>
        </init-param>

        <init-param>
            <param-name>age</param-name>
            <param-value>13</param-value>
        </init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>InitParamServlet</servlet-name>
        <url-pattern>/init_param</url-pattern>
    </servlet-mapping>
相关API
  • String getInitParameter(String name)
  • Enumeration<String> getInitParameterNames()
实现
  • InitParamServlet
java
package com.futureweaver.web;

import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;

// 初始化参数相关的Servlet
public class InitParamServlet implements Servlet {
    private ServletConfig config = null;

    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        config = servletConfig;
        String name = servletConfig.getInitParameter("name");
        String age = servletConfig.getInitParameter("age");

        System.out.println(name);
        System.out.println(age);
    }

    @Override
    public ServletConfig getServletConfig() {
        return config;
    }

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("InitParamServlet被调用了");
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {

    }
}
  • InitParamServlet
java
// 初始化参数相关的Servlet
public class InitParamServlet implements HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String name = getInitParameter("name");
        String age = getInitParameter("age");

        System.out.println(name);
        System.out.println(age);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

【重点】ServletContext是一个域对象

作用范围

Servlet

  • 第一次被访问时,由Tomcat创建
  • 项目卸载时,由Tomcat销毁
  • 创建1次,线程不安全

请求域

  • 服务器接收到浏览器的请求时,由Tomcat创建
  • 响应结束时,由Tomcat销毁

上下文域

  • 项目加载时,由Tomcat创建
  • 项目卸载时,由Tomcat销毁

作用范围

  • 请求域 一个用户的一次请求
  • 上下文域 所有用户的所有请求
相关API
  • setAttribute(String key, Object obj)
  • Object getAttribute(String key)
  • removeAttribute(String key)
案例
  • 统计某 Servlet 的访问次数
实现
java
package com.futureweaver.web;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/count_sample")
public class CountServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 统计这个Servlet的访问次数
        // 把"访问次数"输出到浏览器
        // 字符输出流当中有中文,设置编码
        response.setContentType("text/html; charset=utf-8");

        PrintWriter out = response.getWriter();


        // 先获取上下文域对象
        ServletContext context = getServletContext();

        // 规定:"访问次数"的域 对象的名字:accessCount
        // 规定:"accessCount"是整型
        // 1. 如果第1次访问的,根本就没存,所以需要做判断
        Integer accessCount = (Integer) context.getAttribute("accessCount");
        if (accessCount == null) {
            // 因为一次还要再加1,所以先给一个0
            // 因为一会再加1之后,还需要设置回去,也就是调用setAttribute,所以,一起设置
            accessCount = 0;
        }
        // 2. 每一次访问,"访问次数"取出来,加1,再存回去
        accessCount ++;

        // 3. 要统计的,把"访问次数"找个地方存
        // 把这个数据存放的地方,定为服务器内部
        // 选择域对象进行存储
        // 在请求域和上下文域当中,做出选择
        // 请求域:因为请求域使用的是request对象,request对象在每一次受浏览器访问时,都会创建一份新的
        //         所以放到请求域当中,永远都是1
        // 上下文域:在项目启动时创建,在项目卸载时销毁,有且只有1个
        //           既然有且只有1个的话,那么这个数据,就可以放到上下文域当中
        context.setAttribute("accessCount", accessCount);

        out.write("<h1>此Servlet被访问了" + accessCount + "次</h1>");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

ServletContext与Request域的对比

ServletContext

上下文域

HttpServletRequest

请求域

上下文域,在 Web 应用被 Web 容器加载的时候被创建,在 Web 程序被卸载的时候被销毁。在 Web 应用程序内部有效

请求域上下文域
创建服务器接收到浏览器的请求时服务器加载时
销毁响应结束时服务器卸载时
作用范围一个用户的一次请求所有用户的所有请求

小结

  • ServletContext 的获取方式

    java
    getServletContext();
    request.getServletContext();
  • ServletContext 的作用

    • 获得 Web 应用资源下的文件路径

      java
      String path = context.getRealPath("download.gif");
      InputStream in = new FileInputStream(path);
      
      InputStream input = context.getResourceAsStream("download.gif");
    • 获得 Web 应用的全局初始化参数【了解】

      • 设置

        xml
        <context-param>
          <param-name>name</param-name>
          <param-value>zhangsan</param-value>
        </context-param>
      • 获取

        context.getInitParameter("name");

    • ServletContext 是一个域对象【重点】

      • setAttribute()
      • getAttribute()
      • removeAttribute()
  • ServletContext 的生命周期

    作用范围

    所有用户的所有请求

案例

需求

在浏览器上展示一张随机生成的验证码图片

技术铺垫

相关类

  • java.awt.image.BufferedImage

指定宽、高和图片的类型,创建一个缓存图片对象,用于生成图片

  • java.awt.Graphics

画笔对象,用于绘制图形

  • setColor(Color c)

设置画笔的颜色

  • fillRect(int x, int y, int width, int height)

填充一个矩形区域,指定起始的坐标点,宽度和高度

  • setFont(Font font)

设置字符的字体

  • drawString(String str, int x, int y)

画一个字符串

  • drawLine(int x1, int y1, int x2, int y2)

指定起点和终点画一条线

  • java.awt.Color

表示一个颜色类

  • java.awt.Font

表示一种字体类

  • Font(String name, int style, int size)
  • name

字体。Font.DIALOG

  • style

样式: 粗体、斜体。Font.BOLD +Font.ITALIC

  • size

字号。19

  • javax.imageio.ImageIO

用于将缓存的图片输出到浏览器

代码

java
package com.futureweaver.web;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

// 生成验证码图片
@WebServlet("/check_code")
public class CheckCodeServlet extends HttpServlet {

    private Random random = new Random();

    private Color randomColor() {
        // 随机0-255,random.nextInt(256)
        int r = random.nextInt(256);
        int g = random.nextInt(256);
        int b = random.nextInt(256);
        return new Color(r, g, b);
    }

    private BufferedImage generateImg() {
        int width = 100;
        int height = 30;

        // 创建画布
        // 参数1: 画布宽度
        // 参数2: 画布高度
        // 参数3: 画布的配色方案
        BufferedImage out = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

        // 获取画笔
        Graphics graphics = out.getGraphics();

        // 将画笔的颜色设置为白色
        graphics.setColor(Color.WHITE);

        // 用白色的画笔,刷满整个画布
        graphics.fillRect(0, 0, width, height);

        // 写随机4位字符
        String allstr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";
        for (int idx = 0; idx < 4; ++idx) {
            // 算出一个随机的字符
            int randomStrBegin = random.nextInt(allstr.length());
            String randomStr = allstr.substring(randomStrBegin, randomStrBegin + 1);

            // 设置随机字符的颜色
            graphics.setColor(randomColor());

            // 设置字体、样式、字号
            graphics.setFont(new Font(Font.DIALOG, Font.BOLD + Font.ITALIC, 19));

            // 将随机算出的字符,利用画笔画到画布上
            // 字号18/19
            // 每一个字符的跨度都是20
            // 字符的位置是: 10 + idx * 20
            graphics.drawString(randomStr, 10 + idx * 20, 20);
        }

        // TODO: 画8条干扰线
        // 干扰线的起始与结束,都应该是随机生成的

        graphics.setColor(randomColor());
        graphics.drawLine(0, 0, 100, 20);

        return out;
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ServletOutputStream out = response.getOutputStream();

        // 生成验证码到out
        ImageIO.write(generateImg(), "jpg", out);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

学习目标总结

  • 能够使用 ServletContext 域对象