ServletContext 的使用

448 阅读4分钟

这是我参与2022首次更文挑战的第15天,活动详情查看:2022首次更文挑战」。

ServletContext 的讲解

// 例如一篇文章的上下连接。上下文语境
ServletContext servletContext = this.getServletContext();

Web 容器在启动的时候,一个Web 容器肯定可以和多个Servlet 交互。

比如说我在京东登陆了,这个登陆信息肯定会被带到多个页面,跳到其他页面也会发现自己也是登陆状态的。这个肯定不是自己做的,需要一个“中间商”去做。这个ServletContext 就可以理解为这个“中间商”。

所以在Web 容器在启动的时候,它会为每个Web 程序都创建一个对应的ServletContext 对象,它代表了当前的Web 应用。

参考上面的代码,那个网站,就是由servletContext 这个对象来管理的。因为这个对象,就代表了这个Web 应用。

ServletContext 的应用场景

  1. 共享数据。在某个Servlet 中保存的数据,可以在另外一个Servlet 中拿到。

比如说注册了三个Servlet,Servlet1,Servlet2,Servlet3 对应的url 分别为/s1,/s2,/s3。如果Servlet2 想读取Servlet1 中的某个数据,就可以使用ServletContext。

public class Servlet1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 例如一篇文章的上下连接。上下文语境
        ServletContext servletContext = this.getServletContext();
        String userName = "abc";
        // 将一个数据保存到ServletContext 中
        servletContext.setAttribute("userName", userName);
    }
}

在Servlet1 中,将userName 设置进入了ServletContext。

public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 例如一篇文章的上下连接。上下文语境
        ServletContext servletContext = this.getServletContext();
        // 从ServletContext 中取数据
        String userName = (String) servletContext.getAttribute("userName");

        resp.getWriter().println(userName);
    }
}

这样,在访问第一个Servlet 之后,再访问第二个Servlet,就可以取出对应的userName 并展示了。

  1. 利用ServletContext 读取web.xml 全局初始化参数。我们可以在web.xml 中写入一些web 应用初始化参数配置,如连接db 的url配置。
<context-param>
  <param-name>url</param-name>
  <param-value>jdbc:mysql://localhost:3306/abc</param-value>
</context-param>

上面代码在写入web.xml 之后,可以在下述java 代码中拿到。

public class ServletParaTest extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 例如一篇文章的上下连接。上下文语境
        ServletContext servletContext = this.getServletContext();
        // 从ServletContext 中取数据
        String userName = (String) servletContext.getInitParameter("url");

        resp.getWriter().println(userName);
    }
}
  1. 请求转发
public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("进入此页面");
        // 例如一篇文章的上下连接。上下文语境
        ServletContext servletContext = this.getServletContext();
        // 转发的请求路径,也即此请求会被转发到哪个页面
        RequestDispatcher requestDispatcher = servletContext.getRequestDispatcher("/testDispatcher");
        // requestDispatcher 只是在这里做了转发的作用,然后把req & resp 写入
        requestDispatcher.forward(req, resp);
    }
}
  1. 读取资源文件。比如在resource 文件中新建的配置文件“db.properties”中写入如下数据。
username=root
pwd=123456

正常java 代码读取properties 文件的时候,写如下代码:

image.png 可以选择load 的两个方法,区别就是一个是流,一个是Reader。正常的时候都是用流,流都是按照File 地址生成的,根据文件绝对地址来就可以。

但是现在是web 应用,没有办法保证绝对地址。

我们观察properties 文件会生成到web 的哪个地方。

运行之后,我们发现properties 文件存在于:

Screen Shot 2022-02-08 at 11.29.52 PM.png

即:WEB-INF 文件夹下的classes 文件夹内。所以可以得出结论,resource 文件默认路径是calsses 文件,也即classpath(类路径)。

Screen Shot 2022-02-08 at 11.35.03 PM.png 同时我们也可以观察到,源代码main 文件夹下的java 文件和resource 文件中的内容,最终都生成到target 的classes 文件夹中。所以对于classpath 就比较好理解了。(类路径)

回归正题,如何通过ServletContext 读取配置文件内容。

public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 例如一篇文章的上下连接。上下文语境
        ServletContext servletContext = this.getServletContext();
        // 转发的请求路径,只是在这里做了转发的作用
        RequestDispatcher requestDispatcher = servletContext.getRequestDispatcher("/testDispatcher");
        InputStream is = servletContext.getResourceAsStream("/WEB-INF/classes/db.properties");

        Properties properties = new Properties();
        properties.load(is);
        String username = properties.getProperty("username");
        String pwd = properties.getProperty("pwd");
        
        resp.getWriter().println(userName + " " + pwd);
    }
}

在之后,获取共享数据,一般都用Session,Cookie 这些;初始化参数也不会使用到标签;请求转发一般用request 去做;读取资源文件,之后会用到类加载或者反射的方法。

即几乎不太会用到ServletContext。这里主要是讲一个ServletContext web 应用的思路。上述内容在之后会讲到。