day15-Servlet04

来源:https://www.cnblogs.com/liyuelian/archive/2022/11/11/16881635.html
-Advertisement-
Play Games

Servlet04 12.ServletConfig 12.1ServletConfig基本介紹 ServletConfig類是為Servlet程式配置信息的類 Servlet對象和ServletConfig對象都是由Tomcat負責創建 Servlet對象預設是第一次訪問的時候創建,Servlet ...


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>http://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:


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前文已經初始化了 workspace-root,從本文開始就需要依次搭建組件庫、example、文檔、cli。本文內容是搭建 組件庫的開發環境。 ...
  • 組件化編程 什麼是組件化編程 傳統方式的編寫模式 組件化編程的模式 組件是實現應用中局部功能代碼和資源的集合 vue中非單文件組件的基本使用 點擊查看代碼 <!-- Vue中使用組件的三大步驟: 一、定義組件(創建組件) 二、註冊組件 三、使用組件(寫組件標簽) 一、如何定義一個組件? 使用Vue. ...
  • 本篇文章將為我們的組件庫添加一個新成員:Input組件。其中Input組件要實現的功能有: 基礎用法 禁用狀態 尺寸大小 輸入長度 可清空 密碼框 帶Icon的輸入框 文本域 自適應文本高度的文本域 複合型輸入框 每個功能的實現代碼都做了精簡,方便大家快速定位到核心邏輯,接下來就開始對這些功能進行一 ...
  • 有時候,為了給前端頁面輸出內容,有時候我們需要準備和資料庫不一樣的實體信息,因為資料庫可能記錄的是一些引用的ID或者特殊字元,那麼我們為了避免前端單獨的進行轉義處理,我們可以在後端進行統一的格式化後再行輸出,後端處理可以採用不同的DTO屍體信息,後端對不同的實體進行映射處理即可,也可以採用同一個實體... ...
  • 組件學習: 子組件: <template> <div :title="msg">{{title}}</div> <div>{{cnData}}</div> <div>{{user}}</div> </template> <!-- <script lang="ts"> import { defineC ...
  • 決策引擎服務是風控系統的大腦,承載著風控策略編排和計算的任務,對決策的時耗和精度有著嚴格的要求,本文以決策流執行路徑實現方案為切入點,一窺風控決策引擎高效的原理。 ...
  • 解釋器模式是一種使用頻率相對較低但學習難度較大的設計模式,它用於描述如何使用面向對象語言構成一個簡單的語言解釋器。 ...
  • 當一個服務擁有太多處理邏輯時,會導致代碼結構異常的混亂,很難分辨一段邏輯是在哪個階段發揮作用的。 這時就可以引入狀態機模型,幫助代碼結構變得清晰。 一、狀態機庫概述 一)簡介 狀態機由一組狀態組成: 【初始狀態 -> 中間狀態 -> 最終狀態】。 在一個狀態機中,每個狀態會接收一組特定的事件,根據事 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...