【Servlet05】ServletContext接口

API介绍:

Defines a set of methods that a servlet uses to communicate with its servlet container, for example, to get the MIME type of a file, dispatch requests, or write to a log file.

There is one context per "web application" per Java Virtual Machine. (A "web application" is a collection of servlets and content installed under a specific subset of the server's URL namespace such as /catalog and possibly installed via a .war file.)

In the case of a web application marked "distributed" in its deployment descriptor, there will be one context instance for each virtual machine. In this situation, the context cannot be used as a location to share global information (because the information won't be truly global). Use an external resource like a database instead.

The ServletContext object is contained within the ServletConfig object, which the Web server provides the servlet when the servlet is initialized.

ServletContext接口来自于 Servlet规范中一个接口, 实现类由Http服务器负责提供,习惯上将 ServletContext接口的实现类对象称为全局作用域对象

ServletContext接口的实现类对象会在服务器启动时自动创建,服务器关闭时自动销毁;该对象在服务器运行期间有且仅有一个对象,程序员仅可以获取并操作该对象,但是不能创建或销毁;

ServletContext接口的实现类对象的使用范围是:服务器运行状态下,模块中的所有位置,这意味着可以设置一些全局的数据供不同的Servlt使用,所以该对象的核心功能主要有二:初始化参数作用域数据操作

1 初始化参数设置

初始化参数分为两种:局部的初始化参数和全局的初始化参数。

1.1 局部的初始化参数

局部的初始化参数可以通过xml文件或注解将键值对数据配置在某个Servlet中,局部初始化参数数据的使用范围是一个Servlet

例如,在HelloServlet配置了局部初始化参数:

<?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>helloServelt</servlet-name>
        <servlet-class>com.jackqiang.HelloServlet</servlet-class>
        <init-param>
            <param-name>address</param-name>
            <param-value>Earth</param-value>
        </init-param>
        <init-param>
            <param-name>country</param-name>
            <param-value>China</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>helloServelt</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
</web-app>

在其他Servlet去尝试访问:

@WebServlet("/anno")
public class AnnotationServlet extends HttpServlet {
    public AnnotationServlet() {
        System.out.println("execute constructor in AnnotationServlet");
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("execute doGet in AnnotationServlet");
        String country = this.getInitParameter("country");
        System.out.println("country = " + country);
    }
}

可以发现其实是访问不到的:

1.2 全局的初始化参数

全局的初始化参数可以通过xml文件方式将键值对配置在ServletContext对象中,键值对数据的使用范围是ServletContext对象的范围,即服务器运行下的所有位置。

在web.xml进行配置:

<context-param>
    <param-name>encoding</param-name>
    <param-value>gbk</param-value>
</context-param>
<context-param>
    <param-name>name</param-name>
    <param-value>xiao ming</param-value>
</context-param>

在不同的Servlet进行访问:

HelloServlet

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    System.out.println("execute doGet in HelloServlet......");
    ServletContext servletContext = getServletContext();
    String encoding = servletContext.getInitParameter("encoding");
    Enumeration<String> initParameterNames = servletContext.getInitParameterNames();
    System.out.println("encoding = " + encoding);
    while (initParameterNames.hasMoreElements()){
        String s = initParameterNames.nextElement();
        System.out.println(s);
    }
}

AnnotationServlet

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    System.out.println("execute doGet in AnnotationServlet");
    ServletContext servletContext = getServletContext();
    String name = servletContext.getInitParameter("name");
    Enumeration<String> initParameterNames = servletContext.getInitParameterNames();
    System.out.println("name = " + name);
    while (initParameterNames.hasMoreElements()){
        String s = initParameterNames.nextElement();
        System.out.println(s);
    }
}

重启服务器,访问查看测试结果:

可以看出来,初始化参数设置必须通过配置(xml或注解)的方式添加键值对数据,比较麻烦,并且由于数据写死了,也不够灵活。

2 全局作用域数据操作

在Servlet中会使用作用域对象来存储程序中所需的数据(键值对),只要这个对象存在,就可以随时的使用对象中的数据,这样做的目的是可以完成JavaEE程序之间的数据传递。

ServletContext对象对应的作用域是全局作用域,完成全局作用域数据操作涉及到的三个方法:

  • java.lang.Object getAttribute(java.lang.String name)方法:通过键获取ServletContext对象中对应的值;

  • void removeAttribute(java.lang.String name)方法:通过键删除ServletContext对象中某个键值对;

  • void setAttribute(java.lang.String name, java.lang.Object object)方法:向某个ServletContext对象中存储一个键值对,如果存在键相同的情况则覆盖之前存储的值;

使用:

TestServlet1:

@WebServlet("/test1")
public class TestServlet1 extends HttpServlet {
    public TestServlet1() {
        System.out.println("execute constructor in TestServlet1");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("execute doGet in TestServlet1");
        ServletContext servletContext = getServletContext();
        String name = (String) servletContext.getAttribute("name");
        Integer age = (Integer) servletContext.getAttribute("age");
        System.out.println("ServletContext in TestServlet1 is:" + servletContext);
        System.out.println("name = " + name);
        System.out.println("age = " + age);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("execute doPost in TestServlet1");
    }
}

TestServlet2:

@WebServlet("/test2")
public class TestServlet2 extends HttpServlet {
    public TestServlet2() {
        System.out.println("execute constructor in TestServlet2");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("execute doGet in TestServlet2");
        ServletContext servletContext = getServletContext();
        System.out.println("ServletContext in TestServlet2 is:" + servletContext);
        servletContext.setAttribute("name","zhangsan");
        servletContext.setAttribute("age",18);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("execute doPost in TestServlet2");
    }
}

在TestServlet2中设置了作用域数据,在TestServlet1中进行访问;

可以看到直接访问TestServlet1是不能取到相应的作用域数据的,需要先访问TestServlet2进行设置以后再访问TestServlet1才能取到数据:

并且可以看到两次打印ServletContext对象的地址值是一致的,也再次印证了ServletContext对象是单例的;

ServletContext对象的使用范围(只要服务器不关闭就都可以访问):

  • 不同Servlet类之间;

  • 不同的动态页面之间;

  • 不同请求之间;

  • 不同的浏览器之间;

  • 不同的计算机之间;

小案例:记录网页的访问次数

@WebServlet("/pageCount")
public class PageCountServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext servletContext = getServletContext();
        Integer num = (Integer) (servletContext.getAttribute("num") == null ? 0 : servletContext.getAttribute("num"));
        num++;
        servletContext.setAttribute("num", num);
        System.out.println("当前是" + num + "次访问");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}

版权声明:
作者:jackqiang
链接:http://www.jackqiang.com/javaweb/server/servlet/2129/servletcontext/
来源:JackQiang's
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
< <上一篇
下一篇>>
文章目录
关闭
目 录