天天看點

【Java Web學習筆記】Servlet

Servlet

(1)Servlet與Tomcat的關系

圖略

(2)概念

不能獨立運作,要依賴于Web容器的一種Java伺服器程式。

(3)Servlet開發的三種方式

需求:

1.進行Servlet開發,tomcat伺服器向用戶端發送資訊。

步驟:

1.建立web應用。

2.将Servlet部署到web.xml

1. 實作Servlet接口

public class FirstServlet implements Servlet
{   //該函數用于Servlet初始化,并将其裝載記憶體中
    //該函數隻運作一次,需要在server.xml檔案中進行配置<load-on-start>.
    public void init(ServletConfig config)throws ServletException
    {   }
    //得到ServletConfig對象
    public ServletConfig getServletConfig()
    {   }
    //該函數是服務函數,業務邏輯代碼就是在這裡編寫
    //每次啟動服務都會調用該函數
    //當調用doGet或者doPost才構造ServletRequest和ServletResponse對象
    public void service(ServletRequest req,ServletResponse res)
throws ServletException,java.io.IOException
    {   }
    //擷取Servlet的配置資訊
    public java.lang.String getServletInfo()
    {   }
    //該函數用于銷毀Servlet
    //隻運作一次
    public void destroy(){  }
}
           

2. 繼承GenericServlet

相對于Servlet來說,是需要繼承server函數即可。

GenericServlet抽象類,給出了一些設計servlet的一些骨架,定義了servlet的生命周期,還有一些得到的名字,配置初始化參數的方法,其設計是和應用層協定無關的。

3. 繼承HttpServlet(常用)

public class FirstHttpServlet extends HttpServlet
{
    //兩個底層都代用了server函數
    //Http協定中的get請求和post請求
    //與<form action="送出給?" method="get ro post?"/>中有關
    protected void doGet(HttpServletRequest req,HttpServletResonse resp)
        throws ServletException,java.io.IOException
    {
        resp.getWriter().println("HttpServlet");
    }
    protected void doPost(HttpServletRequest req,HttpServletResonse resp)
        throws ServletException,java.io.IOException
    {
        resp.getWriter().println("HttpServlet");
    }
}
           

(4)Servlet細節

1. Servlet的部署

<!—進行servlet的注冊-->
<!-在android開發中的每個Activity都必須要注冊—>
<servlet>
    <!--servlet-name 可以自定義,但是預設為類名-->
    <servlet-name>MyServlet</servlet-name>
    <!--servlet-class 用于指定servlet存放在哪一個包中(包名+類名),一定要明确-->
    <servlet-class>name.liushiyao.myservlet.MyServlet</servlet-class>
</servlet>

<!-- servlet 的映射(對一個已經注冊的Servlet的映射)-->
<!--一個注冊号的Servlet可以被多次映射-->
<servlet-mapping>
    <!-- 該servlet-name 一定要去上面的servlet-name 相同-->
    <servlet-name>MyServlet</servlet-name>
    <!--url 的資源檔案名(斜杠必須有)-->
    <url-pattern>/ab</url-pattern>
</servlet-mapping>
           

注:

1. 如果url中沒有加“/”運作時會出現錯誤。

2.在IDEA中(應該是JavaEE6的新特性,使用了annotation),可以使用@WebServlet(name = “LastTime”, urlPatterns ={“/LastTime”,”/LastTime2”})進行WebServlet的映射,且可以實作多對一映射,而不需要在web.xml中進行注冊。

2. 通配符

1) /*
    2) *.拓展名
            注:1)比2)優先級高。
           

3. 單例多線程

當Servlet被第一通路後,就被加載到記憶體中,以後該執行個體對各個請求都是用的是同一個内容。JSP也是單例模式。

servlet是多線程的,沒有采用同步機制,是不安全的。同一個Servlet可以同時處理多個用戶端的請求,比如同時有兩個使用者A和使用者B登入時,會啟動兩個負責登入的Servlet線程,并通過觸發Service方法來處理請求。在兩個線程中,接收到的使用者名是不同的,也就是說,多線程裡的Servlet,可能其中的變量不相同。

4. servlet中的配置

需求:當我們的網站啟動的時候,可能會要求初始化一些資料(建立臨時表),或者要求定時備份資料,發送郵件。
解決辦法:可以通過<load-on-startup>配合,線程知識搞定。
    通過配置<load-on-startup>,啟動一個servlet中的init函數,且隻運作一次。
           

在web.xml檔案中進行配置

<!-- 配置init啟動的優先級(必須配置,否者init()不會執行) -->
<load-on-startup>1</load-on-startup>
<!—數值代表啟動的順序-->
           

【模拟定時發送電子郵件】

//用于發送電子郵件的線程
public class Send extends Thread
{
    @Override
    public void run() {
        int count = ;
        while(true)
        {
            try {
                //====每隔10s發送電子郵件
                Thread.sleep(*);
                System.out.println("第"+(++count)+"份郵件被發送");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
//使用init函數進行線程的啟動
public void init() throws ServletException {
        // Put your code here
        System.out.println("ServletInit 的init函數運作。。。");
        Send send = new Send();
        send.start();
}
           

ServletConfig對象

1. 用途

用于讀取Servlet的一些配置資訊。
           

在web.xml檔案中。

<!-- 使用UTF-8編碼 -->
<!-- 局部servlet有效 -->
<init-param>
    <param-name>encoding</param-name>
    <param-value>utf-8</param-value>
</init-param>
           

注:String contextString = this.getServletConfig.getInitParameter(“encoding”);

要使被所有的servlet讀取,應該在之外定義:

<!—所有servlet有效 -->
<context-param>
    <param-name></param-name>
    <param-value></param-value>
</context-param>
           

注:通過String contextString = this.getServletContext().getInitParameter(“encode”);擷取

因為該屬性屬于全局變量,而ServletContext也是屬性全局的,是以要通過getServletContext擷取,而不是通過getServletConfig擷取。

【擷取ServletConfig中的資料】

1. 擷取單一的資料在Servlet中

response.setContentType("text/html;charset=utf-8");//預設編碼
PrintWriter printWriter = response.getWriter();
//擷取param參數内容
String encodingString  = this.getServletConfig().getInitParameter("encoding");
request.setCharacterEncoding(encodingString);
printWriter.println(encodingString);
printWriter.close();
           
  1. 擷取所有的資料
//擷取所有的param的enum對象
Enumeration<String> enum1 = this.getServletConfig().getInitParameterNames();
while (enum1.hasMoreElements()) {
    String string = (String) enum1.nextElement();
    System.out.println(string);
    System.out.println(this.getServletConfig().getInitParameter(string));
}
           

HttpResponse對象

所有的資訊多會封裝到response中,傳回給web服務。web伺服器會将response資訊進行拆解,形成http相應資訊,傳回給浏覽器。
           

1. getWrite();與getOutputStream()

注:一個是字元流,一個是位元組流。雖然說兩者可以互相轉換,但是針對不同的資料針對性的使用。
           

兩個流不能同時使用。否則會出現如下異常:

java.lang.IllegalStateException: getWriter() has already been called for this response

org.apache.catalina.connector.Response.getOutputStream(Response.java:605)

org.apache.catalina.connector.ResponseFacade.getOutputStream(ResponseFacade.java:197)

name.liushiyao.userlogin.Download.doGet(Download.java:37)

javax.servlet.http.HttpServlet.service(HttpServlet.java:621)

javax.servlet.http.HttpServlet.service(HttpServlet.java:722)

注:會自動關閉IO,是以不能同時出現getWrite();getOutputStream();

2. sendRedirect();

sendRedirect( 重定向)發生在浏覽器的跳轉,伺服器根據邏輯,發送一個狀态碼,告訴浏覽器去重新請求那個位址。

實作界面的跳轉,并可以随帶字元串資訊。

1. 實作跳轉:

//執行調轉到登入成功界面(java中其中一種跳轉方式)
//"/web應用名/servlet"
response.sendRedirect("/UserLogin/MainFrame");
           
  1. 攜帶字元串資訊:
response.sendRedirect("/UserLogin/MainFrame?uname="+
name+"&upassword="+password
           

注:url與字元串資訊之間通過“?”進行連接配接。

不同的字元串之間通過“&”連接配接。

sendRedirect不能實作對象的傳遞。但是可以通過session傳遞(也不能說是“傳遞”,隻是在伺服器記憶體中存儲的session)。

User u = new User(name,password);
request.getSession().setAttribute("u",u);
           
  1. 擷取對象:
User us = (User)request.getSession().getAttribute("u");
    out.println(us.getName()+"||"+us.getPassword());
           

HttpRequest對象

該對象表示浏覽器的請求,即http請求資訊。但web伺服器等到該請求後,會把浏覽器請求的資訊封裝成HttpRequest對象。是以可以通過該對象擷取使用者的各種請求資訊。
           

1. getRequestURL();

String uri = request.getRequestURI();
String url = request.getRequestURL().toString();
System.out.println("uri"+uri);
System.out.println("url"+url);
           

輸出:

uri  /RequestDemo/RequestInfo
url  http://localhost:8080/RequestDemo/RequestInfo
           

2. getQueryString();

以GET方法擷取參數資訊(參數+值)。
String quary = request.getQueryString();
    System.out.println("query:"+quary);
           

輸出:

query:name=123

注:這個的參數時url後面帶的所有資訊,而request.getParameter(“age”);則是當個屬性所帶的值

3. getRemoteAddr();

可以擷取使用者的ip位址。(利用該函數可進行ip封殺)

4. getRemotePort();

擷取使用者的端口。
int localport = request.getLocalPort();
int port = request.getRemotePort();
System.out.println("localport:"+localport);
System.out.println("port:"+port);
           

5. getParameterValues();

獲得傳過來的參數名相同的一個數組;

String[] string = request.getParameterValues(“checkbox”);

6. getRequestDispatcher();

request轉向函數。

request.getRequestDispatcher("/MainFrame").forward(request, 
response);
           

實作原理:

  1. sendReDirect與forward的差別?
    forward(轉向):發生在伺服器的跳轉,伺服器請求資源,直接通路目标位址的URL,把URL的響應再發送給浏覽器,浏覽器根本不知道伺服器發送的内容是從哪裡來的,是以位址欄中的URL還是原來的。

答:(1)叫法不同:sendReDirect()叫重定向(轉發);forward叫轉向。

(2)實際發送的位置不同:sendReDirect發生在浏覽器;forward發生在伺服器

(3)用法不同:response.sendReDirect(“/web應用/資源URI”);需要加‘/web應用名’(根據其原理可以知道)

request.getRequestDispather(“/資源URI”).forward(request,response);

不需要加web應用名

(4)範圍不同:sendReDirect 與浏覽器之間

forward 與web伺服器之間。

注:1.所謂的一次http請求:就是沒有重回到浏覽器或者重新啟動則叫為“一次http請求”。

2.request.setAttribute(“key”,”123”);//存儲此請求中的屬性。在請求之間重置屬性。此方法常常與 RequestDispatcher 一起使用。

3. //效果同request.getRequestDispather request.getServletContext().getRequestDispatcher(“/OtherServlet”).forward(request,response);

4. 使用sendReDirect可以防止重新整理帶來的再次通路servlet(因為sendReDirect需要web應用名)

Cookie

1. 概念

cookie是用戶端技術,伺服器把每個使用者的資料以cookie的形式寫給使用者各自的浏覽器。 Cookie包含屬性(String)和值(String)。

注:1. Cookie隻能儲存字元串(鍵值對)

2. 用戶端在發送Http請求時,會攜帶該Web應用的Cookie。

3. Cookie必須設定setMaxAge,否則Cookie在浏覽器關閉時被銷毀(setMaxAge(0)則銷毀Cookie)。

4. 可以被多個浏覽器共享。

5. 如果Cookie重名,會覆寫之前的資料。

6. 當web建立多個Cookie時,會儲存在同一個檔案中,并且存在時間可以不一樣。

7. 建立Cookie時禁止使用“ 空格、逗号”等。

2. Cookie的用途

賬号和密碼的儲存(需要加密)、使用者的喜好、設定等等。

3. Cookie的限制

一個浏覽器隻能存放300個Cookie,一個web站點最多存儲20個Cookie,且 每個大小限制在4K。

4.禁用Cookie

如果使用者禁用Cookie,可以使用URL重寫技術跟蹤回話。

5. Cookie的生命周期

Cookie的生命周期指的是累積時間,即從開始建立時間到設定的結束時間的長度。

Session

1. 概念

Session(域對象)是伺服器端技術,當使用者打開浏覽器,通路伺服器。伺服器為每一個浏覽器提供一個Session對象。 Session包含屬性(String)和值(Object)。

注:1. 隻要不關閉浏覽器,不同的頁面就會處于同一個Session中,而這個Session預設的生存時間是1800s(30分鐘,可以在web.xml中修改)。

2. session是存放在伺服器的記憶體中的

3. session被特定的一個浏覽器所獨享

4. 當同一個session中的屬性名相同時則會覆寫前一個屬性值

2. Session的生命周期

  1. 在web.xml中可以進行生存時間的設定
<session-config>
    <session-timeout>20</session-timeout>
</session-config>
           
  1. 使用httpSession.setMaxInactiveInterval(60);

    //該時間設定的是“發呆時間”—使用者沒有操作Session的時間

  2. 當關閉或重新開機Tomcat時都會删除Session(Session是儲存在記憶體中的)或者使用 invalidate(); 删除Session中所有的屬性和對象(強制性的,用于安全退出)
  3. 單獨删除一個對象

    httpSession.removeAttribute(“name”);

3. Session的原理

伺服器如何為特定的浏覽器配置設定特定的Session?

答:通過ID

實作流程:

1. 當浏覽器第一次通路Servlet時,Cookie中是沒有攜帶JSESSIONID

(Cookie JSESSIONID=D7561FE5F83BACF4E0091BCDADE04078),

2. 通路Servlet之後,會生成Session并配置設定Session ID,通過Cookie寫入浏覽器中;

3. 當使用者再次通路Servlet,http請求會攜帶帶有JSESSIONID的cookie,此時伺服器就能準确的知道該浏覽器是與那個Session相關聯的。

6. Cookie與Session的差別?

①存在的位置不同:

Cookie:存在用戶端(臨時檔案夾)

Session:存在伺服器的記憶體中(一個Session域對象為一個使用者浏覽器服務)

②安全性

Cookie:是以明文方式存放在用戶端,安全性較弱(可以通過加密的方式進行加密)

Session:是存在伺服器中的記憶體中,安全性較強。、

③網絡通信量

Cookie:會傳遞資訊給伺服器(每次在Http請求中都會攜帶Cookie,是以會增加網絡壓力)(是以擷取Cookie時是從Request中擷取 的)

Session:session是存在伺服器的記憶體中的,是以不存在網絡通信壓力問題。

④生命周期

Cookie:是累積時間,即為絕對時間

Session:是“發呆時間”,即相對時間(當浏覽器沒有對session進行操作時的間隔時間)。session失效是指無法通路session的屬性(API解釋:使此會話無效,然後取消對任何綁定到它的對象的綁定。)。相關應用(安全退出)

⑤通路範圍

Cookie:浏覽器共享

Session:浏覽器獨享

注:Session會占用伺服器的記憶體,是以要根據實際情況進行取舍。

ServletContext

1. 概念

Web容器在啟動時,它會為每一個Web應用程式都建立一個對應的ServletContext對象,它代表web應用。
注:可以被多個使用者共享(同一個Web應用中的所有Servlet)
           

2. 擷取ServletContext

//方法一(通過this)

ServletContext servletContext = this.getServletContext();

//方法二(通過getServletConfig)

ServletContext servletContext1 = this.getServletConfig().getServletContext();

3. 添加ServletContext屬性

servletContext.setAttribute(“name”,”劉石堯”);

4. 讀取ServletContext屬性

String string = (String) servletContext.getAttribute(“name”);

5. 删除ServletContxt 屬性

if (servletContext.getAttribute(“name”) != null){

servletContext.removeAttribute(“name”);

out.println(“已删除 name”);

}

6. 使用ServletContext的使用原則

需要資料共享,而且存儲的大小不大又不想出入資料庫,可以使用ServletContext。

7. ServletContext的生命周期

ServletContext是長期存放在伺服器中的記憶體中的,所有不将過大的資料存放在ServletContext中。

8.擷取web.xml中的設定參數

會話跟蹤

會話跟蹤是一種靈活,輕便的機制,使Web上的狀态變成成為可能。

可是使用session,Cookie,位址重寫和隐藏域實作。

JSP

JSP九大内置對象

内置對象 對象名稱 類型 作用域
request 請求對象 javax.servlet.ServletReques Request
response 響應對象 javax.servlet.SrvletResponse Page
pageContext 頁面上下文對象 javax.servlet.jsp.PageContext Page
session 會話對象 javax.servlet.http.HttpSession Session
application 應用程式對象 javax.servlet.ServletContext Application
out 輸出對象 javax.servlet.jsp.JspWriter Page
config 配置對象 javax.servlet.ServletConfig Page
page 頁面對象 javax.lang.Object Page
exception 例外對象 javax.lang.Throwable page
注:“exception” 對象則代表了JSP檔案運作時所産生的例外對象,此對象不能在一般JSP檔案中直接使用,而隻能在使用了“<%@ page isErrorPage=”true “%>”的JSP檔案中使用。

作用域

作用域 範圍 說明
page 有效範圍隻在目前jsp頁面裡 從把變量放到pageContext開始,到jsp頁面結束,你都可以使用這個變量。
request 有效範圍是目前請求周期 所謂請求周期,就是指從http請求發起,到伺服器處理結束,傳回響應的整個過程。在這個過程中可能使用forward的方式跳轉了多個jsp頁面,在這些頁面裡你都可以使用這個變量。
session 有效範圍是目前會話 所謂目前會話,就是指從使用者打開浏覽器開始,到使用者關閉浏覽器這中間的過程。這個過程可能包含多個請求響應。也就是說,隻要使用者不關浏覽器,伺服器就有辦法知道這些請求是一個人發起的,整個過程被稱為一個會話(session),而放到會話中的變量,就可以在目前會話的所有請求裡使用。
application 有效範圍是整個應用 整個應用是指從應用啟動,到應用結束。我們沒有說“從伺服器啟動,到伺服器關閉”,是因為一個伺服器可能部署多個應用,當然你關閉了伺服器,就會把上面所有的應用都關閉了。

  application作用域裡的變量,它們的存活時間是最長的,如果不進行手工删除,它們就一直可以使用。

  

注:application裡的變量可以被所有使用者共用。如果使用者甲的操作修改了application中的變量,使用者乙通路時得到的是修改後的值。這在其他scope中都是不會發生的,page, request,session都是完全隔離的,無論如何修改都不會影響其他人的資料。

jsp注釋

1. <%-- JSP中的注釋,看不見 --%>
2.  // 注釋,看不見
3.   /*
   注釋,看不見
 */
4. <!--顯式注釋-->
           

JSP文法

腳本

<% java代碼 %>:在<%%>中定義局部變量或者調用方法,但不能定義方法。

<%!%>:可以在<%!%>中聲明方法、屬性、全局變量。

<%=%>:稱作jsp表達式,用于将已經聲明的變量或者表達式輸出到網頁上面。

include指令

靜态include:

從外部引入一個jsp檔案(隻含指令和内容本身,不需要body等其他内容),編譯成同一個servlet。屬于靜态引入。

動态include:

<jsp:include />
           

注:動态引入,會翻譯成兩個servlet。是以被引入的檔案可以包含等内容。