首頁(yè)技術(shù)文章正文

Web核心-Servlet

更新時(shí)間:2019-01-10 來(lái)源:黑馬程序員 瀏覽量:

Servlet概念

server applet 運(yùn)行在服務(wù)器上的小程序

Servlet就是一個(gè)接口,定義了Java類被瀏覽器訪問(wèn)到(tomcat識(shí)別)的規(guī)則

將來(lái)我們自定義一個(gè)類,實(shí)現(xiàn)Servlet接口,復(fù)寫(xiě)方法


快速入門(mén)

創(chuàng)建JavaEE項(xiàng)目

定義一個(gè)類,實(shí)現(xiàn)Servlet接口

實(shí)現(xiàn)接口中的抽象方法

配置Servlet:在web.xml中配置


    <!--配置Servlet-->
   

[Java] 純文本查看 復(fù)制代碼

?

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為/項(xiàng)目名稱,再調(diào)用時(shí)需要用localhost:8080/項(xiàng)目名稱/....

Servlet的執(zhí)行原理

當(dāng)服務(wù)器接受到客戶端瀏覽器的請(qǐng)求后,會(huì)解析請(qǐng)求URL路徑,獲取訪問(wèn)的Servlet的資源路徑

查找web.xml,是否有對(duì)應(yīng)的<url-pattern>標(biāo)簽內(nèi)容

通過(guò)servlet-pattern找到servlet-name,又通過(guò)name找到資源的class全類名.

tomcat將類加載進(jìn)內(nèi)存,通過(guò)反射創(chuàng)建對(duì)象并調(diào)用service方法


Servlet中的生命周期

init方法-創(chuàng)建


初始化方法,在Servlet被創(chuàng)建時(shí)執(zhí)行,只會(huì)執(zhí)行一次
- Servlet什么時(shí)候被創(chuàng)建?
   *默認(rèn)情況下,第一次被訪問(wèn)時(shí),Servlet被創(chuàng)建
   *可以在web.xml中配置創(chuàng)建時(shí)機(jī)
     <servlet>
        <load-on-startup>
         0/正值:服務(wù)器啟動(dòng)時(shí)創(chuàng)建,值越大優(yōu)先級(jí)越小,一般從2開(kāi)始,因?yàn)?被tomcat占用了
           負(fù)值:第一次被訪問(wèn)時(shí)創(chuàng)建
        </load-on-startup>
     </servlet>
     
- Servlet在服務(wù)器中只有一個(gè)對(duì)象,所以說(shuō)Servlet是單例的
   *多個(gè)用戶同時(shí)訪問(wèn)時(shí),可能存在線程安全問(wèn)題
   *解決方案:盡量不要在Servlet中定義成員變量,而是使用局部變量;即使定義了成員變量,也不要對(duì)其修改值

service方法-提供服務(wù)


每一次Servlet被訪問(wèn)一次則執(zhí)行一次

destory方法-銷毀


Servlet被殺死(服務(wù)器正常關(guān)閉)時(shí)執(zhí)行一次
一般用于釋放資源

ServletConfig方法  獲取ServletConfig對(duì)象

ServletInfo方法  獲取ServletInfo,如版本.作者,信息等,但一般不實(shí)現(xiàn)該方法


Servlet 3.0注解配置

-[ ] 好處:支持注解配置,可以不需要web.xml了-[ ] 步驟

創(chuàng)建JavaEE項(xiàng)目,選擇Servlet的版本3.0以上,可以不創(chuàng)建web.xml

定義一個(gè)類,實(shí)現(xiàn)Servlet接口

復(fù)寫(xiě)方法

在類上使用@WebServlet注解進(jìn)行配置


@WebServlet("資源路徑")
IDEA和tomcat的相關(guān)配置

[ ]IDEA會(huì)為每一個(gè)tomcat部署項(xiàng)目單獨(dú)建立一份配置文件


啟動(dòng)后服務(wù)器控制臺(tái)有輸出Log:
Using CATALINA_BASE:   "C:\Users\Mcdull\.IntelliJIdea2017.3\system\tomcat\Tomcat_8_5_31_webServer_2"
  在Edit Configure下就可以修改配置文件和虛擬目錄

工作空間項(xiàng)目和tomcat部署的web項(xiàng)目

tomcat真正訪問(wèn)的是"tomcat部署的web項(xiàng)目","tomcat部署的web項(xiàng)目"對(duì)應(yīng)著"工作空間項(xiàng)目"的web目錄下的所有資源


!!!!理解
采用的部署方式為第三種,在config/catalina/下部署
打開(kāi)Using CATALINA_BASE路徑,可以找到config/catalina/day13_servlet.xml
打開(kāi)servlet.xml,<Context docBase="E:\Projects\webServer\out\artifacts\day13_servlet_war_exploded" \>
里面指明了tomcat項(xiàng)目的路徑

WEB-INFO目錄下的資源不能被瀏覽器直接訪問(wèn)

斷點(diǎn)調(diào)試


打斷點(diǎn),后用debug模式啟動(dòng)服務(wù)器
Servlet結(jié)構(gòu)體系

Servlet的實(shí)現(xiàn)類: GenericServlet(抽象類)-->HttpServlet(抽象類)


GenericServlet
GenericServlet將除了servic()以外的方法都空實(shí)現(xiàn)
將來(lái)定義Servlet時(shí)可以繼承GericServlet,只需實(shí)現(xiàn)servic類即可.
其他類也可以重寫(xiě)HttpServlet

-[ ]  實(shí)際上做項(xiàng)目時(shí),我們一般使用GenericServlet的子類HttpServlet,因?yàn)镠ttpServlet封裝了Http協(xié)議

不使用HttpServlet時(shí),service方法需要實(shí)現(xiàn)的功能
判斷用戶的請(qǐng)求方式(get/post...)
   String method = req.getMethod();
   if("GET".equals(method)){//get方式獲取數(shù)據(jù)邏輯操作}
   else if("POST".equals(methos){//post方式獲取數(shù)據(jù)邏輯操作}

HttpService 將判斷請(qǐng)求方式封裝起來(lái),并提供doGet()和doPost()方法,分別寫(xiě)在兩個(gè)邏輯體中

1.定義類繼承HttpServlet類

2.重寫(xiě)doGet/doPost/...方法


   

[Java] 純文本查看 復(fù)制代碼

?

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相關(guān)配置

1.urlpattern:Servlet訪問(wèn)路徑可以有配置多個(gè)


一個(gè)Servlet可以定義多個(gè)訪問(wèn)路徑,在注解中使用{"路徑1","路徑2"...}來(lái)配置

2.urlpattern:Servlet路徑的定義規(guī)則


1)./xxx   以這種方式為主
2)./xxx/xxx
3).*.后綴名
[強(qiáng)制!]開(kāi)發(fā)中后綴名只能用*.do或*.action
HTTP概念

Hyper Text Transfer Protocol:超文本傳輸協(xié)議

傳輸協(xié)議:定義了客戶端和服務(wù)器端通信時(shí)發(fā)送數(shù)據(jù)的格式

特點(diǎn):


  1). 基于TCP/IP的高級(jí)協(xié)議
  2). HTTP的默認(rèn)端口號(hào)為80
      當(dāng)訪問(wèn)資源時(shí),如果服務(wù)器端口號(hào)為80,則可以省略
  3). 基于請(qǐng)求/響應(yīng)模型的:一次請(qǐng)求對(duì)應(yīng)一次響應(yīng)
  4). 無(wú)狀態(tài)的:每次請(qǐng)求之間相互獨(dú)立,不能交互數(shù)據(jù)

歷史版本:    


1.0版本:每一次請(qǐng)求都需要建立一個(gè)連接

1.1版本:復(fù)用連接


請(qǐng)求消息數(shù)據(jù)格式

請(qǐng)求行

格式


  請(qǐng)求行格式:
  請(qǐng)求方式  請(qǐng)求url      請(qǐng)求協(xié)議/版本
  例: GET  /login.html   http/1.1

請(qǐng)求方式


HTTP協(xié)議中有7種請(qǐng)求方式,常用的有2種
*GET:
   1.請(qǐng)求參數(shù)在請(qǐng)求行中,在url后
   2.請(qǐng)求的url長(zhǎng)度是有限制的
   3.不太安全
*POST:
   1.請(qǐng)求參數(shù)在請(qǐng)求體中
   2.請(qǐng)求的url長(zhǎng)度沒(méi)有限制
   3.相對(duì)安全

請(qǐng)求頭-瀏覽器告訴服務(wù)器一些信息

格式


   請(qǐng)求頭格式:
   請(qǐng)求頭名稱:請(qǐng)求頭值

請(qǐng)求頭名稱


常見(jiàn)的請(qǐng)求頭:
   1.User-Agent**:瀏覽器告訴服務(wù)器,訪問(wèn)者使用的瀏覽器版本信息
      *可以在服務(wù)器端獲取該頭信息,解決瀏覽器兼容性問(wèn)
   2.Referer**:告訴服務(wù)器,當(dāng)前請(qǐng)求從哪里來(lái)(發(fā)起請(qǐng)求的頁(yè)面)
      *例:Referer:http://localhost:8080/day_14/login.html
      *作用:
        1)防盜鏈:
            if(referer.equals()){操作}
            else{"想看嗎?來(lái)XXX網(wǎng)站吧!"}
        2)統(tǒng)計(jì)工作:
            統(tǒng)計(jì)工作:統(tǒng)計(jì)請(qǐng)求來(lái)源
            if(refer.eauals("百度"){百度++}
            else if(){}...
   3.Connection:告訴服務(wù)器連接的狀態(tài)(是否可服用)
   4.Host:請(qǐng)求主機(jī)的地址
   5.Accept:告訴服務(wù)器,作為瀏覽器可以解析什么格式的文件

請(qǐng)求空行-用于分割POST請(qǐng)求的請(qǐng)求頭和請(qǐng)求體

空行

請(qǐng)求體(正文)-封裝post請(qǐng)求消息的請(qǐng)求參數(shù)

格式


參數(shù)名=參數(shù)值
響應(yīng)消息數(shù)據(jù)格式

響應(yīng)行

組成


協(xié)議/版本 響應(yīng)狀態(tài)碼 狀態(tài)碼的描述

響應(yīng)狀態(tài)碼:服務(wù)器高速客戶端瀏覽器本次請(qǐng)求和響應(yīng)的一個(gè)狀態(tài)


分類:
  1xx: 服務(wù)器接收客戶端消息,沒(méi)有接收完成,等待一段時(shí)間后,發(fā)送1xx
  2xx: 成功   代表狀態(tài)碼:200
  3xx: 重定向 代表狀態(tài)碼:302(重定向) 304(訪問(wèn)緩存)
  4xx: 客戶端錯(cuò)誤 代表狀態(tài)碼:404(請(qǐng)求路徑錯(cuò)誤) 405(請(qǐng)求方式?jīng)]有對(duì)應(yīng)的doXXX方法)
  5xx: 服務(wù)器錯(cuò)誤 代表狀態(tài)碼:500(服務(wù)器內(nèi)部出現(xiàn)異常)

響應(yīng)頭

格式


頭名稱:值

常見(jiàn)的響應(yīng)頭


1.Content-Type:服務(wù)器告訴客戶端響應(yīng)體數(shù)據(jù)格式以及編碼格式
  例:Content-Type:text/html;charset=UTF-8
2.Content-disposition:服務(wù)器告訴客戶端以什么格式打開(kāi)響應(yīng)體數(shù)據(jù)
  *值:  
     *in-line:默認(rèn)值,在當(dāng)前頁(yè)面內(nèi)打開(kāi)
     *attachment;filename=xxx:以附件形式打開(kāi)響應(yīng)體.文件下載

響應(yīng)空行

響應(yīng)體:傳輸?shù)臄?shù)據(jù)


響應(yīng)字符串格式Request對(duì)象Request和Response對(duì)象的原理

1.tomcat服務(wù)器會(huì)根據(jù)請(qǐng)求url中的資源路徑,創(chuàng)建對(duì)應(yīng)的Servlet對(duì)象

2.tomcat服務(wù)器會(huì)創(chuàng)建request和response對(duì)象;request對(duì)象中封裝消息數(shù)據(jù)

3.tomcat將request和response兩個(gè)對(duì)象傳遞給service方法,并調(diào)用service方法

4.程序員可以通過(guò)request對(duì)象來(lái)獲取請(qǐng)求消息數(shù)據(jù);可以通過(guò)response對(duì)象來(lái)設(shè)置響應(yīng)數(shù)據(jù)

5.tomcat在給瀏覽器作出響應(yīng)之前,會(huì)從response對(duì)象中獲取消息響應(yīng)數(shù)據(jù)并響應(yīng)給瀏覽器

注意:


1) request和response對(duì)象是由服務(wù)器創(chuàng)建的,我們來(lái)使用它們
2) request對(duì)象是來(lái)獲取請(qǐng)求消息,response對(duì)象來(lái)設(shè)置響應(yīng)消息
Requset對(duì)象的繼承結(jié)構(gòu)

ServletRequset(接口)->HttpServletReqest(接口)->RequestFacade(tomcat寫(xiě)的實(shí)現(xiàn)類)


Request對(duì)象的功能獲取請(qǐng)求消息數(shù)據(jù)

1.獲取請(qǐng)求行數(shù)據(jù)


-請(qǐng)求行數(shù)據(jù):  GET /day14/demo01?name=zhangsan HTTP/1.1
-獲取方法:
1)獲取請(qǐng)求方式: GET
  *String getMethod()
2)獲取虛擬目錄**: /day14
  *String getContextPath()
3)獲取Servlet路徑  /demo1
  *String getServletPath()
4)獲取請(qǐng)求參數(shù)  /name=zhangsan
  *String getQueryString()
5)獲取請(qǐng)求的URI**: /day14/demo1
  *String getRquestURI :/day14/demo1
  *StringBuffer getRequestURL: http://localhost/day14/demo1
6)獲取瀏覽器的協(xié)議及版本 HTTP/1.1
  *String getProtocol()
7)獲取客戶機(jī)的IP地址
  *String getRemoteAddr()
注意:
URL:統(tǒng)一資源定位符 http://localhost//day14/demo1
URI:統(tǒng)一資源標(biāo)識(shí)符
day14/demo1
URL的范圍比URI的范圍小

2.獲取請(qǐng)求頭數(shù)據(jù)


1) String getHeader(String name):通過(guò)請(qǐng)求頭名稱獲取請(qǐng)求頭的值
2) Enumeration<String> getHeadernames():獲取所有請(qǐng)求頭的名稱
   Enumberation 和 Iterator類似:
     hasMoreElement()  <-->  hasNext()用于判斷
     nextElement()     <-->  next() 用于獲取下一下元素

3.獲取請(qǐng)求體數(shù)據(jù)只有POST請(qǐng)求方式,才有請(qǐng)求體,在請(qǐng)求體中封裝了POST請(qǐng)求的請(qǐng)求參數(shù)


步驟:
1).獲取流對(duì)象
  *BufferedReader getReader():獲取字符輸入流
  *ServletInputStream getInputStream():獲取字節(jié)輸入流
2).從流對(duì)象中獲取數(shù)據(jù)

4.總結(jié):常用的方法

1)獲取虛擬目錄:getContextPath()

2)獲取請(qǐng)求URI:getRequestURI()/getRequestURL()

3)獲取請(qǐng)求頭:getHeader(String name)


==其他功能==

==1.獲取請(qǐng)求參數(shù)(通用方式)==


1)String getParameter(String name):根據(jù)參數(shù)名稱獲取參數(shù)值
2)String[] getParameterValues(String name): 根據(jù)參數(shù)名稱獲取參數(shù)值的數(shù)組,多用于復(fù)選框
  如:hobby=xx&hobby=game
3)Enumeration<String> getParameterNames():獲取所有請(qǐng)求的參數(shù)名稱
4)Map<String,String[]> getParameterMap():獲取所有參數(shù)的map集合
- 中文亂碼問(wèn)題
   *get方式: tomcat8 已經(jīng)將get方式亂碼問(wèn)題解決了
   *post方式: 會(huì)亂碼
        解決:在獲取參數(shù)前,設(shè)置request編碼
        request.setCharacterEncoding("utf-8")

==2.請(qǐng)求轉(zhuǎn)發(fā):一種在服務(wù)器內(nèi)部的資源跳轉(zhuǎn)的方式==

步驟


1)通過(guò)request對(duì)象獲取請(qǐng)求轉(zhuǎn)發(fā)器對(duì)象:RequestDispatcher getRequestDispatcher(String path)
2)使用RequestDispatcher對(duì)象來(lái)進(jìn)行轉(zhuǎn)發(fā):forward(ServletRequest request,ServletResponse)

特點(diǎn)


1) 瀏覽器地址欄路徑不發(fā)生變化2) 只能轉(zhuǎn)發(fā)至當(dāng)前服務(wù)器的內(nèi)部資源中3) 轉(zhuǎn)發(fā)是一次請(qǐng)求

==3.數(shù)據(jù)共享==

域?qū)ο?一個(gè)有作用范圍的對(duì)象,可以在范圍內(nèi)共享數(shù)據(jù)

request域:代表一次請(qǐng)求的范圍,一般用于請(qǐng)求轉(zhuǎn)發(fā)的多個(gè)資源中去共享數(shù)據(jù)

request資源共享方法


1) void setAttribute(String name ,Object obj) :存儲(chǔ)數(shù)據(jù)2) Object getAttribute(String name) 通過(guò)鍵來(lái)獲取值3) void removeAttribute(String name) 通過(guò)鍵來(lái)移除鍵值對(duì)

==4.獲取ServletContext對(duì)象==


-ServletContext getServletContext()
BeanUtils

用于封裝JavaBean


JavaBean

JavaBean:標(biāo)準(zhǔn)的Java類

類必須被public修飾

必須提供空參的構(gòu)造器

成員變量必須使用private修飾

提供公共的setter和getter方法

JavaBean的功能:封裝數(shù)據(jù)


概念

成員變量

屬性:setter和getter方法截取后的產(chǎn)物


例如:getUsername()-->Username-->username大部分情況下屬性和成員變量是一樣的
BeanUtils的方法

1.setProperty(javaBean,"屬性名","值")

2.getProperty(javaBean,"屬性名")

3.populate(javaBean,屬性集map)


Response對(duì)象

功能:設(shè)置響應(yīng)消息

設(shè)置響應(yīng)行

設(shè)置響應(yīng)頭

設(shè)置響應(yīng)體


設(shè)置響應(yīng)行1.格式HTTP/1.1 200 ok2.設(shè)置狀態(tài)碼setStatus(int sc)
設(shè)置響應(yīng)頭

setHeader(String name, String value)

設(shè)置響應(yīng)體

使用步驟


1.獲取輸出流  *字符輸出流:PrintWriter getWriter()  *字節(jié)輸出流:ServletOutputStream getOutputStream()2.使用輸出流將數(shù)據(jù)輸出到客戶端瀏覽器
案例完成重定向(redirect)

代碼實(shí)現(xiàn)


//1.設(shè)置狀態(tài)碼為 302response.setStatues(302);//2.設(shè)置響應(yīng)頭locationresponse.setHeader("location","/虛擬路徑/資源路徑")

簡(jiǎn)單的重定向方法


resonpse.sendRedirect("/虛擬路徑/資源路徑")

重定向的特點(diǎn)


1. 地址欄發(fā)生變化2. 重定向可以訪問(wèn)其他服務(wù)器的資源3. 重定向是兩次請(qǐng)求

路徑寫(xiě)法:


1.相對(duì)路徑: 通過(guò)相對(duì)路徑不可以確定唯一資源    * 以 ./開(kāi)頭 表示當(dāng)前路徑    * 以 ../開(kāi)頭 表示后退一級(jí)    *規(guī)則: 找到當(dāng)前資源和目標(biāo)資源之間的相對(duì)位置關(guān)系 2.絕對(duì)路徑: 絕對(duì)路徑可以確定唯一資源   在這里可以寫(xiě)為/虛擬路徑/資源路徑

在瀏覽器輸出字符數(shù)據(jù)

代碼實(shí)現(xiàn)


//1.獲取字符輸出流PrintWriter pw = resp.getWriter();//2.向?yàn)g覽器寫(xiě)出字符數(shù)據(jù)pw.write("<h1>你好,response</h1>");此實(shí)現(xiàn)會(huì)出現(xiàn)亂碼,因?yàn)楂@取的流的默認(rèn)編碼為IOS-8859-1

亂碼問(wèn)題


上一個(gè)代碼實(shí)現(xiàn)會(huì)出現(xiàn)亂碼問(wèn)題
解決方法:在獲取流之前設(shè)置編碼和web解碼方式
   //1.設(shè)置response的編碼格式(默認(rèn)為IOS-8859-1)
   //response.setCharacterEncoding("編碼格式")
   //2.使用response設(shè)置響應(yīng)頭,要求使用特定的編碼格式去解碼
   response.setHeader("content-type","text/html;charset=編碼格式")
簡(jiǎn)單方法:
   response.setContentType("text/html;charset=編碼格式")
   
   注意:使用語(yǔ)句2,就可以設(shè)置編碼格式,和瀏覽器的解碼格式.第1步就可以不用寫(xiě)了



作者:黑馬程序員JavaEE培訓(xùn)學(xué)院
首發(fā):http://java.itheima.com/

分享到:
在線咨詢 我要報(bào)名
和我們?cè)诰€交談!