主頁 >  其他 > 學習JavaWeb這一篇就夠了

學習JavaWeb這一篇就夠了

2020-10-21 06:45:43 其他

目錄

  • 第一章 開發工具
    • 1.1、JDK安裝
    • 1.2、Tomcat安裝
    • 1.3、IDEA安裝
    • 1.4、IDEA集成Tomcat
    • 1.5、IDEA運行JavaWeb
  • 第二章 XML(選學)
    • 2.1、XML的概述
    • 2.2、XML的語法
    • 2.3、XML的決議
  • 第三章 YAML(選學)
    • 3.1、YAML的概述
    • 3.2、YAML的語法
    • 3.3、YAML的決議
  • 第四章 Servlet
    • 4.1、Servlet概述
    • 4.2、Servlet語法格式
    • 4.3、Servlet執行程序
    • 4.4、Servlet生命周期
    • 4.5、Servlet繼承體系
    • 4.6、ServletContext
      • 4.6.1、獲取全域配置引數
      • 4.6.2、獲取web工程中的資源
      • 4.6.3、在Servlet間共享資料域物件
    • 4.7、ServletConfig
    • 4.8、HttpServletRequest
    • 4.9、HttpServletResponse
    • 4.10、重定向和請求轉發
    • 4.11、Cookie
    • 4.12、Session
  • 第五章 Listener
    • 5.1、監聽三個作用域創建和銷毀
      • 5.1.1、ServletContextListener
      • 5.1.2、ServletRequestListener
      • 5.1.3、HttpSessionListener
    • 5.2、監聽三個作用域屬性狀態變更
      • 5.2.1、ServletContextAttributeListener
      • 5.2.2、ServletRequestAttributeListener
      • 5.2.3、HttpSessionAttributeListener
    • 5.3、監聽HttpSession存值狀態變更
      • 5.3.1、HttpSessionBindingListener
      • 5.3.2、HttpSessionActivationListener
  • 第六章 Filter
    • 6.1、Filter概述
    • 6.2、Filter生命周期
    • 6.3、Filter語法
    • 6.4、Filter執行順序
    • 6.5、Filter匹配規則
    • 6.6、Filter攔截型別
    • 6.7、Filter統一編碼
  • 第七章 JSP
    • 7.1、JSP概述
    • 7.2、JSP生命周期
    • 7.3、JSP語法
      • 7.3.1、JSP腳本程式
      • 7.3.2、JSP變數宣告
      • 7.3.3、JSP運算式
      • 7.3.4、JSP注釋
      • 7.3.5、JSP指令元素
        • 7.3.5.1、page指令
        • 7.3.5.2、include指令
        • 7.3.5.3、taglib指令
      • 7.3.6、JSP動作元素
        • 7.3.6.1、jsp:include動作
        • 7.3.6.2、jsp:useBean動作
        • 7.3.6.3、jsp:setProperty動作
        • 7.3.6.4、jsp:getProperty動作
        • 7.3.6.5、jsp:forward動作
      • 7.3.7、JSP隱含物件
      • 7.3.8、JSP常見控制
    • 7.4、EL運算式
      • 7.4.1、EL概述
      • 7.4.2、EL語法
      • 7.4.3、EL隱含物件
      • 7.4.4、EL案例演示
    • 7.5、JSTL運算式
      • 7.5.1、JSTL概述
      • 7.5.2、JSTL依賴
      • 7.5.3、JSTL常用標簽
  • 第八章 Servlet3.0
    • 8.1、注解開發
      • 8.1.1、servlet注解
      • 8.1.2、filter注解
      • 8.1.3、listener注解
      • 8.1.4、兩種配置同時存在
      • 8.1.5、如何禁用注解組件
    • 8.2、檔案上傳
    • 8.3、異步處理
    • 8.4、動態注冊
      • 8.4.1、servlet動態注冊
      • 8.4.2、filter動態注冊
      • 8.4.3、listener動態注冊
    • 8.5、可插性支持


配套資料,免費下載
鏈接:https://pan.baidu.com/s/1DNouClLLp4OB8mniUJGmBg
提取碼:dq2w
復制這段內容后打開百度網盤手機App,操作更方便哦

第一章 開發工具

1.1、JDK安裝

第一步:打開官網進行下載(https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html)

image-20200907214959179

第二步:運行程式進行安裝

全部默認下一步即可,不用管路徑是不是存在中文和空格,無礙!

注意:如果自己會配置JDK,可以更改它的安裝路徑,那相應的環境變數也需要修改!

第三步:系統環境變數配置

此電腦 》 右鍵 》 屬性 》 高級系統設定 》 環境變數 》 系統變數 》 新建(需要新建兩個,然后修改一個)

新建兩個:JAVA_HOME代表Java的安裝目錄、CLASSPATH代表程式運行的時候,優先加載當前目錄中的類,然后再加載指定的類別庫

變數名變數值
JAVA_HOMEC:\Program Files\Java\jdk1.8.0_261
CLASSPATH.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;

修改一個:編輯PATH環境變數,它會打開一個視窗,新添兩條路徑,如下圖所示

  • %JAVA_HOME%\bin
  • %JAVA_HOME%\jre\bin

image-20200907215851494

第四步:測驗JDK是否安裝成功

打開一個cmd命令列視窗,輸入以下兩個命令查看,如果有內容輸出則證明已經配置成功!

  • java -version
  • javac -version

image-20200907220105432

1.2、Tomcat安裝

第一步:打開官網進行下載和安裝(http://tomcat.apache.org/)

image-20200907220244579

image-20200907220424149

第二步:系統環境變數配置

此電腦 》 右鍵 》 屬性 》 高級系統設定 》 環境變數 》 系統變數 》 新建(需要新建兩個,然后修改三個)

新建兩個:CATALINA_BASE和CATALINA_HOME均代表Tomcat的安裝目錄

變數名變數值
CATALINA_BASEC:\DevTools\apache-tomcat-8.5.57 (輸入自己解壓的Tomcat目錄,不要照抄我的)
CATALINA_HOMEC:\DevTools\apache-tomcat-8.5.57 (輸入自己解壓的Tomcat目錄,不要照抄我的)

修改一個:編輯CLASSPATH環境變數,它會打開一個視窗,具體修改,如下所示

  • 未修改前:.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;
  • 修改以后:.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;%CATALINA_HOME%\lib\servlet-api.jar;

修改兩個:編輯PATH環境變數,它會打開一個視窗,新添兩條路徑,如下所示

  • %CATALINA_HOME%\bin
  • %CATALINA_HOME%\lib

image-20200907221151092

第三步:測驗Tomcat是否安裝成功

打開一個cmd命令列視窗,輸入以下一個命令查看,如果有內容輸出則證明已經配置成功!

  • catalina run

image-20200907221408847

  • 打開瀏覽器,輸入:http://localhost:8080/

image-20200907221604709

如果看到上邊這個界面了,就把剛才打開的cmd視窗關掉,否則可能會影響后邊IDEA集成Tomcat,

1.3、IDEA安裝

注意:官網的版本會隔一段時間更新一次,我這里只是告訴大家怎么下載,不一定要用最新的,我這套課程使用的是IdeaIU-2020.1.2,如果你不是這個版本,那么我建議你改為這個版本,否則后邊可能會出現一些列問題,

第一步:打開官網進行下載和安裝(https://www.jetbrains.com/idea/)

image-20200907222300232

image-20200907222332219

第二步:運行程式進行安裝

全部默認下一步即可,如果遇到需要一頁打勾的很多,就把有 64 的那個勾上,它代表在桌面創建一個64位的快捷方式,沒勾選也沒事,可以在開始選單打開IDEA!

第三步:關于激活的問題

由于IDEA是收費軟體,請大家自行購買激活碼,然后激活,不激活也可以試用30天!

第四步:常見的設定頁面

image-20200907223241943

image-20200907223302280

image-20200907223343795

第五步:最終的效果圖

image-20200907223037244

1.4、IDEA集成Tomcat

image-20200907223119686

image-20200907223641318

1.5、IDEA運行JavaWeb

image-20200907223827886

image-20200907223915248

image-20200907224005180

注意:這個彈窗意思是你需不需要每天都讓我提示你一些小技巧,我們選擇關閉,不用搭理他!

image-20200907224035030

注意:如果你有依賴的JAR包,就放到lib檔案夾中,然后添加到工程中,方便專案移動的時候,不會丟失JAR包,

至于classes是否需要創建,在這里我個人認為是不需要創建的,因為編譯器會自動創建,如果你創建了,還必須要修改配置資訊,很麻煩,所以我建議就不要創建了,一般我們也不會創建,

image-20200907224153040

image-20200907224212180

注意:Fix并不是所有電腦都需要點擊的,如果它彈出了這個視窗你就點擊,沒彈出來就不用管了!

image-20200907224238302

注意:只有上邊點擊了Fix才會出來這個頁面,沒有點擊Fix,這一步忽略即可,不用糾結!

image-20200907224256452

image-20200907224331553

image-20200909151337789

image-20200909151021071

image-20200909151119004

image-20200909151152023

image-20200909151219563image-20200908180738106

image-20200908180908788

一般瀏覽器也會正常顯示剛才JSP中的檔案內容

image-20200908181054089

image-20200908181130916

第二章 XML(選學)

2.1、XML的概述

XML是可擴展標記語言(eXtensible Markup Language),它被設計用來傳輸和存盤資料,我們一般使用XML檔案來做應用程式的組態檔,

2.2、XML的語法

案例演示:

<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
	<book category="COOKING">
		<title lang="en">Everyday Italian</title>
		<author>Giada De Laurentiis</author>
		<year>2005</year>
		<price>30.00</price>
	</book>
	<book category="CHILDREN">
		<title lang="en">Harry Potter</title>
		<author>J K. Rowling</author>
		<year>2005</year>
		<price>29.99</price>
	</book>
	<book category="WEB">
		<title lang="en">Learning XML</title>
		<author>Erik T. Ray</author>
		<year>2003</year>
		<price>39.95</price>
	</book>
</bookstore>

樹狀結構:

image-20200826153729304

支持語法:

  • 嵌套標簽
  • 單級標簽
  • 內含屬性

注意:根節點只能有一個

注釋語法:

<!-- comment -->

2.3、XML的決議

決議方式:

  • DOM(Document Object Model):在決議的時候,它會把整個XML檔案讀入記憶體中,形成一個樹狀結構,整個檔案稱之為Document物件,所有元素節點對應Element物件,屬性對應Attribute物件,文本對應Text物件,以上所有物件都可以稱之為Node節點,如果XML特別大,可能會造成記憶體溢位,這種決議方式可以對XML檔案進行增刪改查操作,
  • SAX(Simple API For XML):它是基于事件驅動的一種決議方式,也就是讀取一行,決議一行,在讀取較大的XML檔案的時候,也不會造成記憶體溢位,但是這種決議方式只能進行查詢,不能進行增刪改操作,

案例演示:

工程名稱:XMLDemo

包的名稱:com.caochenlei.xml.parse

依賴檔案:dom4j-1.6.1.jar、jaxen-1.1-beta-6.jar、JUnit 4

測驗檔案:bookstore.xml(全路徑:/XMLDemo/bookstore.xml)

<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
	<book category="COOKING">
		<title lang="en">Everyday Italian</title>
		<author>Giada De Laurentiis</author>
		<year>2005</year>
		<price>30.00</price>
	</book>
	<book category="CHILDREN">
		<title lang="en">Harry Potter</title>
		<author>J K. Rowling</author>
		<year>2005</year>
		<price>29.99</price>
	</book>
	<book category="WEB">
		<title lang="en">Learning XML</title>
		<author>Erik T. Ray</author>
		<year>2003</year>
		<price>39.95</price>
	</book>
</bookstore>

代碼名稱:XMLParse.java(全路徑:/XMLDemo/src/com/caochenlei/xml/parse/XMLParse.java)

package com.caochenlei.xml.parse;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.List;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.junit.Test;

public class XMLParse {

	/**
	 * 讀取全部
	 */
	@Test
	public void test1() {
		try {
			SAXReader domReader = new SAXReader();
			Document document = domReader.read(new File("bookstore.xml"));
			Element rootElement = document.getRootElement();
			List<Element> bookElements = rootElement.elements("book");
			for (Element bookElement : bookElements) {
				Attribute category = bookElement.attribute("category");
				String title = bookElement.element("title").getText();
				String author = bookElement.element("author").getText();
				String year = bookElement.element("year").getText();
				String price = bookElement.element("price").getText();
				System.out.println(Arrays.asList(category.getText(), title, author, year, price));
			}
		} catch (DocumentException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 新增一行
	 */
	@Test
	public void test2() {
		try {
			SAXReader domReader = new SAXReader();
			Document document = domReader.read(new File("bookstore.xml"));
			Element rootElement = document.getRootElement();

			Element bookElement = rootElement.addElement("book");
			bookElement.addAttribute("category", "Hibernate");
			bookElement.addElement("title").addText("Learing Hibernate");
			bookElement.addElement("author").addText("caochenlei");
			bookElement.addElement("year").addText("1997");
			bookElement.addElement("price").addText("99.99");

			XMLWriter xmlWriter = new XMLWriter(new FileOutputStream("bookstore.xml"), OutputFormat.createPrettyPrint());
			xmlWriter.write(document);
			xmlWriter.close();
		} catch (DocumentException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 洗掉一行
	 */
	@Test
	public void test3() {
		try {
			SAXReader domReader = new SAXReader();
			Document document = domReader.read(new File("bookstore.xml"));
			Element rootElement = document.getRootElement();

			Node singleNode = rootElement.selectSingleNode("//book[@category='Hibernate']");
			rootElement.remove(singleNode);

			XMLWriter xmlWriter = new XMLWriter(new FileOutputStream("bookstore.xml"), OutputFormat.createPrettyPrint());
			xmlWriter.write(document);
			xmlWriter.close();
		} catch (DocumentException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 修改一行
	 */
	@Test
	public void test4() {
		try {
			SAXReader domReader = new SAXReader();
			Document document = domReader.read(new File("bookstore.xml"));
			Element rootElement = document.getRootElement();

			Node singleNode = rootElement.selectSingleNode("//book[@category='WEB']");
			singleNode.selectSingleNode("title").setText("Learning JavaWeb");
			singleNode.selectSingleNode("author").setText("張三");
			singleNode.selectSingleNode("year").setText("2020");
			singleNode.selectSingleNode("price").setText("09.09");

			XMLWriter xmlWriter = new XMLWriter(new FileOutputStream("bookstore.xml"), OutputFormat.createPrettyPrint());
			xmlWriter.write(document);
			xmlWriter.close();
		} catch (DocumentException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}

第三章 YAML(選學)

3.1、YAML的概述

YAML(YAML Ain’t Markup Language)是一種可讀性高并且容易被人類閱讀,容易和腳本語言互動,用來表達資料序列的編程語言,類似于XML但比XML更簡潔,

3.2、YAML的語法

YAML語法:

  • 大小寫敏感
  • 使用空格縮進表示層級關系
  • 縮進不允許使用tab,只允許空格
  • 縮進的空格數不重要,只要相同層級的元素左對齊即可
  • '#'表示注釋
  • 相同層級的鍵不能重復

YAML物件:

物件鍵值對使用冒號結構表示 key: value,冒號后面要加一個空格,也可以使用 key:{key1: value1, key2: value2, …},還可以使用縮進表示層級關系,

key: 
  child-key1: value1
  child-key2: value2

較為復雜的物件格式,可以使用問號加一個空格代表一個復雜的 key,配合一個冒號加一個空格代表一個 value:

? 
  - complexkey1
  - complexkey2
: 
  - complexvalue1
  - complexvalue2

意思即物件的屬性是一個陣列 [complexkey1,complexkey2],對應的值也是一個陣列 [complexvalue1,complexvalue2]

YAML陣列:

以 - 開頭的行表示構成一個陣列:

- A
- B
- C

YAML 支持多維陣列,可以使用行內表示:

key: [value1, value2, ...]

資料結構的子成員是一個陣列,則可以在該項下面縮進一個空格:

-
 - A
 - B
 - C

一個相對復雜的例子:意思是 companies 屬性是一個陣列,每一個陣列元素又是由 id、name、price 三個屬性構成,

companies:
 -
  id: 1
  name: company1
  price: 200W
 -
  id: 2
  name: company2
  price: 500W

陣列也可以使用流式(flow)的方式表示:

companies: [{id: 1,name: company1,price: 200W},{id: 2,name: company2,price: 500W}]

YAML純量:

純量是最基本的,不可再分的值,包括:

  • 字串
  • 布林值
  • 整數
  • 浮點數
  • Null
  • 時間
  • 日期

使用一個例子來快速了解純量的基本使用:

boolean: 
  - TRUE                          #true,True都可以
  - FALSE                         #false,False都可以
float:
  - 3.14                          #可以直接寫浮點小數
  - 6.8523015e+5                  #可以使用科學計數法
int:
  - 123                           #十進制表示
  - 0b1010_0111_0100_1010_1110    #二進制表示
null:
  nodeName: 'node'
  parent: ~                       #使用~表示null
string:
  - 哈哈
  - 'Hello World'                 #可以使用雙引號或者單引號包裹特殊字符                 
  - comment1:                     #字串可以拆成多行,每一行會被轉化成一個空格   
      newline1
      newline2
  - comment2: >                   #它會在注釋的最后一行加上\n              
      newline3
      newline4
  - comment3: |                   #它會在注釋的每一行尾加上\n              
      newline3
      newline4
date:
  - 2018-02-17 15:02:31           #日期必須使用ISO 8601格式,即yyyy-MM-dd hh-mm-ss
datetime: 
  - 2018-02-17T15:02:31+08:00     #時間使用ISO 8601格式,時間和日期之間使用T連接,最后使用+代表時區

YAML參考:

& 錨點和 * 別名,可以用來參考:

defaults: &defaults
  adapter: postgres
  host: localhost

development:
  database: myapp_development
  <<: *defaults

test:
  database: myapp_test
  <<: *defaults

上邊的代碼相當于:

defaults:
  adapter: postgres
  host: localhost

development:
  database: myapp_development
  adapter: postgres
  host: localhost

test:
  database: myapp_test
  adapter: postgres
  host: localhost

型別指定:

YAML雖然有型別自動決議,但是有時候我們寫了一個數字,但是我們想讓它是字串型別,就用到了型別指定,只要在值的前邊寫上相對應的型別標識就行了,常見的型別標識有以下幾個:

!!null ''                   # null
!!bool 'yes'                # bool
!!int '3...'                # number
!!float '3.14...'           # number
!!binary '...base64...'     # buffer
!!timestamp 'YYYY-...'      # date
!!omap [ ... ]              # array of key-value pairs
!!pairs [ ... ]             # array or array pairs
!!set { ... }               # array of objects with given keys and null values
!!str '...'                 # string
!!seq [ ... ]               # array
!!map { ... }               # object

3.3、YAML的決議

工程名稱:YAMLDemo

包的名稱:com.caochenlei.yaml.parse

依賴檔案:snakeyaml-1.17.jar、JUnit 4

測驗檔案:user.yaml(全路徑:/YAMLDemo/user.yaml)、users.yaml(全路徑:/YAMLDemo/users.yaml)

參考網站:https://bitbucket.org/asomov/snakeyaml/wiki/Home

User.java(全路徑:/YAMLDemo/src/com/caochenlei/yaml/parse/User.java)

package com.caochenlei.yaml.parse;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

public class User {
	private long id;
	private String name;
	private String phone;
	private List<String> hobby;
	private Map<String, BigDecimal> balance;
	private Address address;

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getPhone() {
		return phone;
	}

	public void setPhone(String phone) {
		this.phone = phone;
	}

	public List<String> getHobby() {
		return hobby;
	}

	public void setHobby(List<String> hobby) {
		this.hobby = hobby;
	}

	public Map<String, BigDecimal> getBalance() {
		return balance;
	}

	public void setBalance(Map<String, BigDecimal> balance) {
		this.balance = balance;
	}

	public Address getAddress() {
		return address;
	}

	public void setAddress(Address address) {
		this.address = address;
	}

	@Override
	public String toString() {
		return "User [id=" + id + ", name=" + name + ", phone=" + phone + ", hobby=" + hobby + ", balance=" + balance + ", address=" + address + "]";
	}
}

Address.java(全路徑:/YAMLDemo/src/com/caochenlei/yaml/parse/Address.java)

package com.caochenlei.yaml.parse;

public class Address {
	private String county;
	private String province;
	private String city;

	public String getCounty() {
		return county;
	}

	public void setCounty(String county) {
		this.county = county;
	}

	public String getProvince() {
		return province;
	}

	public void setProvince(String province) {
		this.province = province;
	}

	public String getCity() {
		return city;
	}

	public void setCity(String city) {
		this.city = city;
	}

	@Override
	public String toString() {
		return "Address [county=" + county + ", province=" + province + ", city=" + city + "]";
	}
}

YAMLDemo.java(全路徑:/YAMLDemo/src/com/caochenlei/yaml/parse/YAMLDemo.java)

package com.caochenlei.yaml.parse;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import org.junit.Test;
import org.yaml.snakeyaml.Yaml;

public class YAMLDemo {

	/**
	 * 讀取全部:讀取為字串
	 */
	@Test
	public void test1() {
		try {
			Yaml yaml = new Yaml();
			Object user = yaml.load(new FileInputStream(new File("user.yaml")));
			System.out.println(user);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 讀取全部:讀取為物件
	 */
	@Test
	public void test2() {
		try {
			Yaml yaml = new Yaml();
			User user = yaml.loadAs(new FileInputStream(new File("user.yaml")), User.class);
			System.out.println(user);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 讀取全部:讀取為Map集合
	 */
	@Test
	public void test3() {
		try {
			Yaml yaml = new Yaml();
			Map<String, Object> user = (Map<String, Object>) yaml.load(new FileInputStream(new File("user.yaml")));
			System.out.println(user.get("id"));
			System.out.println(user.get("name"));
			System.out.println(user.get("phone"));
			System.out.println(user.get("hobby"));
			System.out.println(user.get("balance"));
			System.out.println(user.get("address"));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 讀取全部:讀取多組配置
	 */
	@Test
	public void test4() {
		try {
			Yaml yaml = new Yaml();
			Iterable<Object> users = yaml.loadAll(new FileInputStream(new File("users.yaml")));
			for (Object user : users) {
				System.out.println(user);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 將一個物件持久化到檔案
	 */
	@Test
	public void test5() {
		try {
			Yaml yaml = new Yaml();
			User user = new User();
			user.setId(123456);
			user.setName("王五");
			user.setPhone("15633029014");
			user.setHobby(Arrays.asList("aaa", "bbb", "c"));
			HashMap<String, BigDecimal> balance = new HashMap<String, BigDecimal>();
			balance.put("wechat", new BigDecimal(19.99));
			balance.put("alipay", new BigDecimal(29.99));
			user.setBalance(balance);
			Address address = new Address();
			address.setCity("China");
			address.setProvince("HeBei");
			address.setCity("XingTai");
			user.setAddress(address);
			Writer output = new FileWriter("myuser.yaml");
			yaml.dump(user, output);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 將一個集合持久化到檔案
	 */
	@Test
	public void test6() {
		try {
			Yaml yaml = new Yaml();
			HashMap<String, Object> user = new HashMap<String, Object>();
			user.put("id", 123456);
			user.put("name", "王五");
			user.put("phone", "15633029014");
			user.put("hobby", Arrays.asList("aaa", "bbb", "c"));
			HashMap<String, BigDecimal> balance = new HashMap<String, BigDecimal>();
			balance.put("wechat", new BigDecimal(19.99));
			balance.put("alipay", new BigDecimal(29.99));
			user.put("balance", balance);
			Address address = new Address();
			address.setCity("China");
			address.setProvince("HeBei");
			address.setCity("XingTai");
			user.put("address", address);
			Writer output = new FileWriter("mymap.yaml");
			yaml.dump(user, output);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}

第四章 Servlet

4.1、Servlet概述

Java Servlet 是運行在 Web 服務器或應用服務器上的程式,它是作為來自 Web 瀏覽器或其他 HTTP 客戶端的請求和 HTTP 服務器上的資料庫或應用程式之間的中間層,使用 Servlet,您可以收集來自網頁表單的用戶輸入,呈現來自資料庫或者其他源的記錄,還可以動態創建網頁,

4.2、Servlet語法格式

第一步:創建包(com.caochenlei.servlet.demo)

第二步:創建類(com.caochenlei.servlet.demo.MyServlet),并且需要實作Servlet介面中的所有方法

package com.caochenlei.servlet.demo;

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

public class MyServlet implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("MyServlet init ...");
    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) 
            throws ServletException, IOException {
        System.out.println("MyServlet service ...");
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {
        System.out.println("MyServlet destroy ...");
    }
}

方法介紹:

  • init:Servlet初始化時呼叫的方法
  • getServletConfig:獲取當前Servlet的配置資訊
  • service:呼叫Servlet真正去處理邏輯的方法
  • getServletInfo:它提供有關Servlet的資訊,如作者、版本、著作權
  • destroy:Servlet銷毀時呼叫的方法

第三步:配置映射(web.xml中新增以下代碼)

    <servlet>
        <servlet-name>MyServlet</servlet-name>
        <servlet-class>com.caochenlei.servlet.demo.MyServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>MyServlet</servlet-name>
        <url-pattern>/MyServlet</url-pattern>
    </servlet-mapping>

配置介紹:

servlet標簽用于配置Servlet的基本資訊

  1. servlet-class:代表當前Servlet的具體類路徑,注意最后不包含.java
  2. servlet-name:代表當前Servlet的別名,可以和原Servlet名稱一樣,也可以不一樣,一般我們就一樣就行了

servlet-mapping標簽用于配置請求路徑與具體處理Servlet的對應關系

  1. url-pattern:這里寫你要匹配的地址路徑
  2. servlet-name:如果匹配到請求,該交給哪一個Servlet處理,這里的servlet-name其實就是一個Servlet的別名

第四步:啟動應用,然后瀏覽器輸入地址訪問(http://localhost:8080/myJavaWebDemo_war_exploded/MyServlet)

image-20200908213033310

第五步:正常關閉Tomcat服務器,我們會看到呼叫銷毀方法,如下圖所示:

image-20200908214658164

4.3、Servlet執行程序

image-20200908221223043

4.4、Servlet生命周期

Servlet運行在Servlet容器中,其生命周期由容器來管理,

Servlet的生命周期通過javax.servlet.Servlet介面中的init()、service()和destroy()方法來表示,

Servlet的生命周期包含了下面4個階段:

  1. 類加載和實體化
  2. 初始化:init()
  3. 請求處理:service()
  4. 銷毀:destroy()

4.5、Servlet繼承體系

其實我們不難發現,現有的Servlet它的方法比較多,而且大多需要我們自己來實作,那有沒有一種它的實作子類,把大部分方法都是實作了,而我們只要關注請求處理就行了,那答案肯定是有的,這個類就是HttpServlet,我們只要繼承這個類重寫GET、POST方法就能實作一個簡單的Servlet請求處理,Servlet的繼承體系如下圖:

image-20200909134206810

既然我們知道HttpServlet這個類了,我們就要使用一下:

第一步:創建類(com.caochenlei.servlet.demo.MyHttpServlet),并且需要繼承HttpServlet實作doPost、doGet方法,

package com.caochenlei.servlet.demo;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MyHttpServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        System.out.println("doPost method invoke ...");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        System.out.println("doGet method invoke ...");
    }
}

第二步:配置映射(在web.xml檔案中新增以下代碼)

    <servlet>
        <servlet-name>MyHttpServlet</servlet-name>
        <servlet-class>com.caochenlei.servlet.demo.MyHttpServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>MyHttpServlet</servlet-name>
        <url-pattern>/MyHttpServlet</url-pattern>
    </servlet-mapping>

第三步:重啟應用,然后瀏覽器訪問(http://localhost:8080/myJavaWebDemo_war_exploded/MyHttpServlet),觀察控制臺

注意:doPost需要提交表單模擬,這里就不演示了,效果都一樣!

image-20200909132323346

我們注意url-pattern它可以有多種攔截形式:

  • 全路徑匹配:/a
  • 前半段匹配:/a/b/c/*
  • 擴展名匹配:*.action

4.6、ServletContext

每個web工程都只有一個ServletContext物件,也就是不管在哪個Servlet里面,獲取到的這個類的物件都是同一個,它用來獲取Servlet的背景關系,在服務器啟動的時候,會為托管的每一個web應用程式,創建一個ServletContext物件,當從服務器移除托管或者是關閉服務器時,ServletContext將會被銷毀,它主要有以下幾方面作用:

  1. 獲取全域配置引數
  2. 獲取web工程中的資源
  3. 在servlet間共享資料域物件

4.6.1、獲取全域配置引數

第一步:在web.xml中新增以下代碼

    <context-param>
        <param-name>username</param-name>
        <param-value>zhangsan</param-value>
    </context-param>
    <context-param>
        <param-name>password</param-name>
        <param-value>123456</param-value>
    </context-param>

第二步:在MyHttpServlet的doGet方法中新增以下代碼

protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    System.out.println("doGet method invoke ...");

    // 獲取全部初始化名稱和其對應的內容
    Enumeration<String> initParameterNames = getServletContext().getInitParameterNames();
    while(initParameterNames.hasMoreElements()){
        String initParameterName = initParameterNames.nextElement();
        String initParameterValue = getServletContext().getInitParameter(initParameterName);
        System.out.println(initParameterName+":"+initParameterValue);
    }
}

第三步:重啟Tomcat服務器,在瀏覽器中訪問(http://localhost:8080/myJavaWebDemo_war_exploded/MyHttpServlet)

image-20200909140420185

4.6.2、獲取web工程中的資源

第一步:在 myJavaWebDemo 的 web 檔案夾中右鍵創建 a.txt 檔案,內容為 Hello,World!

img

第二步:在MyHttpServlet的doGet方法中新增以下代碼

protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    System.out.println("doGet method invoke ...");

    // 獲取全部初始化名稱和其對應的內容
    Enumeration<String> initParameterNames = getServletContext().getInitParameterNames();
    while (initParameterNames.hasMoreElements()) {
        String initParameterName = initParameterNames.nextElement();
        String initParameterValue = getServletContext().getInitParameter(initParameterName);
        System.out.println(initParameterName + ":" + initParameterValue);
    }

    // 獲取web工程中的資源的絕對路徑
    String realPath = getServletContext().getRealPath("a.txt");
    System.out.println(realPath);

    // 獲取web工程中的資源的輸入流物件
    InputStream resourceAsStream = getServletContext().getResourceAsStream("a.txt");
    System.out.println(resourceAsStream);
}

第三步:重啟Tomcat服務器,在瀏覽器中訪問(http://localhost:8080/myJavaWebDemo_war_exploded/MyHttpServlet)

注意:當你能拿到一個檔案的絕對路徑或者輸入流以后,就可以對它進行操作了!

image-20200909142517924

4.6.3、在Servlet間共享資料域物件

第一步:創建 LoginServlet 并配置請求映射

LoginServlet

package com.caochenlei.servlet.demo;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class LoginServlet 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 {

    }
}

web.xml

    <servlet>
        <servlet-name>LoginServlet</servlet-name>
        <servlet-class>com.caochenlei.servlet.demo.LoginServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>LoginServlet</servlet-name>
        <url-pattern>/LoginServlet</url-pattern>
    </servlet-mapping>

第二步:在 LoginServlet的 doGet 中實作登錄次數的修改,默認為1

protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    // 獲取當前登錄次數
    Integer count = (Integer) getServletContext().getAttribute("count");
    // 如果當前登錄為null,則設定默認值為1
    if (count == null) {
        getServletContext().setAttribute("count", 1);
    } else {
        getServletContext().setAttribute("count", count + 1);
    }
}

第三步:在 MyHttpServlet 的 doGet 中新增以下查看代碼,用于查看當前登錄次數

protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    System.out.println("doGet method invoke ...");

    // 獲取全部初始化名稱和其對應的內容
    Enumeration<String> initParameterNames = getServletContext().getInitParameterNames();
    while (initParameterNames.hasMoreElements()) {
        String initParameterName = initParameterNames.nextElement();
        String initParameterValue = getServletContext().getInitParameter(initParameterName);
        System.out.println(initParameterName + ":" + initParameterValue);
    }

    // 獲取web工程中的資源的絕對路徑
    String realPath = getServletContext().getRealPath("a.txt");
    System.out.println(realPath);

    // 獲取web工程中的資源的輸入流物件
    InputStream resourceAsStream = getServletContext().getResourceAsStream("a.txt");
    System.out.println(resourceAsStream);

    // 查看當前網站登錄次數,這個資料是保存在ServletContext中的
    Integer count = (Integer) getServletContext().getAttribute("count");
    // 判斷是否登錄過,如果沒有登錄過,提示未登錄,如果已經登錄過,顯示登錄次數
    if (count == null) {
        response.getWriter().write("no login!");
    } else {
        response.getWriter().write("count:" + count);
    }
}

第四步:重啟Tomcat服務器

在瀏覽器中訪問(http://localhost:8080/myJavaWebDemo_war_exploded/MyHttpServlet),查看是否登錄

image-20200909145158131

在瀏覽器中訪問(http://localhost:8080/myJavaWebDemo_war_exploded/LoginServlet),模擬登錄場景

image-20200909145250386

在瀏覽器中訪問(http://localhost:8080/myJavaWebDemo_war_exploded/MyHttpServlet),查看登錄次數

image-20200909150340563

4.7、ServletConfig

通過ServletConfig物件可以獲取servlet在配置的時候一些資訊,

第一步:創建類(HelloServlet)

package com.caochenlei.servlet.demo;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class HelloServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

    }

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

    }
}

第二步:在web.xml中配置映射關系

<servlet>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>com.caochenlei.servlet.demo.HelloServlet</servlet-class>
        <!-- Servlet的初始化引數 -->
        <init-param>
            <param-name>driver</param-name>
            <param-value>com.mysql.jdbc.Driver</param-value>
        </init-param>
        <init-param>
            <param-name>url</param-name>
            <param-value>jdbc:mysql://localhost:3306/test</param-value>
        </init-param>
        <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的加載順序 -->
        <load-on-startup>2</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/HelloServlet</url-pattern>
    </servlet-mapping>

第三步:在HelloServlet的doGet方法中新增以下代碼

protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    Enumeration<String> initParameterNames = getServletConfig().getInitParameterNames();
    while (initParameterNames.hasMoreElements()) {
        String initParameterName = initParameterNames.nextElement();
        String initParameterValue = getServletConfig().getInitParameter(initParameterName);
        System.out.println(initParameterName + ":" + initParameterValue);
    }
}

第四步:重啟Tomcat服務器,在瀏覽器中訪問(http://localhost:8080/myJavaWebDemo_war_exploded/HelloServlet)

image-20200909154053106

4.8、HttpServletRequest

HttpServletRequest這個物件封裝了客戶端提交過來的一切資料,

第一步:修改 index.jsp

<form action="RegisterServlet" method="get">
    賬戶:<input type="text" name="username"><br>
    密碼:<input type="text" name="password"><br>
         <input type="submit" value="注冊">
</form>

第二步:創建類(RegisterServlet)

package com.caochenlei.servlet.demo;

import javafx.print.Collation;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;

public class RegisterServlet 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 {
        // 獲取客戶端傳遞過來的頭部資訊
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            String headerValue = request.getHeader(headerName);
            System.out.println(headerName + ":" + headerValue);
        }
        System.out.println("====================");

        // 獲取客戶端傳遞過來的引數資訊
        Enumeration<String> parameterNames = request.getParameterNames();
        while (parameterNames.hasMoreElements()) {
            String parameterName = parameterNames.nextElement();
            String parameterValue = request.getParameter(parameterName);
            // 如果值有多個請使用:request.getParameterValues(parameterName)
            System.out.println(parameterName + ":" + parameterValue);
        }
        System.out.println("====================");

        // 以Map集合的形式獲取客戶端傳遞過來的引數資訊
        Map<String, String[]> parameterMap = request.getParameterMap();
        Set<String> names = parameterMap.keySet();
        for (String name : names) {
            String[] value = parameterMap.get(name);
            System.out.println(name + ":" + Arrays.toString(value));
        }
        System.out.println("====================");

        // 獲取一些其它地址、查詢等資訊
        StringBuffer requestURL = request.getRequestURL();
        String requestURI = request.getRequestURI();
        String servletPath = request.getServletPath();
        String queryString = request.getQueryString();
        System.out.println("requestURL:" + requestURL);
        System.out.println("requestURI:" + requestURI);
        System.out.println("servletPath:" + servletPath);
        System.out.println("queryString:" + queryString);
    }
}

第三步:在web.xml中新增映射資訊

    <servlet>
        <servlet-name>RegisterServlet</servlet-name>
        <servlet-class>com.caochenlei.servlet.demo.RegisterServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>RegisterServlet</servlet-name>
        <url-pattern>/RegisterServlet</url-pattern>
    </servlet-mapping>

第四步:重啟Tomcat服務器,在瀏覽器中訪問(http://localhost:8080/myJavaWebDemo_war_exploded/)

在表單輸入資料,然后點擊提交

image-20200909174127111

查看IDEA的控制臺資訊

host:localhost:8080
connection:keep-alive
upgrade-insecure-requests:1
user-agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36
accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
sec-fetch-site:same-origin
sec-fetch-mode:navigate
sec-fetch-user:?1
sec-fetch-dest:document
referer:http://localhost:8080/myJavaWebDemo_war_exploded/
accept-encoding:gzip, deflate, br
accept-language:zh-CN,zh;q=0.9
cookie:JSESSIONID=4342FA7CB5F51C5E4A5251E485E36E38
====================
username:zhangsan
password:123456
====================
username:[zhangsan]
password:[123456]
====================
requestURL:http://localhost:8080/myJavaWebDemo_war_exploded/RegisterServlet
requestURI:/myJavaWebDemo_war_exploded/RegisterServlet
servletPath:/RegisterServlet
queryString:username=zhangsan&password=123456

如何解決請求資料中文亂碼問題?

  • GET方式

    • // 先用原來的編碼解碼再用UTF—8重新編碼,
      String newUsername = new String(username.getBytes("ISO-8859-1"), "UTF-8");
      
  • POST方式

    • // 這行設定一定要寫在getParameter之前,
      request.setCharacterEncoding("UTF-8");
      

4.9、HttpServletResponse

HttpServletResponse這個物件負責回傳資料給客戶端,

第一步:創建類(DisplayServlet)

package com.caochenlei.servlet.demo;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class DisplayServlet 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.getWriter().write("<h1>hello response 111 ...</h1>");

        // 以位元組流的方式寫資料
        // response.getOutputStream().write("hello response 222 ...".getBytes());
    }
}

第二步:在web.xml檔案中新增以下映射資訊

    <servlet>
        <servlet-name>DisplayServlet</servlet-name>
        <servlet-class>com.caochenlei.servlet.demo.DisplayServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>DisplayServlet</servlet-name>
        <url-pattern>/DisplayServlet</url-pattern>
    </servlet-mapping>

第三步:重啟Tomcat服務器,在瀏覽器中訪問(http://localhost:8080/myJavaWebDemo_war_exploded/DisplayServlet)

image-20200909175839568

如何解決回應資料中文亂碼問題?

  • 以字符流輸出:response.getWriter()

    • response.setCharacterEncoding("UTF-8");
      response.setHeader("Content-Type", "text/html; charset=UTF-8");
      response.getWriter().write("你好,世界!");
      
  • 以位元組流輸出:response.getOutputStream()

    • response.setHeader("Content-Type", "text/html;charset=UTF-8");
      response.getOutputStream().write("你好,世界!".getBytes("UTF-8"));
      

4.10、重定向和請求轉發

  • 重定向
	// 第一種:使用示例
	response.setStatus(302);
	response.setHeader("Location", "login_success.html");*/
		
	// 第二種:使用示例
	response.sendRedirect("login_success.html");

	1. 地址上顯示的是最后的那個資源的路徑地址,

	2. 請求次數最少有兩次,服務器在第一次請求后,會回傳302以及一個地址,瀏覽器在根據這個地址,執行第二次訪問,

	3. 可以跳轉到任意路徑,不是自己的工程也可以跳,

	4. 效率稍微低一點,執行兩次請求, 

	5. 后續的請求,沒法使用上一次的request存盤的資料,或者沒法使用上一次的request物件,因為這是兩次不同的請求,
  • 請求轉發
	// 使用示例:
	request.getRequestDispatcher("login_success.html").forward(request, response);

	1. 地址上顯示的是請求servlet的地址,回傳200ok,

	2. 請求次數只有一次,因為是服務器內部幫客戶端執行了后續的作業, 

	3. 只能跳轉自己專案的資源路徑,  

	4. 效率上稍微高一點,因為只執行一次請求, 

	5. 可以使用上一次的request物件,

4.11、Cookie

Cookie其實是一份小資料,它是服務器給客戶端并且存盤在客戶端上的一份小資料,

第一步:創建類(CookieServlet)

package com.caochenlei.servlet.demo;

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 CookieServlet 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 {
        // 獲取Cookie ============================================================
        Cookie[] cookies = request.getCookies();
        if (cookies.length == 1) {
            System.out.println("沒有其它Cookie存在,只有JSESSIONID這個Cookie存在!");

            // 創建Cookie ============================================================
            // 創建Cookie物件
            Cookie cookie = new Cookie("username", "zhangsan");
            // 添加Cookie描述
            cookie.setComment("用戶賬號Cookie");
            // 正值:表示在這個數字過后,cookie將會失效,
            // 負值:關閉瀏覽器,那么cookie就失效,默認值是 -1,
            // 注意:Cookie是沒有洗掉方法的,想讓要Cookie失效或清除,就只要讓當前值為0就可以了,
            cookie.setMaxAge(60 * 60 * 24 * 7);
            // 重新為當前的這個Cookie賦值
            cookie.setValue("lisi");
            // 只有訪問域名 localhost 才會帶上該Cookie
            cookie.setDomain("localhost");
            // 只有訪問請求 /myJavaWebDemo_war_exploded/CookieServlet 才會帶上該Cookie
            cookie.setPath("/myJavaWebDemo_war_exploded/CookieServlet");
            // 創建Cookie ============================================================

            // 使用回應物件給瀏覽器回應的時候帶上該Cookie
            response.addCookie(cookie);
        } else {
            for (Cookie cookie : cookies) {
                if ("username".equals(cookie.getName())) {
                    System.out.println(cookie.getName() + "====" + cookie.getValue());
                }
            }
        }
        // 獲取Cookie ============================================================
    }
}

第二步:在web.xml中新增映射資訊

    <servlet>
        <servlet-name>CookieServlet</servlet-name>
        <servlet-class>com.caochenlei.servlet.demo.CookieServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>CookieServlet</servlet-name>
        <url-pattern>/CookieServlet</url-pattern>
    </servlet-mapping>

第三步:重啟Tomcat服務器

在瀏覽器中訪問(http://localhost:8080/myJavaWebDemo_war_exploded/CookieServlet)

image-20200909220703130

在瀏覽器中訪問(http://localhost:8080/myJavaWebDemo_war_exploded/DisplayServlet)

image-20200909220826654

4.12、Session

由于Cookie會保存在客戶端上,所以有安全隱患問題,還有一個問題,Cookie的大小與個數有限制,為了解決這個問題,于是就有了Session,Session是基于Cookie的一種會話機制,Cookie是服務器回傳一小份資料給客戶端,并且存放在客戶端上,Session是資料存放在服務器端,

常見用法:

// 獲取Session物件
HttpSession session = request.getSession();

// 獲取SessionID
String id = session.getId();

//存值
session.setAttribute(name, value);

//取值
session.getAttribute(name);

//刪值
session.removeAttribute(name);

生命周期:

  • 創建:如果有在servlet里面呼叫了 request.getSession()
  • 銷毀:關閉服務器或者session會話時間過期,默認有效期: 30分鐘,

第五章 Listener

Listener是監聽器,監聽Servlet某一個事件的發生或者狀態的改變,它的內部其實就是介面回呼,

5.1、監聽三個作用域創建和銷毀

5.1.1、ServletContextListener

監聽物件:

ServletContextListener用于監聽ServletContext物件作用域創建和銷毀,利用它可以完成自己想要的初始化作業,

生命周期:

servletcontext創建:
	1、啟動服務器的時候

servletContext銷毀:
	1、關閉服務器
	2、從服務器移除專案

如何創建:

package com.caochenlei.servlet.demo;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class MyContextListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("contextInitialized ...");
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("contextDestroyed ...");
    }
}

如何配置:

    <listener>
        <listener-class>com.caochenlei.servlet.demo.MyContextListener</listener-class>
    </listener>

5.1.2、ServletRequestListener

監聽物件:

ServletRequestListener用于監聽ServletRequest物件作用域創建和銷毀,利用它可以判斷當前受否存在請求,

生命周期:

request創建:
	1、訪問服務器上的任意資源都會有請求出現,
        訪問 html		:會
        訪問 jsp		:會
        訪問 servlet	:會

request銷毀:
	1、服務器已經對這次請求作出了回應,

如何創建:

package com.caochenlei.servlet.demo;

import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;

public class MyRequestListener implements ServletRequestListener {
    @Override
    public void requestInitialized(ServletRequestEvent servletRequestEvent) {
        System.out.println("requestInitialized ...");
    }

    @Override
    public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
        System.out.println("requestDestroyed ...");
    }
}

如何配置:

    <listener>
        <listener-class>com.caochenlei.servlet.demo.MyRequestListener</listener-class>
    </listener>

5.1.3、HttpSessionListener

監聽物件:

HttpSessionListener用于監聽HttpSession物件作用域創建和銷毀,利用它可以統計在線人數,

生命周期:

session的創建:
    1、只要呼叫getSession()方法,
        html	:不會
        jsp		:會
        servlet	:會

session的銷毀:
    1、會話超時30分鐘,
    2、非正常關閉服務器,
    3、正常關閉服務器(序列化)

如何創建:

package com.caochenlei.servlet.demo;

import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

public class MySessionListener implements HttpSessionListener {
    @Override
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {
        System.out.println("sessionCreated ...");
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
        System.out.println("sessionDestroyed ...");
    }
}

如何配置:

    <listener>
        <listener-class>com.caochenlei.servlet.demo.MySessionListener</listener-class>
    </listener>

5.2、監聽三個作用域屬性狀態變更

5.2.1、ServletContextAttributeListener

主要作用:

監聽ServletContext存值狀態變更,

主要方法:

icon

如何創建:

package com.caochenlei.servlet.demo;

import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;

public class MyContextAttributeListener implements ServletContextAttributeListener {
    @Override
    public void attributeAdded(ServletContextAttributeEvent servletContextAttributeEvent) {
        System.out.println("attributeAdded ...");
    }

    @Override
    public void attributeRemoved(ServletContextAttributeEvent servletContextAttributeEvent) {
        System.out.println("attributeRemoved ...");
    }

    @Override
    public void attributeReplaced(ServletContextAttributeEvent servletContextAttributeEvent) {
        System.out.println("attributeReplaced ...");
    }
}

如何配置:

    <listener>
        <listener-class>com.caochenlei.servlet.demo.MyContextAttributeListener</listener-class>
    </listener>

5.2.2、ServletRequestAttributeListener

主要作用:

監聽ServletRequest存值狀態變更,

主要方法:

icon

如何創建:

package com.caochenlei.servlet.demo;

import javax.servlet.ServletRequestAttributeEvent;
import javax.servlet.ServletRequestAttributeListener;

public class MyRequestAttributeListener implements ServletRequestAttributeListener {
    @Override
    public void attributeAdded(ServletRequestAttributeEvent servletRequestAttributeEvent) {
        System.out.println("attributeAdded ...");
    }

    @Override
    public void attributeRemoved(ServletRequestAttributeEvent servletRequestAttributeEvent) {
        System.out.println("attributeRemoved ...");
    }

    @Override
    public void attributeReplaced(ServletRequestAttributeEvent servletRequestAttributeEvent) {
        System.out.println("attributeReplaced ...");
    }
}

如何配置:

    <listener>
        <listener-class>com.caochenlei.servlet.demo.MyRequestAttributeListener</listener-class>
    </listener>

5.2.3、HttpSessionAttributeListener

主要作用:

監聽HttpSession存值狀態變更,

主要方法:

icon

如何創建:

package com.caochenlei.servlet.demo;

import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;

public class MySessionAttributeListener implements HttpSessionAttributeListener {
    @Override
    public void attributeAdded(HttpSessionBindingEvent httpSessionBindingEvent) {
        System.out.println("attributeAdded ...");
    }

    @Override
    public void attributeRemoved(HttpSessionBindingEvent httpSessionBindingEvent) {
        System.out.println("attributeRemoved ...");
    }

    @Override
    public void attributeReplaced(HttpSessionBindingEvent httpSessionBindingEvent) {
        System.out.println("attributeReplaced ...");
    }
}

如何配置:

    <listener>
        <listener-class>com.caochenlei.servlet.demo.MySessionAttributeListener</listener-class>
    </listener>

5.3、監聽HttpSession存值狀態變更

5.3.1、HttpSessionBindingListener

主要作用:

監聽物件與session系結和解除系結的動作,

如何創建:

package com.caochenlei.servlet.demo;

import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;

public class MySessionBindingListener implements HttpSessionBindingListener {
    @Override
    public void valueBound(HttpSessionBindingEvent httpSessionBindingEvent) {
        System.out.println("valueBound ...");
    }

    @Override
    public void valueUnbound(HttpSessionBindingEvent httpSessionBindingEvent) {
        System.out.println("valueUnbound ...");
    }
}

如何配置:

這一類監聽器不用注冊,

5.3.2、HttpSessionActivationListener

主要作用:

用于監聽現在session的值是鈍化(序列化)還是活化(反序列化)的動作,

鈍化(序列化)  :把記憶體中的資料存盤到硬碟上,
活化(反序列化):把硬碟中的資料讀取到記憶體中,

如何鈍化:

1. 在tomcat的 conf/context.xml 里面配置
		對所有的運行在這個服務器的專案生效,

2. 在tomcat的 conf/Catalina/localhost/context.xml 里面配置
		對localhost生效,

3. 在自己的web工程專案中的 META-INF/context.xml 里面配置
		只對當前的工程生效,

具體配置資訊如下:
	maxIdleSwap 	: 1分鐘不用就鈍化,
	directory 		: 鈍化后的那個檔案存放的目錄位置,

	<Context>
		<Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1">
			<Store className="org.apache.catalina.session.FileStore" directory="D:/Passivate"/>
		</Manager>
	</Context>

如何創建:

package com.caochenlei.servlet.demo;

import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionEvent;

public class MySessionActivationListener implements HttpSessionActivationListener {
    @Override
    public void sessionWillPassivate(HttpSessionEvent httpSessionEvent) {
        System.out.println("sessionWillPassivate ...");
    }

    @Override
    public void sessionDidActivate(HttpSessionEvent httpSessionEvent) {
        System.out.println("sessionDidActivate ...");
    }
}

如何配置:

這一類監聽器不用注冊,

第六章 Filter

6.1、Filter概述

Filter是過濾器,就是對客戶端發出來的請求進行過濾,瀏覽器發出請求,然后服務器派servlet處理,在中間就可以過濾,其實過濾器起到的是攔截的作用,使用過濾器可以對一些敏感詞匯進行過濾、統一設定編碼、實作自動登錄等功能,

6.2、Filter生命周期

  • 創建:在服務器啟動的時候就創建,
  • 銷毀:在服務器停止的時候就銷毀,

6.3、Filter語法

如何定義:

package com.caochenlei.servlet.demo;

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

public class MyFilter implements Filter {
    public void init(FilterConfig config) throws ServletException {
        System.out.println("MyFilter init ...");
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
            throws ServletException, IOException {
        // 放行,讓請求到達下一個目標,
        chain.doFilter(req, resp);
    }

    public void destroy() {
        System.out.println("MyFilter destroy ...");
    }
}

如何配置:

    <filter>
        <filter-name>MyFilter</filter-name>
        <filter-class>com.caochenlei.servlet.demo.MyFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>MyFilter</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
    </filter-mapping>

6.4、Filter執行順序

  1. 客戶端發出請求,先經過過濾器,如果過濾器放行,那么才能到servlet,
  2. 如果有多個過濾器,那么他們會按照注冊的映射順序來排隊,只要有一個過濾器不放行,那么后面排隊的過濾器以及咱們的servlet都不會收到請求,如果全部放行了,那么回來的時候將會是反向執行,比如以下順序:
filter01 ...
filter02 ...
filter03 ...

filter03 ...
filter02 ...
filter01 ...

注意:init方法的引數 FilterConfig , 可以用于獲取Filter在注冊的名字以及初始化引數,其實這里的設計的初衷與ServletConfig是一樣的,

6.5、Filter匹配規則

  • 全路徑匹配:/a
  • 前半段匹配:/a/b/c/*
  • 擴展名匹配:*.action

6.6、Filter攔截型別

注意:針對 dispatcher 設定的選項,

  • REQUEST : 只要是請求過來都攔截,默認就是REQUEST,
  • FORWARD : 只要是轉發過來都攔截,
  • ERROR : 頁面出錯發生跳轉,
  • INCLUDE : 包含頁面的時候就攔截,

6.7、Filter統一編碼

package com.caochenlei.servlet.demo;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Map;

public class EncodingFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) 
            throws IOException, ServletException {
        // 1.強轉
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        // 2.放行
        chain.doFilter(new MyRequest(request), response);
    }

    @Override
    public void destroy() {
    }

}

// 增強了所有的獲取引數的方法request.getParameter("name");
// 增強了所有的獲取引數的方法request.getParameterValues("name");
// 增強了所有的獲取引數的方法request.getParameterMap();
class MyRequest extends HttpServletRequestWrapper {

    private HttpServletRequest request;
    private boolean flag = true;

    public MyRequest(HttpServletRequest request) {
        super(request);
        this.request = request;
    }

    @Override
    public String getParameter(String name) {
        if (name == null || name.trim().length() == 0) {
            return null;
        }
        String[] values = getParameterValues(name);
        if (values == null || values.length == 0) {
            return null;
        }
        return values[0];
    }

    @Override
    public String[] getParameterValues(String name) {
        if (name == null || name.trim().length() == 0) {
            return null;
        }
        Map<String, String[]> map = getParameterMap();
        if (map == null || map.size() == 0) {
            return null;
        }
        return map.get(name);
    }

    @Override
    public Map<String, String[]> getParameterMap() {
        String method = request.getMethod();
        if ("post".equalsIgnoreCase(method)) {
            try {
                request.setCharacterEncoding("utf-8");
                return request.getParameterMap();
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        } else if ("get".equalsIgnoreCase(method)) {
            Map<String, String[]> map = request.getParameterMap();
            if (flag) {
                for (String key : map.keySet()) {
                    String[] arr = map.get(key);
                    for (int i = 0; i < arr.length; i++) {
                        try {
                            arr[i] = new String(arr[i].getBytes("utf-8"), "utf-8");
                        } catch (UnsupportedEncodingException e) {
                            e.printStackTrace();
                        }
                    }
                }
                flag = false;
            }
            return map;
        }
        return super.getParameterMap();
    }

}
    <filter>
        <filter-name>EncodingFilter</filter-name>
        <filter-class>com.caochenlei.servlet.demo.EncodingFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>EncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

第七章 JSP

7.1、JSP概述

JSP(全稱Java Server Pages)是由 Sun Microsystems 公司倡導和許多公司參與共同創建的一種使軟體開發者可以回應客戶端請求,而動態生成 HTML、XML 或其他格式檔案的Web網頁的技術標準,從用戶角度看待,就是是一個網頁,從程式員角度看待,其實是一個Java類,它繼承了Servlet,所以可以直接說JSP就是一個Servlet,

那為什么會有JSP?

HTML多數情況下用來顯示一成不變的靜態內容,但是有時候我們需要在網頁上顯示一些動態資料,比如:查詢所有的學生資訊、根據姓名去查詢具體某個學生,這些動作都需要去查詢資料庫,然后在網頁上顯示,HTML是不支持寫Java代碼 ,JSP里面可以寫Java代碼,

7.2、JSP生命周期

JSP生命周期就是從創建到銷毀的整個程序,類似于Servlet生命周期,區別在于JSP生命周期還包括將JSP檔案編譯成Servlet,

以下是JSP生命周期中所走過的幾個階段:

  • 編譯階段:Servlet容器編譯Servlet源檔案生成Servlet類,
  • 初始化階段:加載與JSP對應的Servlet類,創建其實體并呼叫它的初始化方法,
  • 執行階段:呼叫與JSP對應的Servlet實體的服務方法,
  • 銷毀階段:呼叫與JSP對應的Servlet實體的銷毀方法銷毀Servlet實體,

7.3、JSP語法

7.3.1、JSP腳本程式

第一種格式:

格式:

<% Java代碼片段 %>

示例:

<% System.out.println("Hello"); %>

第二種格式:

格式:

<jsp:scriptlet>
   Java代碼片段
</jsp:scriptlet>

示例:

<jsp:scriptlet>
   System.out.println("Hello");
</jsp:scriptlet>

7.3.2、JSP變數宣告

第一種格式:

格式:

<%! 變數宣告 %>

示例:

<%! int a = 10; int b = 20; %>

第二種格式:

格式:

<jsp:declaration>
   變數宣告
</jsp:declaration>

示例:

<jsp:declaration>
   int c = 30;
   int d = 40;
</jsp:declaration>

7.3.3、JSP運算式

一個JSP運算式中包含的腳本語言運算式,先被轉化成String,然后插入到運算式出現的地方,

由于運算式的值會被轉化成String,所以您可以在一個文本行中使用運算式而不用去管它是否是HTML標簽,

運算式元素中可以包含任何符合Java語言規范的運算式,但是不能使用分號來結束運算式,

第一種格式:

格式:

<%= 運算式 %>

示例:

<%= a %>

第二種格式:

格式:

<jsp:expression>
   運算式
</jsp:expression>

示例:

<jsp:expression>
    a
</jsp:expression>

7.3.4、JSP注釋

不同情況下使用注釋的語法規則:

語法描述
<%-- 注釋 --%>JSP注釋,注釋內容不會被發送至瀏覽器甚至不會被編譯
HTML注釋,通過瀏覽器查看網頁源代碼時可以看見注釋內容
<\%代表靜態 <% 常量
%\>代表靜態 %> 常量
\’在屬性中使用的單引號
\"在屬性中使用的雙引號

7.3.5、JSP指令元素

JSP指令用來設定整個JSP頁面相關的屬性,如網頁的編碼方式和腳本語言,

語法格式:

<%@ 指令 屬性="值" %>

三種指令:

指令描述
<%@ page … %>定義網頁依賴屬性,比如腳本語言、error頁面、快取需求等等
<%@ include … %>包含其他檔案
<%@ taglib … %>引入標簽庫的定義

7.3.5.1、page指令

page指令為容器提供當前頁面的使用說明,一個JSP頁面可以包含多個page指令,

第一種格式:

<%@ page 屬性="值" %>

第二種格式:

<jsp:directive.page 屬性="值" />

屬性串列:

屬性描述
buffer指定out物件使用緩沖區的大小
autoFlush控制out物件的快取區
contentType指定當前JSP頁面的MIME型別和字符編碼
errorPage指定當JSP頁面發生例外時需要轉向的錯誤處理頁面
isErrorPage指定當前頁面是否可以作為另一個JSP頁面的錯誤處理頁面
extends指定servlet從哪一個類繼承
import匯入要使用的Java類
info定義JSP頁面的描述資訊
isThreadSafe指定對JSP頁面的訪問是否為執行緒安全
language定義JSP頁面所用的腳本語言,默認是Java
session指定JSP頁面是否使用session
isELIgnored指定是否執行EL運算式
isScriptingEnabled確定腳本元素能否被使用

7.3.5.2、include指令

JSP可以通過include指令來包含其他檔案,被包含的檔案可以是JSP檔案、HTML檔案或文本檔案,包含的檔案就好像是該JSP檔案的一部分,會被同時編譯執行,

第一種格式:

<%@ include file="檔案相對url地址" %>

第二種格式:

<jsp:directive.include file="檔案相對url地址" />

7.3.5.3、taglib指令

JSP允許用戶自定義標簽,一個自定義標簽庫就是自定義標簽的集合,taglib指令引入一個自定義標簽集合的定義,包括庫路徑、自定義標簽,

第一種格式:

<%@ taglib uri="uri" prefix="標簽前綴" %>

第二種格式:

<jsp:directive.taglib uri="uri" prefix="標簽前綴" />

7.3.6、JSP動作元素

與JSP指令元素不同的是,JSP動作元素在請求處理階段起作用,利用JSP動作可以動態地插入檔案、重用JavaBean組件、把用戶重定向到另外的頁面、為Java插件生成HTML代碼,

語法格式:

<jsp:動作名稱 屬性="值" />

常見動作:

語法描述
jsp:include在頁面被請求的時候引入一個檔案,
jsp:useBean尋找或者實體化一個JavaBean,
jsp:setProperty設定JavaBean的屬性,
jsp:getProperty輸出某個JavaBean的屬性,
jsp:forward把請求轉到一個新的頁面,

常見屬性:

語法描述
idid屬性是動作元素的唯一標識,可以在JSP頁面中參考,
動作元素創建的id值可以通過PageContext來呼叫,
scope該屬性用于識別動作元素的生命周期,
id屬性和scope屬性有直接關系,scope屬性定義了相關聯id物件的壽命,
scope屬性有四個可能的值:page、request、session和application,

7.3.6.1、jsp:include動作

jsp:include動作元素用來包含靜態和動態的檔案,該動作把指定檔案插入正在生成的頁面,

語法格式:

注意:前面已經介紹過include指令,它是在JSP檔案被轉換成Servlet的時候引入檔案,而這里的jsp:include動作不同,插入檔案的時間是在頁面被請求的時候,

<jsp:include page="相對URL地址" flush="true" />

屬性串列:

屬性描述
page包含在頁面中的相對URL地址,
flush布爾屬性,定義在包含資源前是否重繪快取區,

相關示例:

<jsp:include page="myInfo.html" flush="true" />

7.3.6.2、jsp:useBean動作

jsp:useBean動作用來加載一個將在JSP頁面中使用的JavaBean,這個功能非常有用,因為它使得我們可以發揮Java組件復用的優勢,

語法格式:

<jsp:useBean id="ID名稱" class="具體的類" />

屬性串列:

屬性描述
class指定Bean的完整包名,
type指定將參考該物件變數的型別,
beanName通過 java.beans.Beans 的 instantiate() 方法指定Bean的名字,

相關示例:

<jsp:useBean id="user" class="com.caochenlei.servlet.demo.User" />

7.3.6.3、jsp:setProperty動作

jsp:setProperty動作用來設定已經實體化的Bean物件的屬性,

語法格式:

注意:jsp:setProperty只有在新建Bean實體時才會執行,如果是使用現有實體則不執行jsp:setProperty,

第一種格式:

<jsp:useBean id="myName" class="..." />
<jsp:setProperty name="myName" property="屬性名" value="值"/>

第二種格式:

<jsp:useBean id="myName" class="...">
   <jsp:setProperty name="myName" property="屬性名" value="值"/>
</jsp:useBean>

屬性串列:

屬性描述
namename屬性是必需的,它表示要設定屬性的是哪個Bean,
propertyproperty屬性是必需的,它表示要設定哪個屬性,有一個特殊用法:如果property的值是"*",表示所有名字和Bean屬性名字匹配的請求引數都將被傳遞給相應的屬性set方法,
valuevalue 屬性是可選的,該屬性用來指定Bean屬性的值,字串資料會在目標類中通過標準的valueOf方法自動轉換成數字、boolean、Boolean、 byte、Byte、char、Character,例如,boolean和Boolean型別的屬性值(比如"true")通過 Boolean.valueOf 轉換,int和Integer型別的屬性值(比如"42")通過Integer.valueOf轉換,value和param不能同時使用,但可以使用其中任意一個,
paramparam 是可選的,它指定用哪個請求引數作為Bean屬性的值,如果當前請求沒有引數,則什么事情也不做,系統不會把null傳遞給Bean屬性的set方法,因此,你可以讓Bean自己提供默認屬性值,只有當請求引數明確指定了新值時才修改默認屬性值,

相關示例:

第一種格式:

<jsp:useBean id="user1" class="com.caochenlei.servlet.demo.User" />
<jsp:setProperty name="user1" property="username" value="zhangsan"/>

第二種格式:

<jsp:useBean id="user2" class="com.caochenlei.servlet.demo.User">
    <jsp:setProperty name="user2" property="username" value="lisi"/>
</jsp:useBean>

7.3.6.4、jsp:getProperty動作

jsp:getProperty動作提取指定Bean屬性的值,轉換成字串,然后輸出,

語法格式:

<jsp:getProperty name="myName" property="屬性值" />

屬性串列:

屬性描述
name要檢索的Bean屬性名稱,Bean必須已定義,
property表示要提取Bean屬性的值,

相關示例:

<jsp:getProperty name="user2" property="username" />

7.3.6.5、jsp:forward動作

jsp:forward動作把請求轉到另外的頁面,

語法格式:

<jsp:forward page="相對URL地址" />

屬性串列:

屬性描述
pagepage屬性包含的是一個相對URL,
page的值既可以直接給出,也可以在請求的時候動態計算,可以是一個JSP頁面或者一個 Java Servlet,

相關示例:

<jsp:forward page="myJSP.jsp" />

7.3.7、JSP隱含物件

JSP隱式物件是JSP容器為每個頁面提供的Java物件,開發者可以直接使用它們而不用顯式宣告,JSP隱式物件也被稱為預定義變數,

JSP所支持的九大隱式物件:

物件描述
requestHttpServletRequest 介面的實體
responseHttpServletResponse 介面的實體
sessionHttpSession 類的實體
applicationServletContext 類的實體,與應用背景關系有關
configServletConfig 類的實體
outJspWriter 類的實體,用于把結果輸出至網頁上
pageContextPageContext 類的實體,提供對JSP頁面所有物件以及命名空間的訪問
page類似于Java類中的 this 關鍵字
ExceptionException 類的物件,代表發生錯誤的JSP頁面中對應的例外物件

JSP所支持的四大作用域:

  • pageContext 【PageContext】

作用域僅限于當前的頁面,還可以獲取到其他八個內置物件,

  • request 【HttpServletRequest】

作用域僅限于一次請求, 只要服務器對該請求做出了回應,這個域中存的值就沒有了,

  • session 【HttpSession】

作用域限于一次會話(多次請求與回應) 當中,

  • application 【ServletContext】

整個工程都可以訪問,服務器關閉后就不能訪問了

7.3.8、JSP常見控制

if陳述句:

<%! int age = 19; %>
<% if ( age > 18 ) { %>
    <p>已成年</p><br />
<% } else { %>
    <p>未成年</p><br />
<% } %>

for陳述句:

<%--for陳述句--%>
<%! int fontSize1 = 1; %>
<% for (fontSize1 = 1; fontSize1 <= 3; fontSize1++){ %>
    <font color="green" size="<%= fontSize1 %>">fontSize1</font><br />
<% } %>

7.4、EL運算式

7.4.1、EL概述

EL是為了簡化咱們的jsp代碼,具體一點就是為了簡化在jsp里面寫的那些java代碼,

7.4.2、EL語法

注意:如果從作用域中取值,會先從小的作用域開始取,如果沒有,就往下一個作用域取,一直把四個作用域取完都沒有,就沒有顯示,

${ 運算式 }

7.4.3、EL隱含物件

EL運算式的11個內置物件:

隱含物件描述
pageScopepage 作用域
requestScoperequest 作用域
sessionScopesession 作用域
applicationScopeapplication 作用域
paramRequest 物件的引數,字串
paramValuesRequest 物件的引數,字串集合
headerHTTP 資訊頭,字串
headerValuesHTTP 資訊頭,字串集合
initParam背景關系初始化引數
cookieCookie值
pageContext當前頁面的pageContext

注意:您可以在運算式中使用這些物件,就像使用變數一樣,

7.4.4、EL案例演示

如果域中所存的是物件:

<%
    User u = new User();
    u.setUsername("zhangsan");
    u.setPassword("123456");

    pageContext.setAttribute("u", u);
    request.setAttribute("u", u);
    session.setAttribute("u", u);
    application.setAttribute("u", u);
%>

<br>使用普通手段取出作用域中的值<br>

<%= ((User) pageContext.getAttribute("u")).getUsername() %>
<%= ((User) request.getAttribute("u")).getUsername() %>
<%= ((User) session.getAttribute("u")).getUsername() %>
<%= ((User) application.getAttribute("u")).getUsername() %>

<br>使用EL運算式取出作用域中的值<br>

<p>${ pageScope.u.username }</p>
<p>${ requestScope.u.username }</p>
<p>${ sessionScope.u.username }</p>
<p>${ applicationScope.u.username }</p>

如果域中所存的是鍵值:

<%
    pageContext.setAttribute("name", "page");
    request.setAttribute("name", "request");
    session.setAttribute("name", "session");
    application.setAttribute("name", "application");
%>

<br>使用普通手段取出作用域中的值<br>

<%= pageContext.getAttribute("name") %>
<%= request.getAttribute("name") %>
<%= session.getAttribute("name") %>
<%= application.getAttribute("name") %>

<br>使用EL運算式取出作用域中的值<br>

${ pageScope.name }
${ requestScope.name }
${ sessionScope.name }
${ applicationScope.name }	

如果域中所存的是陣列:

<%
    String[] array = {"aa","bb","cc","dd"};

    pageContext.setAttribute("array", array);
    request.setAttribute("array", array);
    session.setAttribute("array", array);
    application.setAttribute("array", array);
%>

<br>使用普通手段取出作用域中的值<br>

<p><%= ((String[]) pageContext.getAttribute("array"))[0] %></p>
<p><%= ((String[]) request.getAttribute("array"))[0] %></p>
<p><%= ((String[]) session.getAttribute("array"))[0] %></p>
<p><%= ((String[]) application.getAttribute("array"))[0] %></p>

<br>使用EL運算式取出作用域中的值<br>

<p>${ pageScope.array[0] }</p>
<p>${ requestScope.array[0] }</p>
<p>${ sessionScope.array[0] }</p>
<p>${ applicationScope.array[0] }</p>

如果域中鎖存的是集合:

<%
    Map map = new HashMap();
    map.put("name", "zhangsan");
    map.put("age",18);

    pageContext.setAttribute("map", map);
    request.setAttribute("map", map);
    session.setAttribute("map", map);
    application.setAttribute("map", map);
%>

<br>使用普通手段取出作用域中的值<br>

<p><%= ((Map) pageContext.getAttribute("map")).get("name") %></p>
<p><%= ((Map) request.getAttribute("map")).get("name") %></p>
<p><%= ((Map) session.getAttribute("map")).get("name") %></p>
<p><%= ((Map) application.getAttribute("map")).get("name") %></p>

<br>使用EL運算式取出作用域中的值<br>

<p>${ pageScope.map.name }</p>
<p>${ requestScope.map.name }</p>
<p>${ sessionScope.map['name'] }</p>
<p>${ applicationScope.map['name'] }</p>

7.5、JSTL運算式

7.5.1、JSTL概述

JSTL(JSP Standard Tag Library,標準標簽庫)主要也是為了簡化jsp的代碼撰寫,替換 <%%> 寫法,一般與EL運算式配合使用,

7.5.2、JSTL依賴

  1. 匯入依賴庫:jstl.jar、standard.jar
  2. 引入標簽庫:<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

7.5.3、JSTL常用標簽

  • c:set
<!-- 宣告一個物件 myname,物件的值 zhangsan,存盤到了 page(默認),指定是 session 域 -->
<c:set var="myname" value="zhangsan" scope="session"></c:set>
${ sessionScope.myname }
  • c:if
<c:set var="age" value="18" ></c:set>
<c:if test="${ age > 26 }">
    年齡大于了26歲...
</c:if>
<c:if test="${ age <= 26 }">
    年齡小于了26歲...
</c:if>

<%--定義一個變數名 flag,去接收前面運算式的值,然后存在 session 域中--%>
<c:if test="${ age > 26 }" var="flag" scope="session">
    年齡大于了26歲...
</c:if>
  • c:forEach
<%--從1開始遍歷到10,得到的結果,賦值給 i,并且會存盤到page域中,step代表增幅為2--%>
<c:forEach begin="1" end="10" var="i" step="2">
    ${i}
</c:forEach>

<%
    List<User> list = new ArrayList<User>();

    User u1 = new User();
    u1.setUsername("zhangsan");
    u1.setPassword("123456");
    list.add(u1);

    User u2 = new User();
    u2.setUsername("lisi");
    u2.setPassword("123456");
    list.add(u2);

    request.setAttribute("list",list);
%>
<!--items:表示遍歷哪一個物件,注意這里必須寫EL運算式,
	var:遍歷出來的每一個元素用user去接收, -->
<c:forEach var="user" items="${ list }">
    ${ user.username } ---- ${ user.password } <br />
</c:forEach>

第八章 Servlet3.0

Servlet 3.0 作為 Java EE 6 規范體系中一員,隨著 Java EE 6 規范一起發布,該版本在前一版本(Servlet 2.5)的基礎上提供了若干新特性用于簡化 Web 應用的開發和部署,其中有幾項特性的引入讓開發者感到非常興奮,同時也獲得了 Java 社區的一片贊譽之聲:

  1. 新增的注解支持:該版本新增了若干注解,用于簡化 Servlet、過濾器(Filter)和監聽器(Listener)的宣告,這使得 web.xml 部署描述檔案從該版本開始不再是必選的了,
  2. 檔案上傳API簡化:從該版本開始,極大地簡化了檔案上傳的操作,
  3. 異步處理支持:有了該特性,Servlet 執行緒不再需要一直阻塞,直到業務處理完畢才能再輸出回應,最后才結束該 Servlet 執行緒,在接收到請求之后,Servlet 執行緒可以將耗時的操作委派給另一個執行緒來完成,自己在不生成回應的情況下回傳至容器,針對業務處理較耗時的情況,這將大大減少服務器資源的占用,并且提高并發處理速度,
  4. 動態注冊組件:在初始化ServletContext容器的時候,可以支持動態注冊三大組件,
  5. 可插性支持:如果說 3.0 版本新增的注解支持是為了簡化 Servlet/ 過濾器 / 監聽器的宣告,從而使得 web.xml 變為可選配置, 那么新增的可插性 (pluggability) 支持則將 Servlet 配置的靈活性提升到了新的高度,熟悉 Struts2 的開發者都知道,Struts2 通過插件的形式提供了對包括 Spring 在內的各種開發框架的支持,開發者甚至可以自己為 Struts2 開發插件,而 Servlet 的可插性支持正是基于這樣的理念而產生的,使用該特性,現在我們可以在不修改已有 Web 應用的前提下,只需將按照一定格式打成的 JAR 包放到 WEB-INF/lib 目錄下,即可實作新功能的擴充,不需要額外的配置,

8.1、注解開發

8.1.1、servlet注解

如何創建:

package com.caochenlei.servlet3.annotation;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(
        name = "AnnotationServlet",//代表servlet名稱
        value = {"/AnnotationServlet"},//代表servlet映射地址,可以寫多個,value與urlPatterns一樣,二者不能同時出現
        loadOnStartup = 2,//代表servlet初始化順序
        initParams = {@WebInitParam(name = "user",value = "zhangsan")},//代表servlet初始化引數,可以寫多個
        asyncSupported = false//代表servlet是否支持異步,默認為false
)
public class AnnotationServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        System.out.println("doPost ...");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        System.out.println("doGet ...");
    }
}

屬性串列:

屬性名型別描述
nameString指定 Servlet 的 name 屬性,如果沒有顯式指定,則該 Servlet 的取值即為類的全限定名
valueString[]該屬性等價于 urlPatterns 屬性,兩個屬性不能同時使用
urlPatternsString[]指定一組 Servlet 的 URL 匹配模式
loadOnStartupint指定 Servlet 的加載順序
initParamsWebInitParam[]指定一組 Servlet 初始化引數
asyncSupportedboolean宣告 Servlet 是否支持異步操作模式
descriptionString該 Servlet 的描述資訊
displayNameString該 Servlet 的顯示名,通常配合工具使用

如何測驗:

打開瀏覽器輸入:http://localhost:8080/servlet3_0_war_exploded/AnnotationServlet

檢測控制臺輸出:

image-20200912214143931

8.1.2、filter注解

如何創建:

package com.caochenlei.servlet3.annotation;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import java.io.IOException;

@WebFilter(
        filterName = "AnnotationFilter",//代表filter名稱
        value = {"/*"},//代表filter映射路徑,可以寫多個,value與urlPatterns一樣,二者不能同時出現
        dispatcherTypes = {DispatcherType.REQUEST},//代表filter攔截型別
        initParams = {@WebInitParam(name = "user", value = "zhansan")},//代表filter初始化引數,可以寫多個
        asyncSupported = false,//代表filter是否支持異步,默認為false
        servletNames = {"AnnotationServlet"}//代表filter指定攔截哪幾個servlet
)
public class AnnotationFilter implements Filter {
    public void init(FilterConfig config) throws ServletException {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
            throws ServletException, IOException {
        System.out.println("doFilter ...");
        chain.doFilter(req, resp);
    }

    public void destroy() {
    }
}

屬性串列:

屬性名型別描述
filterNameString指定過濾器的 name 屬性
valueString[]該屬性等價于 urlPatterns 屬性,但是兩者不應該同時使用
urlPatternsString[]指定一組過濾器的 URL 匹配模式
servletNamesString[]指定過濾器將應用于哪些 Servlet
dispatcherTypesDispatcherType指定過濾器的轉發模式
具體取值包括: ASYNC、ERROR、FORWARD、INCLUDE、REQUEST
initParamsWebInitParam[]指定一組過濾器初始化引數
asyncSupportedboolean宣告過濾器是否支持異步操作模式
descriptionString該過濾器的描述資訊
displayNameString該過濾器的顯示名,通常配合工具使用

如何測驗:

打開瀏覽器輸入:http://localhost:8080/servlet3_0_war_exploded/AnnotationServlet

檢測控制臺輸出:

image-20200912215136141

8.1.3、listener注解

如何創建:

package com.caochenlei.servlet3.annotation;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

@WebListener()
public class AnnotationListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("contextInitialized ...");
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("contextDestroyed ...");
    }
}

如何測驗:

重啟服務器,觀察控制臺:

image-20200912215910354

image-20200912215930667

8.1.4、兩種配置同時存在

  • 對于servlet來說:
    • 若兩種配置方式的url-pattern值相同,則應用無法啟動,
    • 若兩種配置方式的url-pattern值相同,那么相當該servlet具有兩個映射url-pattern,
  • 對于filter來說:
    • 無論兩種配置方式的url-pattern值是否相同,其都是作為獨立的filter出現的,
  • 對于listener來說:
    • 如果兩種配置方式都進行了同一個listener注冊,那么也只能算一個listener,

8.1.5、如何禁用注解組件

如果只想要使用web.xml中的配置而忽略注解注冊的組件,只需要在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" metadata-complete="false">
</web-app>

metadata-complete="false":表示web.xml配置和注解配置同時生效,默認是false,

metadata-complete="true":表示web.xml配置有效,而注解配置則被忽略,

8.2、檔案上傳

前臺頁面:

  <form action="uploadServlet" method="post" enctype="multipart/form-data">
    選擇檔案:<input type="file" name="myfile" /> <br />
    上傳檔案:<input type="submit" value="上傳" />
  </form>

上傳模塊:

package com.caochenlei.servlet3.annotation;

import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.IOException;

@WebServlet("/uploadServlet")
@MultipartConfig
public class UploadServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        Part part = request.getPart("myfile");
        part.write("D:/xxx.txt");
        response.setHeader("Content-Type", "text/html;charset=UTF-8");
        response.getWriter().println("檔案上傳成功!");

    }
}

@MultipartConfig注解:

屬性名型別是否可選描述
fileSizeThresholdint當資料量大于該值時,內容將被寫入檔案
locationString存放生成的檔案地址
maxFileSizelong允許上傳的檔案最大值,默認值為-1,表示沒有限制
maxRequestSizelong針對該multipart/form-data請求的最大數量,默認值為-1,表示沒有限制

如何測驗:

image-20200912222942202

image-20200912222913813

image-20200912223106718

8.3、異步處理

注意問題:

如果你的servlet開啟了異步支持,那么你的filter也必須開啟異步支持,否則會報錯!

經典場景:

在用戶注冊的時候,通常會發送一封注冊通知郵件,這里就是用到了異步處理的技術,

如何實作:

第一步:修改AnnotationFilter的asyncSupported 為 true

第二步:創建異步支持的注冊servlet

package com.caochenlei.servlet3.annotation;

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

@WebServlet(value = "/RegisterServlet",asyncSupported = true)
public class RegisterServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 獲取異步支持背景關系
        AsyncContext asyncContext = request.startAsync();
        // 啟動一個耗時子執行緒
        EmailSendThread est = new EmailSendThread(asyncContext);
        // 設定異步超時的時間
        asyncContext.setTimeout(3000);
        // 開啟異步背景關系物件
        asyncContext.start(est);

        // 模擬注冊成功的提示
        response.setHeader("Content-Type", "text/html;charset=UTF-8");
        response.getWriter().println("恭喜您注冊成功,請檢查您的郵箱進行激活!");
    }
}

第三步:創建發送郵件的子行程類

package com.caochenlei.servlet3.annotation;

import javax.servlet.AsyncContext;

public class EmailSendThread implements Runnable {
    private AsyncContext ac;

    public EmailSendThread(AsyncContext ac) {
        this.ac = ac;
    }

    public AsyncContext getAc() {
        return ac;
    }

    public void setAc(AsyncContext ac) {
        this.ac = ac;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("確認郵件已經發送,請及時查收!");
    }
}

如何測驗:

打開瀏覽器輸入:http://localhost:8080/servlet3_0_war_exploded/RegisterServlet

檢測控制臺輸出:

三秒后頁面輸出:

image-20200912225334502

十秒后控制臺輸出:

image-20200912225356682

8.4、動態注冊

動態注冊就是在tomcat啟動的時候,利用ServletContext進行組件動態注冊的技術,

修改AnnotationListener,以后三大組建的配置都是在contextInitialized方法中進行,

package com.caochenlei.servlet3.annotation;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletRegistration;
import javax.servlet.annotation.WebListener;

@WebListener()
public class AnnotationListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("contextInitialized ...");
        ServletContext servletContext = servletContextEvent.getServletContext();
        
        // 三大組件注冊代碼位置 ...
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("contextDestroyed ...");
    }
}

8.4.1、servlet動態注冊

創建一個普通的servlet:

package com.caochenlei.servlet3.annotation;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class NormalServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        System.out.println("NormalServlet doPost ...");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        System.out.println("NormalServlet doGet ...");
    }
}

利用ServletContextListener進行動態注冊:

// 動態注冊servlet
String servletName = "NormalServlet";
String servletClass = "com.caochenlei.servlet3.annotation.NormalServlet";
ServletRegistration.Dynamic srd = servletContext.addServlet(servletName, servletClass);
srd.addMapping("/NormalServlet");

如何測驗:

打開瀏覽器輸入:http://localhost:8080/servlet3_0_war_exploded/NormalServlet

檢測控制臺輸出:

image-20200912230733138

8.4.2、filter動態注冊

創建一個普通的filter:

package com.caochenlei.servlet3.annotation;

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

public class NormalFilter implements Filter {
    public void init(FilterConfig config) throws ServletException {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
            throws ServletException, IOException {
        chain.doFilter(req, resp);
        System.out.println("NormalFilter doFilter ...");
    }

    public void destroy() {
    }
}

利用ServletContextListener進行動態注冊:

注意:addMappingForServletNames的第二個引數為true代表,在以前的過濾之后過濾,為false,代表在以前的過濾之前過濾,

// 動態注冊filter
String filterName = "NormalFilter";
String filterClass = "com.caochenlei.servlet3.annotation.NormalFilter";
FilterRegistration.Dynamic frd = servletContext.addFilter(filterName, filterClass);
frd.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST),true,"/a");

如何測驗:

打開瀏覽器輸入:http://localhost:8080/servlet3_0_war_exploded/a

檢測控制臺輸出:

image-20200912231942921

8.4.3、listener動態注冊

創建一個普通的listener:

package com.caochenlei.servlet3.annotation;

import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;

public class NormalListener implements ServletRequestListener {
    @Override
    public void requestInitialized(ServletRequestEvent servletRequestEvent) {
        System.out.println("NormalListener requestInitialized ...");
    }

    @Override
    public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
        System.out.println("NormalListener requestDestroyed ...");
    }
}

利用ServletContextListener進行動態注冊:

// 動態注冊listener
servletContext.addListener("com.caochenlei.servlet3.annotation.NormalListener");

如何測驗:

打開瀏覽器輸入:http://localhost:8080/servlet3_0_war_exploded/index.jsp

檢測控制臺輸出:

image-20200912232247479

8.5、可插性支持

如何實作模塊化開發?

  • 撰寫一個類繼承自 HttpServlet,并且在該類上使用 @WebServlet 注解將該類宣告為 Servlet,將該類放在 classes 目錄下的對應包結構中,無需修改 web.xml 檔案,

  • 撰寫一個類繼承自 HttpServlet,將該類打成 JAR 包,并且在 JAR 包的 META-INF 目錄下放置一個 web-fragment.xml 檔案,該檔案中宣告了相應的 Servlet 配置,web-fragment.xml 檔案示例如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-fragment xmlns="http://java.sun.com/xml/ns/javaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0"
              xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
              http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd">

</web-fragment>

從上面的示例可以看出,web-fragment.xml 與 web.xml 除了在頭部宣告的 XSD 參考不同之外,其主體配置與 web.xml 是完全一致的,

由于一個 Web 應用中可以出現多個 web-fragment.xml 宣告檔案,加上一個 web.xml 檔案,加載順序問題便成了不得不面對的問題,Servlet 規范的專家組在設計的時候已經考慮到了這個問題,并定義了加載順序的規則,

web-fragment.xml 包含了兩個可選的頂層標簽, 如果希望為當前的檔案指定明確的加載順序,通常需要使用這兩個標簽, 主要用于標識當前的檔案,而 則用于指定先后順序,一個簡單的示例如下:

<web-fragment...>
    <name>FragmentA</name>
    <ordering>
        <after>
            <name>FragmentB</name>
            <name>FragmentC</name>
        </after>
        <before>
            <others/>
        </before>
    </ordering>
    ...
</web-fragment>

接下來我們使用一個完整示例來演示:

我們先看下我們目前已經做了哪些工程:

image-20200913075756862

創建一個JavaWeb片段工程,可以算是一個功能模塊,具體步驟如下圖:

image-20200913075848749

image-20200913075922078

image-20200913075959981

image-20200913080103129

image-20200913080129954

image-20200913080252409

image-20200913080336915

image-20200913080359392

image-20200913080434432

把以下代碼拷貝到組態檔中:

<?xml version="1.0" encoding="UTF-8"?>
<web-fragment xmlns="http://java.sun.com/xml/ns/javaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0"
              xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
              http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd">

</web-fragment>

image-20200913080542561

創建一個需要測驗的Servlet,這里我們直接采用注解開發

image-20200913080756126

image-20200913080829311

image-20200913080956887

接下來我們需要把當前這個工程編譯為一個jar包,以方便嵌入到別的工程中

image-20200913081106654

image-20200913081149935

image-20200913081217309

image-20200913081232746

image-20200913081325671

image-20200913081400378

編譯完成,就會出現這個jar包,把它拷貝到桌面,備用,然后關閉當前工程

image-20200913081529575

image-20200913081611871

打開之前的servlet3.0的專案,我們把剛才編譯好的jar包放到這個工程中,用來測驗是不是可行

image-20200913081710460

image-20200913081754969

image-20200913081947108

image-20200913082011629

image-20200913082152803

image-20200913082223988

image-20200913082245084

image-20200913082302433

把剛才復制到桌子上的fragment.jar復制到lib中

image-20200913082343006

啟動服務器,然后輸入FragmentServlet的映射網址,看看控制臺會不會輸出

image-20200913082602992

打開瀏覽器,輸入:http://localhost:8080/servlet3_0_war_exploded/FragmentServlet

image-20200913082700341

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

標籤:其他

上一篇:java集合中List,Set,Map的特點以及在作業中如何選型

下一篇:Spring系列第八講 自動注入(autowire)詳解,高手在于堅持!

標籤雲
其他(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)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more