day15-Servlet04

Servlet04

12.ServletConfig

12.1ServletConfig基本介紹

  1. ServletConfig類是為Servlet程式配置資訊的類
  2. Servlet對象和ServletConfig對象都是由Tomcat負責創建
  3. Servlet對象默認是第一次訪問的時候創建,ServletConfig在Servlet對象創建的時候,就創建一個對應的ServletConfig對象

12.2ServletConfig作用

  1. 獲取Servlet程式的servlet-name的值
  2. 獲取初始化參數init-param
  3. 獲取ServletContext對象(上下文對象)

12.3ServletConfig應用實例

例子

需求:編寫DBServlet.java,完成如下功能

  1. 在web.xml配置連接mysql的用戶名和密碼

  2. 在DBServlet執行doGet()或者doPost()時,可以獲取到web.xml配置的用戶名和密碼

  3. 思路分析:

    瀏覽器發送請求,Tomcat去創建DBServlet,DBServlet去web.xml文件中去獲取配置的參數,獲取的方法有兩種:一是使用dom4j,二是使用ServletConfig類

    image-20221110231130553

web.xml配置Servlet:

<!--配置DBServlet-->
<servlet>
    <servlet-name>DBServlet</servlet-name>
    <servlet-class>servlet.DBServlet</servlet-class>
    <!--為該Servlet配置初始參數-->
    <init-param>
        <!--參數名-->
        <param-name>username</param-name>
        <!--參數值-->
        <param-value>jack</param-value>
    </init-param>
    <init-param>
        <param-name>pwd</param-name>
        <param-value>123456</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>DBServlet</servlet-name>
    <url-pattern>/db</url-pattern>
</servlet-mapping>

DBServlet:

package servlet;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;

public class DBServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //在DBServlet執行doGet()或者doPost()時,可以獲取到web.xml配置的用戶名和密碼
        //DBServlet的父類GenericServlet有方法getServletConfig()
        /**
         * 1.getServletConfig()是父類GenericServlet的
         * 2.返回的ServletConfig對象是GenericServlet的private transient ServletConfig config
         * 3.當一個屬性被transient修飾,表示該屬性不會被串列化(有些重要資訊不希望保存到文件中)
         */
        ServletConfig servletConfig = getServletConfig();
        String username = servletConfig.getInitParameter("username");
        String pwd = servletConfig.getInitParameter("pwd");
        System.out.println("初始化參數username=" + username);
        System.out.println("初始化參數pwd=" + pwd);
    }
}

瀏覽器訪問DBServlet時,後台輸出:

image-20221111163640834

問題一:在doPost方法中可以得到servletConfig,在doGet方法也可以得到servletConfig,那麼這兩個servletConfig是同一個servletConfig嗎?

答:是同一個servletConfig。

先來看一個例子

在上述的DBServlet中重寫init方法,並且分別在init和doPost方法中輸出ServletConfig對象

package servlet;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;

public class DBServlet extends HttpServlet {
    @Override
    public void init(ServletConfig config) throws ServletException {
        System.out.println("init()=" + config);
    }

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

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
        ServletConfig servletConfig = getServletConfig();
        System.out.println("doPost()=" + servletConfig);
        String username = servletConfig.getInitParameter("username");
        String pwd = servletConfig.getInitParameter("pwd");
        System.out.println("初始化參數username=" + username);
        System.out.println("初始化參數pwd=" + pwd);
    }
}

redeployTomcat,在瀏覽器重新訪問DBServlet,會發現出現了500錯誤,這表明伺服器內部運行出現錯誤

image-20221111165414131

查看控制台輸出,發現doPost方法竟然輸出了null

image-20221111165456889

在DBServlet中的init方法加上語句super.init(config);

image-20221111165825143

redeployTomcat,重新訪問瀏覽器,會發現訪問DBServlet成功,後台輸出變正常了

image-20221111165845773

問題二:這是為什麼呢?


我們先來梳理ServletConfig config的使用流程

  1. 當DBServlet對象初始化時,Tomcat會同時創建一個ServletConfig對象

  2. 如果DBServlet init()方法中調用了super.init(config);

  3. 就會調用父類GenericServlet的init方法:

    public void init(ServletConfig config) throws ServletException {
    	this.config = config;
    	this.init();
    }
    

    這時就會把Tomcat創建的ServletConfig對象賦給GenericServlet的屬性config

  4. 因此如果要重寫init()方法,記住如果你想在其他方法通過getServletConfig()獲取ServletConfig,則一定要記住調用super.init(config);


回到問題二:

如果沒有把tomcat創建的ServletConfig,賦值給GenericServlet的屬性config。那麼GenericServlet的屬性config的值就為null,而doPost或者doGet方法通過getServletConfig()拿到的就是GenericServlet的屬性config,因此就會輸出null。

側面證實了方法中獲取的servletConfig是同一個對象(問題一)

因此上面的例子中,瀏覽器訪問DBServlet,發現出現了500錯誤的原因是,doPost方法中獲取了為null的ServletConfig對象中的屬性

image-20221111172545657

13.ServletContext

13.1為什麼需要ServletContext

先來看一個需求:如果我們希望統計某個web應用的所有Servlet被訪問的次數,怎麼辦?

方案一:使用DB

image-20221111180455985

方案二:使用ServletContext

image-20221111180517874

13.2ServletContext基本介紹

  1. ServletContext是一個介面,它表示Servlet上下文對象

  2. 一個web工程中,只有一個ServletContext對象實例

  3. ServletContext對象是在web工程啟動的時候創建的,在web工程停止的時候銷毀

  4. 可以通過ServletConfig.getServletContext方法獲得對ServletContext對象的應用,也可以通過this.getServletContext()來獲得其對象的引用

  5. 由於一個web應用中的所有Servlet共享一個ServletContext對象,因此Servlet對象之間可以通過ServletContext對象來實現多個Servlet間的通訊。ServletContext對象通常也被稱為域對象。

    image-20221111182439732

13.3ServletContext可以做什麼

  1. 獲取web.xml文件中配置的上下文參數context-param [資訊和整個web應用相關,而不是屬於某個Servlet]

  2. 獲取當前的工程路徑,格式:/工程路徑

  3. 獲取工程部署後在伺服器硬碟上的絕對路徑

    比如 D:\IDEA-workspace\servlet\out\artifacts\servlet_war_exploded

  4. 向Map一樣存取數據,多個Servlet共享數據

13.4應用實例

13.4.1應用實例1-獲取工程相關資訊

需求如下:

  1. 獲取web.xml中配置的上下文參數context-param
  2. 獲取當前的工程路徑,格式:/工程路徑
  3. 獲取工程部署後在伺服器硬碟上的絕對路徑

配置ServletContext_: 在web.xml文件增加相關配置

<!--配置ServletContext_-->
<servlet>
    <servlet-name>ServletContext_</servlet-name>
    <servlet-class>com.li.servlet.servletcontext.ServletContext_</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>ServletContext_</servlet-name>
    <url-pattern>/servletContext_</url-pattern>
</servlet-mapping>

<!--配置整個網站的資訊-->
<context-param>
    <param-name>website</param-name>
    <param-value>//www.lili.net</param-value>
</context-param>
<context-param>
    <param-name>company</param-name>
    <param-value>lili有限公司</param-value>
</context-param>

ServletContext_:

package com.li.servlet.servletcontext;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;

public class ServletContext_ extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //獲取web.xml的context-parameter

        //1.獲取到ServletContext對象
        ServletContext servletContext = getServletContext();
        //2.獲取website
        String website = servletContext.getInitParameter("website");
        String company = servletContext.getInitParameter("company");
        System.out.println("website= " + website);
        System.out.println("company= " + company);
        //3.獲取項目的工程路徑
        String contextPath = servletContext.getContextPath();
        System.out.println("項目路徑= " + contextPath);// /servlet_demo
        //4.得到項目發布後真正的工作路徑
        //這裡的斜杠/表示我們的項目發布後的根路徑 D:\IDEA-workspace\servlet_demo\out\artifacts\servlet_demo_war_exploded
        String realPath = servletContext.getRealPath("/");
        System.out.println("項目發布後的絕對路徑= " + realPath);
    }
}

瀏覽器訪問ServletContext_:

image-20221111190127615

後台輸出:

image-20221111190940108

13.4.2應用實例2-簡單的網站訪問次數統計器

需求:完成一個簡單的網站訪問次數統計器

不管使用什麼瀏覽器,每訪問一次Servlet,就增加1訪問次數,在後台輸出,並將結果返回給瀏覽器顯示

image-20221111191533055

WebUtils.java:

package com.li.servlet.servletcontext;

import javax.servlet.ServletContext;

public class WebUtils {
    //該方法對訪問網站的次數累加,同時返回次數
    public static Integer visitCount(ServletContext servletContext) {
        //從servletContext獲取 visit_count 屬性 k-v
        Object visit_count = servletContext.getAttribute("visit_count");
        //判斷visit_count是否為空
        if (visit_count == null) {//說明是第1次訪問網站
            servletContext.setAttribute("visit_count", 1);
            visit_count = 1;
        } else {//說明是第二次或之後訪問
            //visit_count+1
            visit_count = Integer.parseInt(visit_count + "") + 1;
            //再將其放回servletContext
            servletContext.setAttribute("visit_count", visit_count);
        }
        return Integer.parseInt(visit_count + "");
    }
}

Servlet01.java:

package com.li.servlet.servletcontext;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.io.PrintWriter;

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

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //獲取到ServletContext對象
        ServletContext servletContext = getServletContext();

        Integer visit_count = WebUtils.visitCount(servletContext);

        //輸出顯示
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.print("<h1>該網站被訪問的次數是" + visit_count + "</h1>");
        writer.flush();
        writer.close();
    }
}

Servlet02.java:

package com.li.servlet.servletcontext;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.io.PrintWriter;

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

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //獲取到ServletContext對象
        ServletContext servletContext = getServletContext();

        Integer visit_count = WebUtils.visitCount(servletContext);

        //輸出顯示
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.print("<h1>該網站被訪問的次數是" + visit_count + "</h1>");
        writer.flush();
        writer.close();
    }
}

redeployTomcat,在不同的瀏覽器分別訪問Servlet01和Servlet02:

Tags: