主頁 > 後端開發 > JavaWeb

JavaWeb

2023-02-28 07:15:36 後端開發

JavaWeb

什么是JavaWeb?

  • JavaWeb就是指所有通過Java語言撰寫可以通過瀏覽器訪問的程式的總稱;
  • 一個JavaWeb程式由多個靜態web資源和動態資源組成,web程式開發完成后,若要被外界訪問,就要把web應用所在的目錄交給web服務器管理(虛擬目錄的映射);
  • JavaWeb是基于請求和回應來開發的;

在這里插入圖片描述

靜態Web

  • 指任何時候訪問的內容都一致的Web界面,沒有互動;
  • 靜態資源:html、CSS、js、txt、mp4...

動態Web

  • 只訪問內容隨時間改變的Web界面,有互動,一般是與資料庫互動;
  • 動態資源:jsp頁面、Servlet程式...

什么是請求和回應?

請求

  • 請求是指客戶端向服務器發送資料,Request;

回應

  • 回應是指服務器給客戶端回傳資料,Response;

請求和回應是成對出現的,有請求就有回應;

在這里插入圖片描述

常用的Web服務器

Web服務器主要用來接收客戶端發送的請求和回應客戶端的請求;

  1. Web服務器主要用來接收客戶端發送的請求和回應客戶端請求,

  2. Tomcat(Apache)( 我們主要擼這只貓 ):當前應用最廣的JavaWeb服務器;

  3. JBoss(Redhat紅帽):支持JavaEE,應用比較廣EJB容器 –> SSH輕量級的框架代替

  4. GlassFish(Orcale):Oracle開發JavaWeb服務器,應用不是很廣;

  5. Resin(Caucho):支持JavaEE,應用越來越廣;

  6. Weblogic(Orcale):要錢的!支持JavaEE,適合大型專案;

  7. Websphere(IBM):要錢的!支持JavaEE,適合大型專案

Tomcat服務器

安裝教程:

目錄介紹

在這里插入圖片描述

  • backup:存放組態檔,是在第一次運行了Tomcat服務器之后產生的,和conf目錄下的內容基本一致;
  • bin:存放Tomcat服務器的可執行程式,核心包;
  • conf:存放Tomcat服務器的組態檔;
  • lib:存放Tomcat服務器的jar包;
  • logs:存放Tomcat服務器運行時輸出的日記資訊;
  • temp:存放Tomcat服務器運行時產生的臨時資料;
  • webapps:存放部署的Web工程,里面的一個檔案夾就是一個Web工程;
  • work:是Tomcat作業時的目錄,用來存放Tomcat運行時jsp翻譯為Servlet的原始碼,和Session鈍化的目錄;

啟動Tomcat服務器

  1. 找到Tomcat安裝目錄下的bin目錄下的startup.bat檔案,雙擊即可啟動Tomcat服務器;
  2. cmd命令列下,進入bin目錄下,輸入catalina run回車,即可啟動;

啟動Tomcat一閃而過問題解決:檢查JDK的環境配置

測驗Tomcat服務器是否開啟成功

  • 在瀏覽器中輸入以下地址進行測驗:
    • http://localhost:8080
    • http://127.0.0.1:8080
    • http://真實IP:8080

關閉Tomcat服務器

  1. 右上角X號;
  2. 快捷鍵Ctrl+C;
  3. Tomcat的bin目錄下的shutdown.bat,雙擊;

修改Tomcat的埠號

  1. 找到Tomcat目錄下的conf目錄下的server.xml組態檔;
  2. 找到Connector標簽,port就是埠號設定,修改它;

在這里插入圖片描述

  • Tomcat默認的埠號是8080;
  • HTTP協議默認的埠號是:80;

將web工程部署到Tomcat服務器上

  • 將Web工程拷貝到Tomcat安裝路徑的webapps目錄中

    • 訪問Tomcat中的web工程:瀏覽器中輸入http://ip:port/工程名/目錄名/檔案名
  • 找到Tomcat安裝目錄中的conf目錄下的Catalina目錄下的localhost下,創建組態檔XXX.xml

    • <!-- 檔案內容:
      	Context 表示一個工程背景關系
      	path 表示工程的訪問路徑:/abc
      	docBase 表示你的工程目錄在哪里-->
      <Context path="/abc" docBase="E:\book" />
      
    • 訪問Tomcat中的web工程:瀏覽器中輸入http://ip:port/abc/ 就代表進入到了E:\book目錄下,先要繼續訪問book檔案中的資訊,就繼續/輸入

手托html頁面到瀏覽器與在瀏覽器輸入框http://ip:port:工程名/訪問的區別

在這里插入圖片描述

地址欄的默認訪問

  • 瀏覽器地址欄如果輸入http://ip:port/ 沒有工程名,默認訪問的就是Tomcat中的webapps目錄下的ROOT工程
  • 瀏覽器地址欄中輸入http://ip:port/工程名/ 沒有資源名,默認訪問的就是該工程下的index.html檔案

部署在IDEA或者eclipse上

https://blog.csdn.net/weixin_44775516/article/details/109522779

Web工程的目錄介紹

在這里插入圖片描述

  • src:存放java代碼;
  • web:存放web工程的資源檔案,html、css...
  • WEB-INF:是一個受服務器保護的目錄,瀏覽器無法直接訪問到此目錄中
  • lib:存放第三方jar包,jar包需要配置
  • web.xml:是整個動態web工程的配置部署檔案,可以配置Servlet程式、Filter過濾器、Listener監聽器、Session超時...組件

Web 中的相對路徑和絕對路徑

  • 相對路徑是:

    • . 表示當前目錄
    • .. 表示上一級目錄
    • 資源名 表示當前目錄/資源名
  • 絕對路徑:

    • http://ip:port/工程路徑/資源路徑

web 中/ 斜杠的不同意義

  • 在web中,/斜杠是一種絕對路徑
  • /斜杠在瀏覽器中被決議,地址是:http://ip:port/
    • <a href="https://www.cnblogs.com/">斜杠</a>
  • / 斜杠如果被服務器決議,得到的地址是:http://ip:port/工程路徑
    • <url-pattern>/servlet1</url-pattern>
    • servletContext.getRealPath(“/”);
    • request.getRequestDispatcher(“/”);
  • 特殊情況: response.sendRediect(“/”); 把斜杠發送給瀏覽器決議,得到http://ip:port/

Servlet

什么是Servlet?

  • Servlet(Server Applet),全稱Java Servlet;
  • Servlet是JavaEE規范之一,就是介面,是用java撰寫的服務端程式;
  • Servlet是JavaWeb三大組件之一,都有:Servlet程式、Filter過濾器、Listener監聽器;
  • Servlet是運行在服務器上的一個Java小程式,它可以接受客戶端發送過來的請求,并回應資料給客戶端;

第一個Servlet程式

  1. 撰寫一個類要實作Servlet介面
  2. 實作介面中的service()方法,用于處理請求與回應資料
  3. 在web.xml中配置Servlet程式的訪問地址

這種方式一般不使用,我們繼承他的實作類HttpServlet

JAVA代碼:

public class Servlet1 implements Servlet {
    @Override//初始化
    public void init(ServletConfig servletConfig) throws ServletException {
    }
    @Override
    public ServletConfig getServletConfig() {
        return null;
    }
    /**
     * service方法是用來專門處理請求和回應的
     * @param servletRequest
     * @param servletResponse
     * @throws ServletException
     * @throws IOException
     */
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
    }
    @Override
    public String getServletInfo() {
        return null;
    }
    @Override//銷毀
    public void destroy() {
    }
}

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">
     <!--welcome-file-list標簽是當Tomcat服務啟動時,默認跳到哪個資源,
    其實這個不用設定,默認也會跳轉到index.html或者index.jsp資源的
    -->
    <welcome-file-list>
        <!--welcome-file標簽就是要跳轉的資源-->
        <welcome-file>HolleWord.html</welcome-file>
    </welcome-file-list>
    
    <!--service標簽是給Tomcat配置Servlet程式的 -->
    <servlet>
        <!--servlet-name標簽是給Servlet程式起一個別名-->
        <servlet-name>Servlet1</servlet-name>
        <!--servlet-class標簽是Servlet程式的全類名-->
        <servlet-class>com.mlyr.Servlet1</servlet-class>
    </servlet>
    <!--servlet-mapping標簽給Servlet程式配置訪問地址-->
    <servlet-mapping>
        <!--servlet-name標簽的作用是告訴服務器,當前配置的地址給誰用-->
        <servlet-name>Servlet1</servlet-name>
        <!--
            url-pattern標簽配置訪問地址
            /  在服務器決議時,會被決議為http://ip:port/工程名
            /servlet1表示地址為:http://ip:port/工程名/servlet1
        -->
        <url-pattern>/servlet1</url-pattern>
    </servlet-mapping>
</web-app>

URL地址到Servlet程式的訪問

在這里插入圖片描述

Servlet的生命周期

  1. 第一步:執行Servlet構造器方法;
  2. 第二步:執行init()初始化方法;
  3. 第三步:執行service()方法;
  4. 第四步:執行destroy()銷毀方法;

第一部與第二步,只在第一次訪問,創建Servlet程式的時候會執行;

第三步,每次訪問Servlet程式的時候都會執行;

第四步,只當web工程停止的時候,會執行;

GET、POET請求的分發處理

  • getMethod():可以獲取請求過來的方式,是GET請求還是POST請求
 @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        //型別轉換,HttpServletRequest有getMethod()方法,
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        //可以獲取請求的方式
        String method = request.getMethod();
        //將不同的請求,分為兩個方法,分別處理
        if (method.equals("GET")){
            doGet();
        }else if (method.equals("POST")){
            doPost();
        }
    }
    private void doPost() {
        System.out.println("POST請求");
    }
    private void doGet() {
        System.out.println("GET請求");
    }

主要類與方法

HttpServlet類

  • 一般實作Servlet程式,都是使用繼承HttpServlet類的方式來開發;
  • 它在Servlet介面的基礎上,分開了請求方式,還有一系列方法;
  1. 撰寫一個類繼承HttpServlet類
  2. 重寫它的doGet()、doPost()方法;
  3. 到web.xml檔案中配置Servlet程式的訪問地址

HttpServlet類的方法:

  • doPost():處理post請求;
  • doGet():處理get請求;

java代碼

public class Servlet2 extends HttpServlet {
    /**
     * 只有在post請求時呼叫
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("HelloServlet2 doPost 方法");
    }

    /**
     * 只有在get請求時呼叫
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("HelloServlet2 doGet 方法");
    }
}

web.xml檔案配置

<servlet>
    <servlet-name>Servlet2</servlet-name>
    <servlet-class>com.mlyr.Servlet2</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>Servlet2</servlet-name>
    <url-pattern>/servlet2</url-pattern>
</servlet-mapping>

html檔案

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="servlet2" method="post">
    <input type="submit">
</form>
</body>
</html>
  • 當表單請求是post方法,只會呼叫Servlet2類中的doPost()方法!

在這里插入圖片描述

IDEA中能夠一鍵生成Servlet程式:右擊包->點擊NEW->Create New Servlet(在下面找)->Name框(自定義類名)

根據IDEA版本不同,會注解宣告訪問地址或者web.xml檔案中宣告

@WebServlet(name="Servlet3",urlPatterns = "/servlet3")這就是注解宣告訪問地址,idea自動生成的有問題,要自行修改

Servlet類的繼承體系

在這里插入圖片描述

ServletConfig類

  • ServletConfig類是Servlet程式的配置資訊類;
  • Servlet程式和ServletConfig物件都是由Tomcat負責創建的,Servlet程式是第一次訪問的時候創建,ServletConfig是每個Servlet程式創建時,就創建一個對應的ServletConfig物件;

ServletConfig類的作用

  • 可以獲取Servlet程式的別名,就是servlet-name標簽中的值;
  • 獲取初始化引數init-param標簽中的值;
    • init-param標簽只能在servlet標簽中定義,它只屬于它所在的Servlet程式;
    • 只能被ServletConfig物件獲取;
  • 獲取ServletContext物件;

ServletConfig類中的方法:

  • getServletName():獲取web.xml組態檔中servlet-name標簽的值;
  • getInitParameter(引數):獲取init-param標簽中的值;
    • 引數:param-name標簽
    • 獲取到param-value標簽的值,這兩個標簽好比鍵值對
  • getServletContext():回傳ServletContext物件;

web.xml檔案配置

<servlet>
    <servlet-name>Servlet2</servlet-name>
    <servlet-class>com.mlyr.Servlet2</servlet-class>
    <!--init-param標簽是初始化引數,這個只屬于Servlet2程式中的,別的程式訪問不到-->
    <init-param>
        <!--引數的名字-->
        <param-name>username</param-name>
        <!--引數的值-->
        <param-value>root</param-value>
    </init-param>
    <init-param>
        <!--引數的名字-->
        <param-name>password</param-name>
        <!--引數的值-->
        <param-value>123456</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>Servlet2</servlet-name>
    <url-pattern>/servlet2</url-pattern>
</servlet-mapping>

Java代碼

public class Servlet2 implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        //獲取Servlet程式的別名,就是servlet-name標簽的值
        System.out.println(servletConfig.getServletName());
        //獲取初始化引數,init-param標簽中的
        System.out.println("username:"+servletConfig.getInitParameter("username"));
        System.out.println("password:"+servletConfig.getInitParameter("password"));
        //獲取ServletContext物件
        System.out.println(servletConfig.getServletContext());
    }
}

上方的是實作了Servlet介面,init()方法自然會重寫Servlet介面中的方法;

下方:如果繼承了HttpServlet類,它的父抽象類GenericServlet中有兩個init()方法,一個是從介面Servlet中實作的有參方法,還有一個無參init()方法是獨有的,如果自定義的類要重寫HttpServlet類中的init()有參方法,一定要呼叫super.init(config);不然會在使用ServletConfig物件的時候會報500錯誤(內部服務器錯誤),空指標例外;

在這里插入圖片描述

ServletContext類

  • ServletContext是一個介面,表示Servlet背景關系物件;
  • 一個web工程只有一個ServletContext物件;
  • ServletContext物件是一個域物件;
    • 域物件,是可以像Map一樣存取資料的物件;
存資料 取資料 洗掉資料
Map put() get() remove()
域物件 setAttribute() getAttribute() removeAttribute()
  • ServletContext在web工程啟動的時候創建,在web工程停止的時候銷毀;

ServletContext類的作用

  • 獲取web.xml中配置的背景關系引數context-param標簽;
    • context-param標簽是不能在servlet標簽中的,只能在最外面,屬于整個web工程,不單單只屬于哪一個Servlet程式;
    • 只能被ServletContext物件獲取;
  • 獲取當前工程路徑
  • 獲取工程部署后在服務器硬碟上的絕對路徑;
  • 像Map一樣存取資料;

ServletContext類中的方法

  • getInitParameter(引數):獲取context-param標簽中的資料;
  • getContextPath():獲取當前工程的路徑;
  • getRealPath(引數):獲取工程部署后在服務器硬碟上的絕對路徑;
    • 引數/: 斜杠在服務器上會被決議為http://ip:port/工程名/ 就是映射到IDEA代碼的web目錄
    • sc.getRealPath("/img"):表示獲取該工程下的img目錄在工程部署后在服務器硬碟上的絕對路徑;
  • setAttribute(別名,物件):將一個物件存盤到ServletContext物件中,起個別名;
  • getAttribute(別名):通過別名獲取存入其中的物件;
  • removeAttribute(別名):洗掉該別名中的物件;

web.xml檔案配置

<!--context-param是背景關系引數,屬于整個web工程,都能訪問到-->
<context-param>
    <!--param-name與param-value是存盤資料的標簽-->
    <param-name>name</param-name>
    <param-value>ROOT</param-value>
</context-param>
<context-param>
    <param-name>PSW</param-name>
    <param-value>123</param-value>
</context-param>

Java代碼

public class Servlet4 extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 獲取ServletContext 物件
        ServletContext sc = getServletContext();
        //獲取web.xml中配置的背景關系引數,context-param標簽中的資料
        System.out.println("name:"+sc.getInitParameter("name"));//name:ROOT
        System.out.println("PSW:"+sc.getInitParameter("PSW"));//PSW:123
        //獲取當前的工程路徑
        System.out.println("當前工程路徑"+sc.getContextPath());//當前工程路徑/JavaWeb_4
        //獲取工程部署后在服務器硬碟上的絕對路徑
        //   / 斜杠在服務器上會被決議為http://ip:port/工程名/   就是映射到IDEA代碼的web目錄
        System.out.println("工程部署的路徑是:"+sc.getRealPath("/"));//工程部署的路徑是:E:\IDEA\JavaWeb_4\out\artifacts\JavaWeb_4_war_exploded\
        System.out.println("工程下img目錄的絕對路徑是:"+sc.getRealPath("/img"));//工程下img目錄的絕對路徑是:E:\IDEA\JavaWeb_4\out\artifacts\JavaWeb_4_war_exploded\img
        System.out.println("工程下img目錄下的1.jpg檔案的絕對路徑是:"+sc.getRealPath("/img/1.jpg"));//工程下img目錄下的1.jpg檔案的絕對路徑是:E:\IDEA\JavaWeb_4\out\artifacts\JavaWeb_4_war_exploded\img\1.jpg

        // 獲取ServletContext 物件
        ServletContext context = getServletContext();
        System.out.println(context);
        System.out.println("保存之前:獲取key的值是:"+ context.getAttribute("key"));//保存之前:獲取key的值是:null
        //在key中存盤一個物件
        context.setAttribute("key", "value");
        System.out.println("存盤之后:獲取域資料key的值是:"+ context.getAttribute("key"));//存盤之后:獲取域資料key的值是:value
        //洗掉key里面存盤的物件
        context.removeAttribute("key");
        //上面的洗掉了key里面的物件,下面將獲取不到
        System.out.println("存盤之后:獲取域資料key的值是:"+ context.getAttribute("key"));//存盤之后:獲取域資料key的值是:null

    }
}

在這里插入圖片描述

這個上面的工程路徑是IDEA整合Tomcat之后,Tomcat被拷貝的一些副本內容,就是將IDEA實際存在的專案,映射進Tomcat服務器中;

setAttribute存盤的物件,要先存進去,然后整個web工程中所有Servlet程式才能夠訪問到,沒有存盤到ServletContext物件中,是獲取不到的;

HttpServletRequest類

  • 每次只要有請求進入Tomcat服務器,Tomcat服務器就會把請求過來的HTTP協議資訊決議好封裝到Request物件中,然后傳遞到service方法(doGet、doPost方法)中供我們使用;
  • 通過HTTPServletRequest物件,可以獲取所有請求的資訊;

HTTPServletRequest類的方法

  • getRequestURI() 獲取請求的資源路徑
  • getRequestURL() 獲取請求的統一資源定位符(絕對路徑)
  • getRemoteHost() 獲取客戶端的ip 地址
  • getHeader(引數) 獲取請求頭
    • 引數:要獲取的請求頭名稱
  • getMethod() 獲取請求的方式GET 或POST
  • getParameter(引數) 獲取請求的引數
    • 引數:要請求哪一個引數的值
  • getParameterValues(引數) 獲取請求的多個引數
    • 引數:要請求哪一個引數的值
  • setAttribute(別名,物件) 將物件作為request對象的一個屬性存放到request物件中;
    • 別名:String型別,就相當于request物件中的一個屬性,自己起名;
    • 物件:Object型別
  • getAttribute(別名) 獲取request物件中該別名的值(這個值可以是任何型別)
  • getRequestDispatcher(引數) 獲取請求轉發物件
    • 引數:就是要轉發給誰
  • getRequestDispatcher(引數).forward(request,response) 轉發

java代碼

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //獲取請求的資源路徑
  System.out.println("URI:"+request.getRequestURI());//URI:/JavaWeb_4/servlet5
    //獲取請求的統一資源定位符(絕對路徑)
  System.out.println("URL:"+request.getRequestURL());//URL:http://localhost:8080/JavaWeb_4/servlet5
    //獲取客戶端的ip 地址
    //IP:0:0:0:0:0:0:0:1      客戶端localhost:8080訪問,這個是ipv6的表現形式,對應ipv4來說相當于127.0.0.1
    //IP:192.168.137.1        使用真實IP地址訪問
    //IP:127.0.0.1            客戶端127.0.0.1:8080訪問
    System.out.println("IP:"+request.getRemoteHost());
    //獲取請求頭
    System.out.println("User-Agent請求頭"+request.getHeader("User-Agent"));//User-Agent請求頭Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36
    System.out.println("Accept-Language請求頭"+request.getHeader("Accept-Language"));//Accept-Language請求頭zh-CN,zh;q=0.9
    //獲取請求的方式GET 或POST
    System.out.println(request.getMethod());//GET
    ////////////////////////////////////////////////////////////////
    //獲取請求引數,就是獲取表單提交過來的引數值
    System.out.println("用戶名:"+request.getParameter("username"));//用戶名:MLYR
    System.out.println("密碼:"+request.getParameter("password"));//密碼:123
    //獲取請求的多個引數
    String[] hobby = request.getParameterValues("hobby");
    System.out.println("興趣愛好:"+ Arrays.toString(hobby));//興趣愛好:[java, js]
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //設定請求的字符集編碼為UTF-8,如果不設定,輸入中文會亂碼
    req.setCharacterEncoding("UTF-8");
    //獲取當前請求的字符編碼,需要提前設定,不然是null
    System.out.println(req.getCharacterEncoding());//UTF-8
    //獲取請求引數,就是獲取表單提交過來的引數值
    System.out.println("用戶名:"+req.getParameter("username"));//用戶名:中
    System.out.println("密碼:"+req.getParameter("password"));//密碼:1212
    //獲取多個請求的引數
    String[] hobby = req.getParameterValues("hobby");
    System.out.println("興趣愛好:"+ Arrays.toString(hobby));//興趣愛好:[cpp, java]
}

表單代碼

<form action="servlet5" method="get">
    用戶名:<input type="text" name="username"><br/>
    密碼:<input type="password" name="password"><br/>
    興趣愛好:<input type="checkbox" name="hobby" value="https://www.cnblogs.com/MLYR/p/cpp">C++
    <input type="checkbox" name="hobby" value="https://www.cnblogs.com/MLYR/p/java">Java
    <input type="checkbox" name="hobby" value="https://www.cnblogs.com/MLYR/p/js">JavaScript<br/>
    <input type="submit">
</form>

doGet()請求一般不會亂碼,如果有,按照下面的方法解決:

String username = request.getParameter("username");
//先以iso-8859-1進行編碼,再以utf-8進行解碼
username = new String(username.getBytes("iso-8859-1"),"UTF-8");
//獲取請求引數,就是獲取表單提交過來的引數值
System.out.println("用戶名:"+username);

HttpServletResponse類

  • HttpServletResponse類和HttpServletRequest類一樣,每一次請求進來,Tomcat服務器都會創建一個Response物件和Request物件;
  • HttpServletResponse表示所有的回應資訊,HttpServletRequest表示請求過來的資訊;
  • 要回傳給客戶端資訊,都是通過Response物件進行設定;

兩個輸出流

  • getOutputStream() 位元組流,常用于下載,傳遞二進制;
  • getWriter() 字符流,常用于回傳字串
  • 兩個流不能同時使用;

HttpServletResponse類的方法

  • setContentType() 同時設定服務器和客戶端的編碼格式
  • setCharacterEncoding() 設定服務器的編碼格式
  • setStatus(引數) 設定回應狀態嗎,表示重定向
  • setHeader() 通過回應頭設定瀏覽器的編碼格式
  • getWriter() 獲取字符輸出流物件PrintWriter
    • writer(引數) 寫資料,引數可以是Object、int、String、陣列、double...
  • getOutputStream() 獲取位元組輸出流物件ServletOutputStream
    • print(引數) 寫資料,,引數可以是int、String、陣列、double...不能寫物件
  • sendRedirect(引數) 重定向
    • 引數:要重定向的路徑

java代碼

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //它會同時設定服務器和客戶端都使用UTF-8 字符集,還設定了回應頭
    //此方法一定要在獲取流物件之前呼叫才有效
    response.setContentType("text/html; charset=UTF-8");
    //設定服務器字符集為UTF-8
    response.setCharacterEncoding("UTF-8");
    //通過回應頭,設定瀏覽器也使用UTF-8 字符集
    response.setHeader("Content-Type", "text/html; charset=UTF-8");
    //CharConversionException: 不是ISO 8859-1字符:[啦]
    System.out.println("doGet方法");
    //獲取字符輸出流物件
    //PrintWriter writer = response.getWriter();
    //寫資料
    //writer.println("啦啦啦lll");
    //獲取位元組輸出流物件
    ServletOutputStream os = response.getOutputStream();
    //寫資料
    os.print(121212121);
}   

java.lang.IllegalStateException: 當前回應已經呼叫了方法getOutputStream()

兩個流一起使用報錯

請求轉發與重定向

請求轉發

  • 服務器收到請求后,從一次資源跳轉到另一個資源的操作,叫做請求轉發;

在這里插入圖片描述

表單

<form action="servlet6" method="post">
    資訊:<input type="text" name="xinxi"><br/>
    <input type="submit">
</form>

Servlet6

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //設定請求的字符集編碼
    req.setCharacterEncoding("UTF-8");
    //獲取請求引數
    String xinxi = req.getParameter("xinxi");
    System.out.println(xinxi);//陌路邑人
    //設定資料域,就是將一個物件放進資料域中,起個別名key
    req.setAttribute("key","來自Servlet6");
    //獲取要轉發給的地址物件(一般與下面執行轉發是一步撰寫)  /servlet7就是http://localhost:8080/JavaWeb_4/servlet7
    RequestDispatcher rd = req.getRequestDispatcher("/servlet7");
    //執行轉發操作
    rd.forward(req,resp);
}

Servlet7

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //doPost方法中,必須是POST請求,才能被獲取
    //獲取請求引數
    String xinxi = request.getParameter("xinxi");//陌路邑人
    System.out.println(xinxi);
    //獲取Servlet6轉發過來的物件
    Object key = request.getAttribute("key");
    System.out.println("Servlet7獲取到Servlet6轉發過來的物件:"+key);//Servlet7獲取到Servlet6轉發過來的物件:來自Servlet6
}

表單中的提交是post請求方式,所以在兩個Servlet程式中,想要獲取表單提交的資料,必須也是doPost方法進行獲取;

a標簽的轉發

web工程下d.html

<head>
    <meta charset="UTF-8">
    <title>首頁</title>
</head>
<body>
<!--下方的可以與HTML下的e.html互相跳轉-->
<a href="https://www.cnblogs.com/MLYR/p/HTML/e.html">b.html</a>
<!--該標簽跳轉到servlet7程式配置的路徑上-->
<a href="https://www.cnblogs.com/MLYR/p/servlet7">請求轉發</a>
</body>

HTML下e.html

<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!--base 標簽設定頁面相對路徑作業時參照的地址href 屬性就是引數的地址值-->
    <base href="http://localhost:8080/JavaWeb_4/HTML/e.html">
</head>
<body>
    <a href="https://www.cnblogs.com/MLYR/d.html">回到首頁</a>
</body>

Servlet7

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    System.out.println("經過了Servlet7程式");
    //如果有請求到這,進行轉發到HTML下的e.html
  request.getRequestDispatcher("/HTML/e.html").forward(request,response);
}

這種情況沒有base標簽給e.html進行參照路徑的話,他就會報錯,找不到檔案;

下面解釋:

  1. 當首先訪問web工程下的d.html檔案時,它的絕對路徑是http://localhost:8080/JavaWeb_4/d.html;
  2. 當點擊請求轉發連接時,他就會跳到Servlet7程式所配置的路徑上:http://localhost:8080/JavaWeb_4/servlet7;
  3. 然后當點擊回到首頁連接時,它相當于將a標簽中的../d.html路徑與他現在所在的路徑進行拼接跳轉,就會跳轉到http://localhost:8080/JavaWeb_4/d.html(http://localhost:8080/JavaWeb_4/servlet7../d.html,../相當于與前面的目錄相抵消)路徑,當然找不到檔案;
  4. 當base標簽給e.html檔案給定一個絕對路徑http://localhost:8080/JavaWeb_4/HTML/e.html,就是該檔案的絕對路徑,不管怎么與a標簽上的../d.html進行拼接,他就可以找到正確的路徑

在這里插入圖片描述

重定向

  • 請求重定向,是指客戶端給服務器發送請求后,回傳服務器給客戶端一個新地址,讓客戶端重新去訪問新地址;

在這里插入圖片描述

java代碼

//Servlet9 
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    System.out.println("來晚了");
        /*request.setAttribute("kk","KKKKKK");
        //第一種重定向方式
        //設定回應狀態嗎,表市重定向
        response.setStatus(302);
        //設定回應頭,說明新地址
        response.setHeader("Location","servlet8");*/
    //第二種重定向,引數不能加/斜杠,這里的/會被服務器決議為http://localhost:8080/
    response.sendRedirect("servlet8");
}
//Servlet8
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    System.out.println("Servlet8doGet方法");
    //重定向不共享Request物件中的資料域
    System.out.println(req.getAttribute("kk"));
}

轉發與重定向的區別

  • 路徑區別
    • 相對路徑沒有區別;
    • 絕對路徑:
      • 轉發:中的/表示:http://ip:port/工程路徑;
      • 重定向:中的/表示:http://ip:port/;
  • 地址欄的變化
    • 轉發:地址欄不會顯示出轉發后的地址;
    • 重定向:則是完全跳轉到新地址,地址欄也就是新地址;
  • Request物件中的資料
    • 轉發:不會丟失資料;
    • 重定向:會丟失資料;
  • 請求次數
    • 轉發:客戶端只向服務器發送一次請求;
    • 重定向:客戶端發送了兩次請求給服務器;
  • 跳轉位置
    • 轉發:在服務器中跳轉;
    • 重定向:回傳給客戶端新地址,客戶端跳轉;
  • 訪問域
    • 轉發:只能在web工程中訪問跳轉;
    • 重定向:可以跨域訪問跳轉;就是隨便跳;
  • 能否訪問web工程的WEB-INF目錄
    • 轉發:可以訪問;
    • 重定向:不可以訪問;

監聽器

什么是監聽器?

  • Listener監聽器是JavaWeb的三大組件之一;
  • 作用:監聽某種事物的變化,然后通過回呼函式,反饋給客戶;

ServletContextListener監聽器

  • ServletContextListener 它可以監聽ServletContext 物件的創建和銷毀
  • ServletContext 物件在web 工程啟動的時候創建,在web 工程停止的時候銷毀,
  • 監聽到創建和銷毀之后都會分別呼叫ServletContextListener 監聽器的方法反饋
public interface ServletContextListener extends EventListener {
//在ServletContext 物件創建之后馬上呼叫,做初始化
public void contextInitialized(ServletContextEvent sce);
//在ServletContext 物件銷毀之后呼叫
public void contextDestroyed(ServletContextEvent sce);
}

如何實作ServletContextListener監聽器監聽ServletContext物件

public class Listener1 implements ServletContextListener{
    //ServletContext物件在創建的時候執行
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("ServletContext物件創建了");
    }
    //ServletContext物件在銷毀的時候被執行
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("ServletContext物件銷毀了");
    }
}
<!--配置監聽器-->
<listener>
    <listener-class>com.mlyr.listener.Listener1</listener-class>
</listener>

ServletContextListener監聽器的主要作用

  • 初始化作業:初始化物件,初始化資料,比如加載資料庫驅動,對連接池的初始化,
  • 加載一些初始化的組態檔;

Cookie

什么是Cookie?

  • Cookie 是一小段文本資訊,伴隨著用戶請求和頁面在 Web 服務器和瀏覽器之間傳遞,Cookie 包含每次用戶訪問站點時 Web 應用程式都可以讀取的資訊;

在這里插入圖片描述

為什么需要Cookie?

  • 因為HTTP協議是無狀態的,對于一個瀏覽器發出的多次請求,WEB服務器無法區分是否來源于同一個瀏覽器;
  • 所以,需要額外的資料用于維護會話;Cookie正是這樣一段隨HTTP請求一起被傳遞的額外資料;

Cookie的注意點

能不能一次發送多個Cookie?

  • 可以,可以創建多個Cookie物件,使用response呼叫多次addCookie方法發送即可;

Cookie能不能存中文?

  • 在Tomcat8之前不能存中文,要進行URL編碼(%E3)或者BASE64編碼將中文資料轉碼
  • 在Tomcat8之后支持中文資料,但是特殊字符還是不支持;

Cookie大小限制

  • 瀏覽器對于單個cookie 的大小有限制(4kb) 以及 對同一個域名下的總cookie數量也有限制(20個)

Cookie的創建、獲取、修改

在這里插入圖片描述

html頁面

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="pragma" content="no-cache" />
    <meta http-equiv="cache-control" content="no-cache" />
    <meta http-equiv="Expires" content="0" />
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Cookie</title>
    <base href="http://localhost:8080/JavaWeb_4/">
    <style type="text/css">
        ul li {
            list-style: none;
        }
    </style>
</head>
<body>
<iframe name="target"  height="500" style="float: left;"></iframe>
<div style="float: left;">
    <ul>
        <li><a href="https://www.cnblogs.com/MLYR/p/cookie1?action=createCookie" target="target">Cookie的創建</a></li>
        <li><a href="https://www.cnblogs.com/MLYR/p/cookie1?action=getCookie" target="target">Cookie的獲取</a></li>
        <li><a href="https://www.cnblogs.com/MLYR/p/cookie1?action=updateCookie" target="target">Cookie值的修改</a></li>
        <li>Cookie的存活周期</li>
        <li>
            <ul>
                <li><a href="https://www.cnblogs.com/MLYR/p/cookie1?action=defaultLife" target="target">Cookie的默認存活時間(會話)</a></li>
                <li><a href="https://www.cnblogs.com/MLYR/p/cookie1?action=deleteNow" target="target">Cookie立即洗掉</a></li>
                <li><a href="https://www.cnblogs.com/MLYR/p/cookie1?action=life3600" target="target">Cookie存活3600秒(1小時)</a></li>
            </ul>
        </li>
        <li><a href="https://www.cnblogs.com/MLYR/p/cookie1?action=testPath" target="target">Cookie的路徑設定</a></li>
        <li><a href="" target="target">Cookie的用戶免登錄練習</a></li>
    </ul>
</div>
</body>
</html>

java代碼

package com.mlyr.Cookie;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class Cookie1 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request,response);
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setCharacterEncoding("UTF-8");
        String action = request.getParameter("action");
        switch (action){
            case "createCookie":
                createCookie(request,response);
                break;
            case "getCookie":
                getCookie(request,response);
                break;
            case "updateCookie":
                updateCookie(request,response);
                break;
        }
    }
// Cookie的創建
    protected void createCookie(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //創建Cookie物件
        Cookie cookie1 = new Cookie("key1", "value1");
        Cookie cookie2 = new Cookie("key2", "value2");
        //保存到客戶端
        response.addCookie(cookie1);
        response.addCookie(cookie2);
        //回傳資訊給客戶端頁面
        response.getWriter().write("Cookie創建成功{Cookie1:"+cookie1+"-->Cookie2:"+cookie2+"}");
    }
// Cookie的獲取
    protected void getCookie(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //通過請求獲取客戶端中的Cookie陣列
        Cookie[] cookies = request.getCookies();
        for (Cookie cookie : cookies) {
            //getName():獲取到Cookie的key值
            //getValue():獲取到Cookie的value值
            response.getWriter().write("key=="+cookie.getName()+"-->valuehttps://www.cnblogs.com/MLYR/p/=="+cookie.getValue()+"\n");
        }
        Cookie key1 = CookieUtils.findCookie("key1", cookies);
        String value = https://www.cnblogs.com/MLYR/p/key1.getValue();
        response.getWriter().write("key1=="+value);
    }
// Cookie的修改
    protected void updateCookie(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        //第一種方式:直接創建一個新的Cookie物件,key值與要修改的一樣,直接覆寫掉原來的
        Cookie cookie = new Cookie("key1", "我改了");
        response.addCookie(cookie);
        //第二種方式:先找到要修改的Cookie物件,呼叫setValue()方法修改值
        Cookie key2 = CookieUtils.findCookie("key2", request.getCookies());
        if (key2!=null){
            //修改
            key2.setValue("人傻了");
            //通知客戶端
            response.addCookie(key2);
        }else {
            System.out.println("沒找到");
        }
    }
}

查找Cookie

import javax.servlet.http.Cookie;
// Cookie工具類
public class CookieUtils {
    public static Cookie findCookie(String name,Cookie[] cookies ){
        //判斷當名字、Cookie陣列任意一個為null時,就沒有必要查詢了
        if (name == null || cookies == null || cookies.length ==0){
            return null;
        }
        //回圈遍歷Cookie陣列
        for (Cookie cookie : cookies) {
            //當name與cookie中的key值相同就回傳它
            if (name.equals(cookie.getName())) {
                return cookie;
            }
        }
        return null;
    }
}

Cookie的生命周期

  • setMaxAge(int seconds):這個方法就是設定Cookie的保存時間的方法;
    • 正數:要保存的時間秒數,將Cookie資料寫到硬碟中;
    • 負數:默認值,當瀏覽器關閉,Cookie資料被銷毀;
    • 零:洗掉Cookie資訊;
//Cookie的立即洗掉
private void deleteNow(HttpServletRequest request, HttpServletResponse response) throws IOException {
    Cookie key3 = CookieUtils.findCookie("key3", request.getCookies());
    if (key3!=null){
        key3.setMaxAge(0);
        response.addCookie(key3);
        response.getWriter().write("Key3已經洗掉!!!");
    }
}
//保存3600秒
private void life3600(HttpServletRequest request, HttpServletResponse response) throws IOException {
    Cookie key4 = new Cookie("key4", "3600");
    //設定保存key4的時間
    key4.setMaxAge(60*60);
    response.addCookie(key4);
    response.getWriter().write("Key4已經設定保存時間1小時");
}

Cookie的共享設定

  • 默認的Cookie只能在一個應用中共享,即一個Cookie只能由創建它的應用獲得,
  • setPath():設定cookie的共享范圍;
    • cookie.setPath("/"):可在同一應用服務器內共享方法
    • cookie.setPath(request.getContextPath()+"/HTML");只在該工程的HTML下共享,別的目錄下獲取不到
private void testPath(HttpServletRequest request, HttpServletResponse response) throws IOException {
    Cookie cookie = new Cookie("key5", "有效路徑");
    cookie.setPath(request.getContextPath()+"/HTML");
    response.addCookie(cookie);
    response.getWriter().write("創建了一個帶有路徑的cookie");
}

免輸入用戶名登錄

java代碼

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //獲取到請求進來的用戶名與密碼
    String username = request.getParameter("username");
    String password = request.getParameter("password");
    //先給定一個死的值
    if ("111111".equals(username) && "111111".equals(password)){
        //將請求進來的用戶名放入Cookie物件中
        Cookie cookie = new Cookie("username",username);
        //設定它的保存時間
        cookie.setMaxAge(60*60*60);
        //回傳給客戶端
        response.addCookie(cookie);
        System.out.println("登陸成功");
    }else{
        System.out.println("登錄失敗");
    }
}

jsp頁面

  • jap頁面中的用戶名輸入框中的value值就在cookie域中拿就行,第一次沒有默認就為空,第二次訪問時,Cookie域中就會保存有用戶名,當訪問時就有了用戶名
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="http://localhost:8080/JavaWeb_4/cookie2" method="get">
    用戶名:<input type="text" name="username" value="https://www.cnblogs.com/MLYR/p/${cookie.username.value}"> <br>
    密碼:<input type="password" name="password"> <br>
    <input type="submit" value="https://www.cnblogs.com/MLYR/p/登錄">
</form>
</body>
</html>

Session

什么是Session?

  • Session 就是會話,它是用來維護一個客戶端和服務器之間關聯的一種技術;
  • Session是另一種記錄客戶狀態的機制,不同的是Cookie保存在客戶端瀏覽器中,而Session保存在服務器上,
  • 客戶端瀏覽器訪問服務器的時候,服務器把客戶端資訊以某種形式記錄在服務器上,這就是Session,客戶端瀏覽器再次訪問時只需要從該Session中查找該客戶的狀態就可以了

創建Session物件、Session域中的存取

HTML頁面

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="pragma" content="no-cache" />
        <meta http-equiv="cache-control" content="no-cache" />
        <meta http-equiv="Expires" content="0" />
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Session</title>
        <base href="http://localhost:8080/JavaWeb_4/">
        <style type="text/css">
            ul li {
                list-style: none;
            }
        </style>
    </head>
    <body>
        <iframe name="target"  height="500" style="float: left;"></iframe>
        <div style="float: left;">
            <ul>
                <li><a href="https://www.cnblogs.com/MLYR/p/session1?action=createOrGetSession" target="target">Session的創建和獲取(id號、是否為新創建)</a></li>
                <li><a href="https://www.cnblogs.com/MLYR/p/session1?action=setAttribute" target="target">Session域資料的存盤</a></li>
                <li><a href="https://www.cnblogs.com/MLYR/p/session1?action=getAttribute" target="target">Session域資料的獲取</a></li>
                <li>Session的存活</li>
                <li>
                    <ul>
                        <li><a href="https://www.cnblogs.com/MLYR/p/session1?action=defaultLife" target="target">Session的默認超時及配置</a></li>
                        <li><a href="https://www.cnblogs.com/MLYR/p/session1?action=life3" target="target">Session3秒超時銷毀</a></li>
                        <li><a href="https://www.cnblogs.com/MLYR/p/session1?action=deleteNow" target="target">Session馬上銷毀</a></li>
                    </ul>
                </li>
                <li><a href="" target="target">瀏覽器和Session系結的原理</a></li>
            </ul>
        </div>
    </body>
</html>

java代碼

package com.mlyr;

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 javax.servlet.http.HttpSession;
import java.io.IOException;

@WebServlet("/session1")
public class Session1 extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        String action = request.getParameter("action");
        switch (action){
            case "createOrGetSession":
                createOrGetSession(request,response);
                break;
            case "setAttribute":
                setAttribute(request,response);
                break;
            case "getAttribute":
                getAttribute(request,response);
                break;
        }
    }
      //Session的創建和獲取(id號、是否為新創建)
    protected void createOrGetSession(HttpServletRequest request, HttpServletResponse response) throws IOException {
        //創建Session物件
        HttpSession session = request.getSession();
        //獲取Session物件的ID值
        String id = session.getId();
        //判斷Session是否剛剛創建的
        boolean aNew = session.isNew();
        //將結果回應給頁面
        response.getWriter().write("Session物件:"+session+"\n");
        response.getWriter().write("Session物件的ID值:"+id+"\n");
        response.getWriter().write("判斷Session是否剛剛創建的:"+aNew+"\n");
    }
    //Session域資料的存盤
    protected void setAttribute(HttpServletRequest request, HttpServletResponse response) throws IOException {
        //向Session域中存放資料
        request.getSession().setAttribute("key1","value1");
        response.getWriter().write("Session域資料的存盤完成");
    }
    //Session域資料的獲取
    protected void getAttribute(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        //獲取Session域中的資料
        Object key1 = request.getSession().getAttribute("key1");
        response.getWriter().write("獲取Session域中的資料:"+key1);
    }
}

Session生命周期

  • public void setMaxInactiveInterval(int interval) 設定Session 的超時時間(以秒為單位),超過指定的時長,Session就會被銷毀,
    • 值為正數的時候,設定Session 的超時時長,
    • 負數表示永不超時(極少使用)
  • public int getMaxInactiveInterval()獲取Session 的超時時間
  • public void invalidate() 讓當前Session會話馬上超時無效

Session的默認Session超時時長

  • IDEA中Using CATALINA_BASE整合后的路徑下,web.xml組態檔中默認配置了Session的超時時長為30分鐘
<session-config>
    <session-timeout>30</session-timeout>
</session-config>
  • 如果想修改整個Web工程的所有Session超時時長,可以在Web工程下的web.xml組態檔中添加配置,就是上面的
  • 如果只想修改個別Session的超時時長,使用setMaxInactiveInterval()方法單獨設定
//Session的默認超時及配置
protected void defaultLife(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
    int maxInactiveInterval = request.getSession().getMaxInactiveInterval();
    response.getWriter().write("Session的默認超時時長:"+maxInactiveInterval);
}
//Session3秒超時銷毀
protected void life3(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
    request.getSession().setMaxInactiveInterval(3);
    response.getWriter().write("已經設定Session的超時時長為3秒");
}
//Session馬上銷毀
protected void deleteNow(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
    request.getSession().invalidate();
    response.getWriter().write("設定Session立即銷毀");
}

在這里插入圖片描述

Session的實作原理

  • Session 技術,底層其實是基于Cookie 技術來實作的,

在這里插入圖片描述

sessioncookie的聯系和區別

  • session和cookie都可以保存跟特定會話關聯的資訊
  • session的資訊是存放在服務器端的,cookie的資訊是存放在瀏覽器端
  • session中可以存放Object,cookie只能存放字串資訊

過濾器

是什么過濾器?

  • Filter過濾器是JavaWeb的三大組件之一;
  • 過濾器實際上就是對web資源進行攔截,做一些處理后再交給下一個過濾器或servlet處理,通常都是用來攔截request進行處理的,也可以對回傳的response進行攔截處理;
  • 它的作用:攔截請求,過濾回應;
    • 攔截請求的常見應用場景:權限檢查、日記操作、事務管理...

在這里插入圖片描述

創建一個Filter過濾器

  • 權限設定,沒有登錄的不能直接訪問web工程下的HTML目錄下的所有資源

首先一個登陸頁面

  • 提交到LoginServlet程式
<form action="http://localhost:8080/JavaWeb_4/loginservlet" method="get">
    用戶名:<input type="text" name="username"/><br/>
    密  碼:<input type="password" name="password"/><br/>
    <input type="submit"/>
</form>

LoginServlet程式

@WebServlet(name = "LoginServlet",urlPatterns = "/loginservlet")
public class LoginServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //處理回應亂碼
        response.setContentType("text/jsp;charset=UTF-8");
        //獲取輸入的用戶名以及密碼
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        //先給定一個值
        if ("abcdef".equals(username) && "123456".equals(password)){
            //如果用戶名密碼正確,將用戶名保存在Session域中
            request.getSession().setAttribute("username",username);
            response.getWriter().write("登陸成功!!!");
        }else {
            request.getRequestDispatcher("/index.jsp").forward(request,response);
        }
    }
}

登陸成功之后將用戶名放入到Session域中

創建Filter過濾器

public class Filter1 implements Filter {
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        //通過ServletRequest請轉獲取到HttpServletRequest請求
        HttpServletRequest request = (HttpServletRequest) req;
        //通過request請求再獲取Session域
        HttpSession session = request.getSession();
        //查詢Session與中是否有用戶名資訊,有說明已經登錄,可訪問HTML下的
        Object username = session.getAttribute("username");
        //為null,就說明沒有登錄
        if (username == null) {
            //沒有登錄就重定向到登錄頁面
            req.getRequestDispatcher("/index.jsp").forward(req, resp);
        } else {
            //登錄的話,就放行,該請求哪里就讓他到哪里
            chain.doFilter(req, resp);
        }
    }
}

當Session域中沒有用戶名的時候(用戶沒有登錄),放強行訪問HTML下的資源時,就會被過濾器重定向到登錄頁面,只有當Session域中存在用戶名時,才會被過濾器放行允許其訪問HTML下的資源

Filter過濾器的web配置

<!--filter 標簽用于配置一個Filter 過濾器-->
<filter>
    <!--給filter起一個別名-->
    <filter-name>Filter1</filter-name>
    <!--配置filter的全類名-->
    <filter-class>com.mlyr.filter.Filter1</filter-class>
</filter>
<!--filter過濾器攔截的路徑-->
<filter-mapping>
    <!--給那個filter過濾器使用-->
    <filter-name>Filter1</filter-name>
    <!--url-pattern:配置filter的攔截路徑
            /  表示http://ip:port/工程路徑/   映射到web目錄
            /HTML/*</  表示攔截http://ip:port/工程路徑/HTML/目錄下的所有檔案及目錄
        -->
    <url-pattern>/HTML/*</url-pattern>
</filter-mapping>

Filter的生命周期

public class Filter2 implements Filter {
    //構造方法
    public Filter2() {}
    @Override//init()初始化方法
    public void init(FilterConfig filterConfig) throws ServletException {}
    @Override//doFilter()過濾方法
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {}
    @Override//destroy()銷毀方法
    public void destroy() {}
}

構造方法與init()初始化方法在web工程啟動的時候執行

doFilter()過濾方法在每次攔截到請求時執行

destroy()銷毀方法在停止web工程的時候執行

FilterConfig類

  • 它是Filter過濾器的組態檔類
  • 當web工程創建Filter過濾器時,同時會創建一個FilterConfig類
  • 它的作用:獲取Filter過濾器的配置內容
    • 獲取Filter的名稱,也就是filter-name標簽中的內容
    • 獲取Filter中配置的init-param初始化的內容
    • 獲取ServletContext物件
public void init(FilterConfig config) throws ServletException {
    //獲取Filter過濾器名字
    System.out.println(config.getFilterName());//Filter3
    //獲取init初始化內容
    System.out.println(config.getInitParameter("name"));//張三
    //獲取ServletContext物件
    ServletContext servletContext = config.getServletContext();
}
<filter>
    <filter-name>Filter3</filter-name>
    <filter-class>com.mlyr.filter.Filter3</filter-class>
    <init-param>
        <param-name>name</param-name>
        <param-value>張三</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>Filter3</filter-name>
    <url-pattern>/</url-pattern>
</filter-mapping>

FilterChain過濾鏈

  • 如果有多個過濾器,它就形成了一個FilterChain過濾器鏈
  • 那個Filter先執行與Filter的配置相關,在web.xml組態檔中,那個配置在最前方,那個就先執行
  • 第一個執行到doFilter時,會進行判斷,如果有下一個Filter,就去執行下個Filter;沒有的話,就直接執行資源檔案,然后回傳Filter執行doFilter后面的代碼
  • 所有的Filter和目標資源默認在同一個執行緒中;多個Filter執行的時候,他們使用同一個Request物件

在這里插入圖片描述

Filter的攔截路徑分類

精確匹配

  • 只會攔截HTML下的a.html的請求
<url-pattern>/HTML/a.html</url-pattern>

目錄匹配

  • 只會攔截HTML下的所有請求
<url-pattern>/HTML/*</url-pattern>

后綴名匹配

  • 只會攔截以.html結尾的請求
<url-pattern>*.html</url-pattern>

Filter過濾器只關心請求的地址是否匹配,不關心請求的資源是否存在

不經風雨,怎見彩虹?

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/545168.html

標籤:Java

上一篇:面試官:怎么洗掉 HashMap 中的元素?我一行代碼搞定,趕緊拿去用!

下一篇:IDEA2022.3永久激活破解 最新激活 一鍵激活 親測可用!

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more