配套資料,免費下載
連結:https://pan.baidu.com/s/1DNouClLLp4OB8mniUJGmBg
提取碼:dq2w
複製這段內容後開啟百度網路硬碟手機App,操作更方便哦
第一步:開啟官網進行下載(https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html)
第二步:執行程式進行安裝
全部預設下一步即可,不用管路徑是不是存在中文和空格,無礙!
注意:如果自己會設定JDK,可以更改它的安裝路徑,那相應的環境變數也需要修改!
第三步:系統環境變數設定
此電腦 》 右鍵 》 屬性 》 高階系統設定 》 環境變數 》 系統變數 》 新建(需要新建兩個,然後修改一個)
新建兩個:JAVA_HOME代表Java的安裝目錄、CLASSPATH代表程式執行的時候,優先載入當前目錄中的類,然後再載入指定的類庫
變數名 | 變數值 |
---|---|
JAVA_HOME | C:\Program Files\Java\jdk1.8.0_261 |
CLASSPATH | .;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar; |
修改一個:編輯PATH環境變數,它會開啟一個視窗,新添兩條路徑,如下圖所示
第四步:測試JDK是否安裝成功
開啟一個cmd命令列視窗,輸入以下兩個命令檢視,如果有內容輸出則證明已經設定成功!
第一步:開啟官網進行下載和安裝(http://tomcat.apache.org/)
第二步:系統環境變數設定
此電腦 》 右鍵 》 屬性 》 高階系統設定 》 環境變數 》 系統變數 》 新建(需要新建兩個,然後修改三個)
新建兩個:CATALINA_BASE和CATALINA_HOME均代表Tomcat的安裝目錄
變數名 | 變數值 |
---|---|
CATALINA_BASE | C:\DevTools\apache-tomcat-8.5.57 (輸入自己解壓的Tomcat目錄,不要照抄我的) |
CATALINA_HOME | C:\DevTools\apache-tomcat-8.5.57 (輸入自己解壓的Tomcat目錄,不要照抄我的) |
修改一個:編輯CLASSPATH環境變數,它會開啟一個視窗,具體修改,如下所示
修改兩個:編輯PATH環境變數,它會開啟一個視窗,新添兩條路徑,如下所示
第三步:測試Tomcat是否安裝成功
開啟一個cmd命令列視窗,輸入以下一個命令檢視,如果有內容輸出則證明已經設定成功!
如果看到上邊這個介面了,就把剛才開啟的cmd視窗關掉,否則可能會影響後邊IDEA整合Tomcat。
注意:官網的版本會隔一段時間更新一次,我這裡只是告訴大家怎麼下載,不一定要用最新的,我這套課程使用的是IdeaIU-2020.1.2,如果你不是這個版本,那麼我建議你改為這個版本,否則後邊可能會出現一些列問題。
第一步:開啟官網進行下載和安裝(https://www.jetbrains.com/idea/)
第二步:執行程式進行安裝
全部預設下一步即可,如果遇到需要一頁打勾的很多,就把有 64 的那個勾上,它代表在桌面建立一個64位元的快捷方式,沒勾選也沒事,可以在開始選單開啟IDEA!
第三步:關於啟用的問題
由於IDEA是收費軟體,請大家自行購買啟用碼,然後啟用,不啟用也可以試用30天!
第四步:常見的設定頁面
第五步:最終的效果圖
注意:這個彈窗意思是你需不需要每天都讓我提示你一些小技巧,我們選擇關閉,不用搭理他!
注意:如果你有依賴的JAR包,就放到lib資料夾中,然後新增到工程中,方便專案移動的時候,不會丟失JAR包。
至於classes是否需要建立,在這裡我個人認為是不需要建立的,因為編譯器會自動建立,如果你建立了,還必須要修改設定資訊,很麻煩,所以我建議就不要建立了,一般我們也不會建立。
注意:Fix並不是所有電腦都需要點選的,如果它彈出了這個視窗你就點選,沒彈出來就不用管了!
注意:只有上邊點選了Fix才會出來這個頁面,沒有點選Fix,這一步忽略即可,不用糾結!
一般瀏覽器也會正常顯示剛才JSP中的檔案內容
XML是可延伸標示語言(eXtensible Markup Language),它被設計用來傳輸和儲存資料,我們一般使用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>
樹狀結構:
支援語法:
注意:根節點只能有一個
註釋語法:
<!-- comment -->
解析方式:
案例演示:
工程名稱: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(YAML Ain’t Markup Language)是一種可讀性高並且容易被人類閱讀,容易和指令碼語言互動,用來表達資料序列的程式語言,類似於XML但比XML更簡潔。
YAML語法:
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純量:
純量是最基本的,不可再分的值,包括:
使用一個例子來快速瞭解純量的基本使用:
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
工程名稱: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();
}
}
}
Java Servlet 是執行在 Web 伺服器或應用伺服器上的程式,它是作為來自 Web 瀏覽器或其他 HTTP 使用者端的請求和 HTTP 伺服器上的資料庫或應用程式之間的中間層。使用 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 ...");
}
}
方法介紹:
第三步:設定對映(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的基本資訊
servlet-mapping標籤用於設定請求路徑與具體處理Servlet的對應關係
第四步:啟動應用,然後瀏覽器輸入地址存取(http://localhost:8080/myJavaWebDemo_war_exploded/MyServlet)
第五步:正常關閉Tomcat伺服器,我們會看到呼叫銷燬方法,如下圖所示:
Servlet執行在Servlet容器中,其生命週期由容器來管理。
Servlet的生命週期通過javax.servlet.Servlet介面中的init()、service()和destroy()方法來表示。
Servlet的生命週期包含了下面4個階段:
其實我們不難發現,現有的Servlet它的方法比較多,而且大多需要我們自己來實現,那有沒有一種它的實現子類,把大部分方法都是實現了,而我們只要關注請求處理就行了,那答案肯定是有的,這個類就是HttpServlet,我們只要繼承這個類重寫GET、POST方法就能實現一個簡單的Servlet請求處理,Servlet的繼承體系如下圖:
既然我們知道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需要提交表單模擬,這裡就不演示了,效果都一樣!
我們注意url-pattern它可以有多種攔截形式:
/a
/a/b/c/*
*.action
每個web工程都只有一個ServletContext物件,也就是不管在哪個Servlet裡面,獲取到的這個類的物件都是同一個,它用來獲取Servlet的上下文,在伺服器啟動的時候,會為託管的每一個web應用程式,建立一個ServletContext物件,當從伺服器移除託管或者是關閉伺服器時,ServletContext將會被銷燬。它主要有以下幾方面作用:
第一步:在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)
第一步:在 myJavaWebDemo 的 web 資料夾中右鍵建立 a.txt 檔案,內容為 Hello,World!
第二步:在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)
注意:當你能拿到一個檔案的絕對路徑或者輸入流以後,就可以對它進行操作了!
第一步:建立 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),檢視是否登入
在瀏覽器中存取(http://localhost:8080/myJavaWebDemo_war_exploded/LoginServlet),模擬登入場景
在瀏覽器中存取(http://localhost:8080/myJavaWebDemo_war_exploded/MyHttpServlet),檢視登入次數
通過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)
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/)
在表單輸入資料,然後點選提交
檢視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");
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)
如何解決響應資料中文亂碼問題?
以字元流輸出: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"));
// 第一種:使用範例
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物件。
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)
在瀏覽器中存取(http://localhost:8080/myJavaWebDemo_war_exploded/DisplayServlet)
由於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);
生命週期:
Listener是監聽器,監聽Servlet某一個事件的發生或者狀態的改變,它的內部其實就是介面回撥。
監聽物件:
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>
監聽物件:
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>
監聽物件:
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>
主要作用:
監聽ServletContext存值狀態變更。
主要方法:
如何建立:
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>
主要作用:
監聽ServletRequest存值狀態變更。
主要方法:
如何建立:
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>
主要作用:
監聽HttpSession存值狀態變更。
主要方法:
如何建立:
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>
主要作用:
監聽物件與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 ...");
}
}
如何設定:
這一類監聽器不用註冊。
主要作用:
用於監聽現在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是過濾器,就是對使用者端發出來的請求進行過濾。瀏覽器發出請求,然後伺服器派servlet處理。在中間就可以過濾,其實過濾器起到的是攔截的作用。使用過濾器可以對一些敏感詞彙進行過濾、統一設定編碼、實現自動登入等功能。
如何定義:
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>
filter01 ...
filter02 ...
filter03 ...
filter03 ...
filter02 ...
filter01 ...
注意:init方法的引數 FilterConfig , 可以用於獲取Filter在註冊的名字以及初始化引數,其實這裡的設計的初衷與ServletConfig是一樣的。
/a
/a/b/c/*
*.action
注意:針對 dispatcher 設定的選項。
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(全稱Java Server Pages)是由 Sun Microsystems 公司倡導和許多公司參與共同建立的一種使軟體開發者可以響應使用者端請求,而動態生成 HTML、XML 或其他格式檔案的Web網頁的技術標準。從使用者角度看待,就是是一個網頁,從程式設計師角度看待,其實是一個Java類,它繼承了Servlet,所以可以直接說JSP就是一個Servlet。
那為什麼會有JSP?
HTML多數情況下用來顯示一成不變的靜態內容,但是有時候我們需要在網頁上顯示一些動態資料,比如:查詢所有的學生資訊、根據姓名去查詢具體某個學生,這些動作都需要去查詢資料庫,然後在網頁上顯示,HTML是不支援寫Java程式碼 ,JSP裡面可以寫Java程式碼。
JSP生命週期就是從建立到銷燬的整個過程,類似於Servlet生命週期,區別在於JSP生命週期還包括將JSP檔案編譯成Servlet。
以下是JSP生命週期中所走過的幾個階段:
第一種格式:
格式:
<% Java程式碼片段 %>
範例:
<% System.out.println("Hello"); %>
第二種格式:
格式:
<jsp:scriptlet>
Java程式碼片段
</jsp:scriptlet>
範例:
<jsp:scriptlet>
System.out.println("Hello");
</jsp:scriptlet>
第一種格式:
格式:
<%! 變數宣告 %>
範例:
<%! int a = 10; int b = 20; %>
第二種格式:
格式:
<jsp:declaration>
變數宣告
</jsp:declaration>
範例:
<jsp:declaration>
int c = 30;
int d = 40;
</jsp:declaration>
一個JSP表示式中包含的指令碼語言表示式,先被轉化成String,然後插入到表示式出現的地方。
由於表示式的值會被轉化成String,所以您可以在一個文字行中使用表示式而不用去管它是否是HTML標籤。
表示式元素中可以包含任何符合Java語言規範的表示式,但是不能使用分號來結束表示式。
第一種格式:
格式:
<%= 表示式 %>
範例:
<%= a %>
第二種格式:
格式:
<jsp:expression>
表示式
</jsp:expression>
範例:
<jsp:expression>
a
</jsp:expression>
不同情況下使用註釋的語法規則:
語法 | 描述 |
---|---|
<%-- 註釋 --%> | JSP註釋,註釋內容不會被傳送至瀏覽器甚至不會被編譯 |
HTML註釋,通過瀏覽器檢視網頁原始碼時可以看見註釋內容 | |
<\% | 代表靜態 <% 常數 |
%\> | 代表靜態 %> 常數 |
\’ | 在屬性中使用的單引號 |
\" | 在屬性中使用的雙引號 |
JSP指令用來設定整個JSP頁面相關的屬性,如網頁的編碼方式和指令碼語言。
語法格式:
<%@ 指令 屬性="值" %>
三種指令:
指令 | 描述 |
---|---|
<%@ page … %> | 定義網頁依賴屬性,比如指令碼語言、error頁面、快取需求等等 |
<%@ include … %> | 包含其他檔案 |
<%@ taglib … %> | 引入標籤庫的定義 |
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 | 確定指令碼元素能否被使用 |
JSP可以通過include指令來包含其他檔案,被包含的檔案可以是JSP檔案、HTML檔案或文字檔案,包含的檔案就好像是該JSP檔案的一部分,會被同時編譯執行。
第一種格式:
<%@ include file="檔案相對url地址" %>
第二種格式:
<jsp:directive.include file="檔案相對url地址" />
JSP允許使用者自定義標籤,一個自定義標籤庫就是自定義標籤的集合,taglib指令引入一個自定義標籤集合的定義,包括庫路徑、自定義標籤。
第一種格式:
<%@ taglib uri="uri" prefix="標籤字首" %>
第二種格式:
<jsp:directive.taglib uri="uri" prefix="標籤字首" />
與JSP指令元素不同的是,JSP動作元素在請求處理階段起作用,利用JSP動作可以動態地插入檔案、重用JavaBean元件、把使用者重定向到另外的頁面、為Java外掛生成HTML程式碼。
語法格式:
<jsp:動作名稱 屬性="值" />
常見動作:
語法 | 描述 |
---|---|
jsp:include | 在頁面被請求的時候引入一個檔案。 |
jsp:useBean | 尋找或者範例化一個JavaBean。 |
jsp:setProperty | 設定JavaBean的屬性。 |
jsp:getProperty | 輸出某個JavaBean的屬性。 |
jsp:forward | 把請求轉到一個新的頁面。 |
常見屬性:
語法 | 描述 |
---|---|
id | id屬性是動作元素的唯一標識,可以在JSP頁面中參照。 動作元素建立的id值可以通過PageContext來呼叫。 |
scope | 該屬性用於識別動作元素的生命週期。 id屬性和scope屬性有直接關係,scope屬性定義了相關聯id物件的壽命。 scope屬性有四個可能的值:page、request、session和application。 |
jsp:include動作元素用來包含靜態和動態的檔案,該動作把指定檔案插入正在生成的頁面。
語法格式:
注意:前面已經介紹過include指令,它是在JSP檔案被轉換成Servlet的時候引入檔案,而這裡的jsp:include動作不同,插入檔案的時間是在頁面被請求的時候。
<jsp:include page="相對URL地址" flush="true" />
屬性列表:
屬性 | 描述 |
---|---|
page | 包含在頁面中的相對URL地址。 |
flush | 布林屬性,定義在包含資源前是否重新整理快取區。 |
相關範例:
<jsp:include page="myInfo.html" flush="true" />
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" />
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>
屬性列表:
屬性 | 描述 |
---|---|
name | name屬性是必需的。它表示要設定屬性的是哪個Bean。 |
property | property屬性是必需的。它表示要設定哪個屬性。有一個特殊用法:如果property的值是"*",表示所有名字和Bean屬性名字匹配的請求引數都將被傳遞給相應的屬性set方法。 |
value | value 屬性是可選的。該屬性用來指定Bean屬性的值。字串資料會在目標類中通過標準的valueOf方法自動轉換成數位、boolean、Boolean、 byte、Byte、char、Character。例如,boolean和Boolean型別的屬性值(比如"true")通過 Boolean.valueOf 轉換,int和Integer型別的屬性值(比如"42")通過Integer.valueOf轉換。value和param不能同時使用,但可以使用其中任意一個。 |
param | param 是可選的。它指定用哪個請求引數作為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>
jsp:getProperty動作提取指定Bean屬性的值,轉換成字串,然後輸出。
語法格式:
<jsp:getProperty name="myName" property="屬性值" />
屬性列表:
屬性 | 描述 |
---|---|
name | 要檢索的Bean屬性名稱,Bean必須已定義。 |
property | 表示要提取Bean屬性的值。 |
相關範例:
<jsp:getProperty name="user2" property="username" />
jsp:forward動作把請求轉到另外的頁面。
語法格式:
<jsp:forward page="相對URL地址" />
屬性列表:
屬性 | 描述 |
---|---|
page | page屬性包含的是一個相對URL。 page的值既可以直接給出,也可以在請求的時候動態計算,可以是一個JSP頁面或者一個 Java Servlet。 |
相關範例:
<jsp:forward page="myJSP.jsp" />
JSP隱式物件是JSP容器為每個頁面提供的Java物件,開發者可以直接使用它們而不用顯式宣告,JSP隱式物件也被稱為預定義變數。
JSP所支援的九大隱式物件:
物件 | 描述 |
---|---|
request | HttpServletRequest 介面的範例 |
response | HttpServletResponse 介面的範例 |
session | HttpSession 類的範例 |
application | ServletContext 類的範例,與應用上下文有關 |
config | ServletConfig 類的範例 |
out | JspWriter 類的範例,用於把結果輸出至網頁上 |
pageContext | PageContext 類的範例,提供對JSP頁面所有物件以及名稱空間的存取 |
page | 類似於Java類中的 this 關鍵字 |
Exception | Exception 類的物件,代表發生錯誤的JSP頁面中對應的異常物件 |
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 />
<% } %>
EL是為了簡化咱們的jsp程式碼,具體一點就是為了簡化在jsp裡面寫的那些java程式碼。
注意:如果從作用域中取值,會先從小的作用域開始取,如果沒有,就往下一個作用域取,一直把四個作用域取完都沒有,就沒有顯示。
${ 表示式 }
EL表示式的11個內建物件:
隱含物件 | 描述 |
---|---|
pageScope | page 作用域 |
requestScope | request 作用域 |
sessionScope | session 作用域 |
applicationScope | application 作用域 |
param | Request 物件的引數,字串 |
paramValues | Request 物件的引數,字串集合 |
header | HTTP 資訊頭,字串 |
headerValues | HTTP 資訊頭,字串集合 |
initParam | 上下文初始化引數 |
cookie | Cookie值 |
pageContext | 當前頁面的pageContext |
注意:您可以在表示式中使用這些物件,就像使用變數一樣。
如果域中所存的是物件:
<%
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>
JSTL(JSP Standard Tag Library,標準標籤庫)主要也是為了簡化jsp的程式碼編寫,替換 <%%> 寫法,一般與EL表示式配合使用。
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!-- 宣告一個物件 myname,物件的值 zhangsan,儲存到了 page(預設),指定是 session 域 -->
<c:set var="myname" value="zhangsan" scope="session"></c:set>
${ sessionScope.myname }
<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>
<%--從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>
Servlet 3.0 作為 Java EE 6 規範體系中一員,隨著 Java EE 6 規範一起釋出。該版本在前一版本(Servlet 2.5)的基礎上提供了若干新特性用於簡化 Web 應用的開發和部署。其中有幾項特性的引入讓開發者感到非常興奮,同時也獲得了 Java 社群的一片讚譽之聲:
如何建立:
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 ...");
}
}
屬性列表:
屬性名 | 型別 | 描述 |
---|---|---|
name | String | 指定 Servlet 的 name 屬性,如果沒有顯式指定,則該 Servlet 的取值即為類的全限定名 |
value | String[] | 該屬性等價於 urlPatterns 屬性,兩個屬性不能同時使用 |
urlPatterns | String[] | 指定一組 Servlet 的 URL 匹配模式 |
loadOnStartup | int | 指定 Servlet 的載入順序 |
initParams | WebInitParam[] | 指定一組 Servlet 初始化引數 |
asyncSupported | boolean | 宣告 Servlet 是否支援非同步操作模式 |
description | String | 該 Servlet 的描述資訊 |
displayName | String | 該 Servlet 的顯示名,通常配合工具使用 |
如何測試:
開啟瀏覽器輸入:http://localhost:8080/servlet3_0_war_exploded/AnnotationServlet
檢測控制檯輸出:
如何建立:
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() {
}
}
屬性列表:
屬性名 | 型別 | 描述 |
---|---|---|
filterName | String | 指定過濾器的 name 屬性 |
value | String[] | 該屬性等價於 urlPatterns 屬性,但是兩者不應該同時使用 |
urlPatterns | String[] | 指定一組過濾器的 URL 匹配模式 |
servletNames | String[] | 指定過濾器將應用於哪些 Servlet |
dispatcherTypes | DispatcherType | 指定過濾器的轉發模式 具體取值包括: ASYNC、ERROR、FORWARD、INCLUDE、REQUEST |
initParams | WebInitParam[] | 指定一組過濾器初始化引數 |
asyncSupported | boolean | 宣告過濾器是否支援非同步操作模式 |
description | String | 該過濾器的描述資訊 |
displayName | String | 該過濾器的顯示名,通常配合工具使用 |
如何測試:
開啟瀏覽器輸入:http://localhost:8080/servlet3_0_war_exploded/AnnotationServlet
檢測控制檯輸出:
如何建立:
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 ...");
}
}
如何測試:
重新啟動伺服器,觀察控制檯:
如果只想要使用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設定有效,而註解設定則被忽略。
前臺頁面:
<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註解:
屬性名 | 型別 | 是否可選 | 描述 |
---|---|---|---|
fileSizeThreshold | int | 是 | 當資料量大於該值時,內容將被寫入檔案 |
location | String | 是 | 存放生成的檔案地址 |
maxFileSize | long | 是 | 允許上傳的檔案最大值。預設值為-1,表示沒有限制 |
maxRequestSize | long | 是 | 針對該multipart/form-data請求的最大數量,預設值為-1,表示沒有限制 |
如何測試:
注意問題:
如果你的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
檢測控制檯輸出:
三秒後頁面輸出:
十秒後控制檯輸出:
動態註冊就是在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 ...");
}
}
建立一個普通的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
檢測控制檯輸出:
建立一個普通的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
檢測控制檯輸出:
建立一個普通的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
檢測控制檯輸出:
如何實現模組化開發?
編寫一個類繼承自 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>
接下來我們使用一個完整範例來演示:
我們先看下我們目前已經做了哪些工程:
建立一個JavaWeb片段工程,可以算是一個功能模組,具體步驟如下圖:
把以下程式碼拷貝到組態檔中:
<?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>
建立一個需要測試的Servlet,這裡我們直接採用註解開發
接下來我們需要把當前這個工程編譯為一個jar包,以方便嵌入到別的工程中
編譯完成,就會出現這個jar包,把它拷貝到桌面,備用,然後關閉當前工程
開啟之前的servlet3.0的專案,我們把剛才編譯好的jar包放到這個工程中,用來測試是不是可行
把剛才複製到桌子上的fragment.jar複製到lib中
啟動伺服器,然後輸入FragmentServlet的對映網址,看看控制檯會不會輸出
開啟瀏覽器,輸入:http://localhost:8080/servlet3_0_war_exploded/FragmentServlet