Servlet概念
server applet 運行在服務器上的小程序
Servlet就是一個接口,定義了Java類被瀏覽器訪問到(tomcat識別)的規則
將來我們自定義一個類,實現Servlet接口,復寫方法
快速入門
創建JavaEE項目
定義一個類,實現Servlet接口
實現接口中的抽象方法
配置Servlet:在web.xml中配置
<!--配置Servlet-->
[Java] 純文本查看 復制代碼
?
01
02
03
04
05
06
07
08
09
10
11
12
13
<servlet>
<servlet-name>
demo01
</servlet-name>
<servlet-class>
cn.itcast.web.servlet.ServletDemo01
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>demo01</servlet-name>
<url-pattern>/demo01</url-pattern>
</servlet-mapping>
注:一般在IDEA中配置Tmocatd的Application context為/項目名稱,再調用時需要用localhost:8080/項目名稱/....
Servlet的執行原理
當服務器接受到客戶端瀏覽器的請求后,會解析請求URL路徑,獲取訪問的Servlet的資源路徑
查找web.xml,是否有對應的<url-pattern>標簽內容
通過servlet-pattern找到servlet-name,又通過name找到資源的class全類名.
tomcat將類加載進內存,通過反射創建對象并調用service方法
Servlet中的生命周期
init方法-創建
初始化方法,在Servlet被創建時執行,只會執行一次
- Servlet什么時候被創建?
*默認情況下,第一次被訪問時,Servlet被創建
*可以在web.xml中配置創建時機
<servlet>
<load-on-startup>
0/正值:服務器啟動時創建,值越大優先級越小,一般從2開始,因為1被tomcat占用了
負值:第一次被訪問時創建
</load-on-startup>
</servlet>
- Servlet在服務器中只有一個對象,所以說Servlet是單例的
*多個用戶同時訪問時,可能存在線程安全問題
*解決方案:盡量不要在Servlet中定義成員變量,而是使用局部變量;即使定義了成員變量,也不要對其修改值
service方法-提供服務
每一次Servlet被訪問一次則執行一次
destory方法-銷毀
Servlet被殺死(服務器正常關閉)時執行一次
一般用于釋放資源
ServletConfig方法 獲取ServletConfig對象
ServletInfo方法 獲取ServletInfo,如版本.作者,信息等,但一般不實現該方法
Servlet 3.0注解配置
-[ ] 好處:支持注解配置,可以不需要web.xml了-[ ] 步驟
創建JavaEE項目,選擇Servlet的版本3.0以上,可以不創建web.xml
定義一個類,實現Servlet接口
復寫方法
在類上使用@WebServlet注解進行配置
@WebServlet("資源路徑")
IDEA和tomcat的相關配置
[ ]IDEA會為每一個tomcat部署項目單獨建立一份配置文件
啟動后服務器控制臺有輸出Log:
Using CATALINA_BASE: "C:\Users\Mcdull\.IntelliJIdea2017.3\system\tomcat\Tomcat_8_5_31_webServer_2"
在Edit Configure下就可以修改配置文件和虛擬目錄
工作空間項目和tomcat部署的web項目
tomcat真正訪問的是"tomcat部署的web項目","tomcat部署的web項目"對應著"工作空間項目"的web目錄下的所有資源
!!!!理解
采用的部署方式為第三種,在config/catalina/下部署
打開Using CATALINA_BASE路徑,可以找到config/catalina/day13_servlet.xml
打開servlet.xml,<Context docBase="E:\Projects\webServer\out\artifacts\day13_servlet_war_exploded" \>
里面指明了tomcat項目的路徑
WEB-INFO目錄下的資源不能被瀏覽器直接訪問
斷點調試
打斷點,后用debug模式啟動服務器
Servlet結構體系
Servlet的實現類: GenericServlet(抽象類)-->HttpServlet(抽象類)
GenericServlet
GenericServlet將除了servic()以外的方法都空實現
將來定義Servlet時可以繼承GericServlet,只需實現servic類即可.
其他類也可以重寫HttpServlet
-[ ] 實際上做項目時,我們一般使用GenericServlet的子類HttpServlet,因為HttpServlet封裝了Http協議
不使用HttpServlet時,service方法需要實現的功能
判斷用戶的請求方式(get/post...)
String method = req.getMethod();
if("GET".equals(method)){//get方式獲取數據邏輯操作}
else if("POST".equals(methos){//post方式獲取數據邏輯操作}
HttpService 將判斷請求方式封裝起來,并提供doGet()和doPost()方法,分別寫在兩個邏輯體中
1.定義類繼承HttpServlet類
2.重寫doGet/doPost/...方法
[Java] 純文本查看 復制代碼
?
1
2
3
4
5
6
7
8
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp){
System.out.println("doGet...");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp){
System.out.println("doGet...");
}
Servlet urlpattern相關配置
1.urlpattern:Servlet訪問路徑可以有配置多個
一個Servlet可以定義多個訪問路徑,在注解中使用{"路徑1","路徑2"...}來配置
2.urlpattern:Servlet路徑的定義規則
1)./xxx 以這種方式為主
2)./xxx/xxx
3).*.后綴名
[強制!]開發中后綴名只能用*.do或*.action
HTTP概念
Hyper Text Transfer Protocol:超文本傳輸協議
傳輸協議:定義了客戶端和服務器端通信時發送數據的格式
特點:
1). 基于TCP/IP的高級協議
2). HTTP的默認端口號為80
當訪問資源時,如果服務器端口號為80,則可以省略
3). 基于請求/響應模型的:一次請求對應一次響應
4). 無狀態的:每次請求之間相互獨立,不能交互數據
歷史版本:
1.0版本:每一次請求都需要建立一個連接
1.1版本:復用連接
請求消息數據格式
請求行
格式
請求行格式:
請求方式 請求url 請求協議/版本
例: GET /login.html http/1.1
請求方式
HTTP協議中有7種請求方式,常用的有2種
*GET:
1.請求參數在請求行中,在url后
2.請求的url長度是有限制的
3.不太安全
*POST:
1.請求參數在請求體中
2.請求的url長度沒有限制
3.相對安全
請求頭-瀏覽器告訴服務器一些信息
格式
請求頭格式:
請求頭名稱:請求頭值
請求頭名稱
常見的請求頭:
1.User-Agent**:瀏覽器告訴服務器,訪問者使用的瀏覽器版本信息
*可以在服務器端獲取該頭信息,解決瀏覽器兼容性問
2.Referer**:告訴服務器,當前請求從哪里來(發起請求的頁面)
*例:Referer:http://localhost:8080/day_14/login.html
*作用:
1)防盜鏈:
if(referer.equals()){操作}
else{"想看嗎?來XXX網站吧!"}
2)統計工作:
統計工作:統計請求來源
if(refer.eauals("百度"){百度++}
else if(){}...
3.Connection:告訴服務器連接的狀態(是否可服用)
4.Host:請求主機的地址
5.Accept:告訴服務器,作為瀏覽器可以解析什么格式的文件
請求空行-用于分割POST請求的請求頭和請求體
空行
請求體(正文)-封裝post請求消息的請求參數
格式
參數名=參數值
響應消息數據格式
響應行
組成
協議/版本 響應狀態碼 狀態碼的描述
響應狀態碼:服務器高速客戶端瀏覽器本次請求和響應的一個狀態
分類:
1xx: 服務器接收客戶端消息,沒有接收完成,等待一段時間后,發送1xx
2xx: 成功 代表狀態碼:200
3xx: 重定向 代表狀態碼:302(重定向) 304(訪問緩存)
4xx: 客戶端錯誤 代表狀態碼:404(請求路徑錯誤) 405(請求方式沒有對應的doXXX方法)
5xx: 服務器錯誤 代表狀態碼:500(服務器內部出現異常)
響應頭
格式
頭名稱:值
常見的響應頭
1.Content-Type:服務器告訴客戶端響應體數據格式以及編碼格式
例:Content-Type:text/html;charset=UTF-8
2.Content-disposition:服務器告訴客戶端以什么格式打開響應體數據
*值:
*in-line:默認值,在當前頁面內打開
*attachment;filename=xxx:以附件形式打開響應體.文件下載
響應空行
響應體:傳輸的數據
響應字符串格式Request對象Request和Response對象的原理
1.tomcat服務器會根據請求url中的資源路徑,創建對應的Servlet對象
2.tomcat服務器會創建request和response對象;request對象中封裝消息數據
3.tomcat將request和response兩個對象傳遞給service方法,并調用service方法
4.程序員可以通過request對象來獲取請求消息數據;可以通過response對象來設置響應數據
5.tomcat在給瀏覽器作出響應之前,會從response對象中獲取消息響應數據并響應給瀏覽器
注意:
1) request和response對象是由服務器創建的,我們來使用它們
2) request對象是來獲取請求消息,response對象來設置響應消息
Requset對象的繼承結構
ServletRequset(接口)->HttpServletReqest(接口)->RequestFacade(tomcat寫的實現類)
Request對象的功能獲取請求消息數據
1.獲取請求行數據
-請求行數據: GET /day14/demo01?name=zhangsan HTTP/1.1
-獲取方法:
1)獲取請求方式: GET
*String getMethod()
2)獲取虛擬目錄**: /day14
*String getContextPath()
3)獲取Servlet路徑 /demo1
*String getServletPath()
4)獲取請求參數 /name=zhangsan
*String getQueryString()
5)獲取請求的URI**: /day14/demo1
*String getRquestURI :/day14/demo1
*StringBuffer getRequestURL: http://localhost/day14/demo1
6)獲取瀏覽器的協議及版本 HTTP/1.1
*String getProtocol()
7)獲取客戶機的IP地址
*String getRemoteAddr()
注意:
URL:統一資源定位符 http://localhost//day14/demo1
URI:統一資源標識符
day14/demo1
URL的范圍比URI的范圍小
2.獲取請求頭數據
1) String getHeader(String name):通過請求頭名稱獲取請求頭的值
2) Enumeration<String> getHeadernames():獲取所有請求頭的名稱
Enumberation 和 Iterator類似:
hasMoreElement() <--> hasNext()用于判斷
nextElement() <--> next() 用于獲取下一下元素
3.獲取請求體數據只有POST請求方式,才有請求體,在請求體中封裝了POST請求的請求參數
步驟:
1).獲取流對象
*BufferedReader getReader():獲取字符輸入流
*ServletInputStream getInputStream():獲取字節輸入流
2).從流對象中獲取數據
4.總結:常用的方法
1)獲取虛擬目錄:getContextPath()
2)獲取請求URI:getRequestURI()/getRequestURL()
3)獲取請求頭:getHeader(String name)
==其他功能==
==1.獲取請求參數(通用方式)==
1)String getParameter(String name):根據參數名稱獲取參數值
2)String[] getParameterValues(String name): 根據參數名稱獲取參數值的數組,多用于復選框
如:hobby=xx&hobby=game
3)Enumeration<String> getParameterNames():獲取所有請求的參數名稱
4)Map<String,String[]> getParameterMap():獲取所有參數的map集合
- 中文亂碼問題
*get方式: tomcat8 已經將get方式亂碼問題解決了
*post方式: 會亂碼
解決:在獲取參數前,設置request編碼
request.setCharacterEncoding("utf-8")
==2.請求轉發:一種在服務器內部的資源跳轉的方式==
步驟
1)通過request對象獲取請求轉發器對象:RequestDispatcher getRequestDispatcher(String path)
2)使用RequestDispatcher對象來進行轉發:forward(ServletRequest request,ServletResponse)
特點
1) 瀏覽器地址欄路徑不發生變化2) 只能轉發至當前服務器的內部資源中3) 轉發是一次請求
==3.數據共享==
域對象:一個有作用范圍的對象,可以在范圍內共享數據
request域:代表一次請求的范圍,一般用于請求轉發的多個資源中去共享數據
request資源共享方法
1) void setAttribute(String name ,Object obj) :存儲數據2) Object getAttribute(String name) 通過鍵來獲取值3) void removeAttribute(String name) 通過鍵來移除鍵值對
==4.獲取ServletContext對象==
-ServletContext getServletContext()
BeanUtils
用于封裝JavaBean
JavaBean
JavaBean:標準的Java類
類必須被public修飾
必須提供空參的構造器
成員變量必須使用private修飾
提供公共的setter和getter方法
JavaBean的功能:封裝數據
概念
成員變量
屬性:setter和getter方法截取后的產物
例如:getUsername()-->Username-->username大部分情況下屬性和成員變量是一樣的
BeanUtils的方法
1.setProperty(javaBean,"屬性名","值")
2.getProperty(javaBean,"屬性名")
3.populate(javaBean,屬性集map)
Response對象
功能:設置響應消息
設置響應行
設置響應頭
設置響應體
設置響應行1.格式HTTP/1.1 200 ok2.設置狀態碼setStatus(int sc)
設置響應頭
setHeader(String name, String value)
設置響應體
使用步驟
1.獲取輸出流 *字符輸出流:PrintWriter getWriter() *字節輸出流:ServletOutputStream getOutputStream()2.使用輸出流將數據輸出到客戶端瀏覽器
案例完成重定向(redirect)
代碼實現
//1.設置狀態碼為 302response.setStatues(302);//2.設置響應頭locationresponse.setHeader("location","/虛擬路徑/資源路徑")
簡單的重定向方法
resonpse.sendRedirect("/虛擬路徑/資源路徑")
重定向的特點
1. 地址欄發生變化2. 重定向可以訪問其他服務器的資源3. 重定向是兩次請求
路徑寫法:
1.相對路徑: 通過相對路徑不可以確定唯一資源 * 以 ./開頭 表示當前路徑 * 以 ../開頭 表示后退一級 *規則: 找到當前資源和目標資源之間的相對位置關系 2.絕對路徑: 絕對路徑可以確定唯一資源 在這里可以寫為/虛擬路徑/資源路徑
在瀏覽器輸出字符數據
代碼實現
//1.獲取字符輸出流PrintWriter pw = resp.getWriter();//2.向瀏覽器寫出字符數據pw.write("<h1>你好,response</h1>");此實現會出現亂碼,因為獲取的流的默認編碼為IOS-8859-1
亂碼問題
上一個代碼實現會出現亂碼問題
解決方法:在獲取流之前設置編碼和web解碼方式
//1.設置response的編碼格式(默認為IOS-8859-1)
//response.setCharacterEncoding("編碼格式")
//2.使用response設置響應頭,要求使用特定的編碼格式去解碼
response.setHeader("content-type","text/html;charset=編碼格式")
簡單方法:
response.setContentType("text/html;charset=編碼格式")
注意:使用語句2,就可以設置編碼格式,和瀏覽器的解碼格式.第1步就可以不用寫了
作者:黑馬程序員JavaEE培訓學院
首發:http://java.itheima.com/