Servlet 和 JSP 基礎

--Servlet技術是使用Java語言開發的一套組件規範,
    是由一個單獨的線程來處理的。
--組件是對部分功能的實現,不能單獨運行,
    對這些組件進行管理、創建、銷燬的運行環境稱爲容器。
--這些容器有:Tomcat、Weblogic、JBoss等
--Servlet 的實現
    1)實現接口Servlet
    2)實現抽象類GenericServlet
    3)實現抽象類HttpServlet
    -- HttpServlet的父類——>GenericServlet 實現了接口 -->Servlet
>>>>>>>>>>>>1.報錯和解決<<<<<<<<<<<<<<<<<<<<<<
1. 404錯誤產生原因及解決方法
    --產生原因:Web服務器(容器)根據請求地址找不到對應資源
>>以下情況會出現404錯誤
    1)輸入的地址有誤(應用名大小寫不正確,名稱拼寫不正確)
    2)在web.xml文件中<servlet>和<servlet-mapping>中的兩個<servlet-name>不一致
    3)沒有將工程部署到Tomcat的webapps下面
    4)Web工程部署時的結構沒有遵循Servlet的規範
2. 405錯誤產生原因及解決方法
    --產生原因:容器找不到service方法來處理請求。
>>以下情況容器都將視爲沒有找到service()方法
    1)service方法名寫錯,字母順序不對或大小寫錯誤
    2)service方法參數類型與標準不一致,或參數順序與標準不一致。
        一定是先HttpServletRequest,然後是HttpServletResponse類型
    3)service方法異常、返回值類型與標準不一致,
        一定是拋出ServletException、IOException。返回值類型是void。
3. 500錯誤產生原因及解決方法
    --錯誤原因:請求的Servlet在執行service方法的過程中出現了錯誤,
        程序不能繼續運行了
>>以下情況容器都將視爲500的一種情況:
    1)Servlet沒有繼承HttpServlet或實現Servlet接口
    2)web.xml文件中的<servlet-class>寫錯,與真正的包名類名不符
    3)service方法中的代碼運行時拋出異常

>>>>>>>>>>>>>>>>2.HTTP協議<<<<<<<<<<<<<<<<<<<<<<
--HTTP協議是HyperText Transfer Protocol,即超文本傳輸協議 
--由W3C指定的一種應用層協議
--規範瀏覽器和web服務器如何通信及通信的數據格式
>>>一次請求一次連接,儘量降低服務器的壓力
1.HTTP如何通信
    1)建立連接
    2)請求數據
    3)響應數據
    4)關閉連接
2.數據包格式:
  2.1請求包數據
    --請求行:請求基本的信息
      --請求方式+請求資源路徑+協議類型+版本
    --消息頭:請求數據的描述信息
    --實體內容:請求的數據
  2.2響應包數據
      --狀態行:響應基本的信息
      --協議類型+版本+狀態碼+狀態描述
    --消息頭:響應數據的描述信息
    --實體內容:響應的數據

>>>>>>>>>>>>>>>>3.請求方式GET和POST<<<<<<<<<<<<<<<<<<<<<<
1.GET
    --使用請求路徑傳參,將參數附加在路徑上發送服務器
    --參數在傳遞過程中可見,隱私性差
    --請求路徑空間有限,只能攜帶少量參數(<2K)
     >>所有默認的請求都是GET請求
2.POST
    --使用實體內容傳參
    --參數在傳遞過程中不可見,隱私性好
    --實體內容專門用來傳參,大小沒有限制
    >>在form上增加method="post"時
3.獲取GET和POSt傳到服務器的參數
    --服務器端處理GET和POST請求是沒有分別的
    --使用方法:
        --req.req.getParameter(表單name屬性) 返回字符串
        --req.getParameterValues(表單name屬性) 返回字符串數字組
            --如果同一個name 對應多個值就用此方法
            --即用於獲取表單中一組參數名相同的控件提交的數據組
4.解決亂碼問題
  4.1 解決服務器端亂碼
    --方案1:
        --get/post:讓Serverlet接收亂碼String,
            用ISO8859-1將其還原稱byte,再用UTF-8將其轉成String
            --byte[] bs = user.getBytes("iso8859-1");
            --user = new String(bs,"utf-8");
        --優點:萬能   --缺點:麻煩
    --方案2:
          get:修改Tomcat的配置文件server.xml,65行左右
          --優點:簡單
    --方案3:
        post: 在獲取請求參數之前,設置
            --req.setCharacterEncoding("utf-8");
        優點:簡單
    ◆注:一般採用後面兩種方式
  4.2 解決瀏覽器端亂碼
      --設置發送的編碼規則
          --res.setContentType("text/html;charset=utf-8");
5.表單的action路徑問題
--表單絕對路徑:
    有固定格式:/項目名/Servlet路徑
--表單相對路徑:
    --沒有固定格式,需要寫出當前訪問和目標Servlet之間的相對位置
    --因爲打開網頁和訪問Servlet都由瀏覽器實現,
    --站在瀏覽器的角度來說:
        --網頁訪問路徑:/Servlet2/register.html
        --Servlet訪問路徑:/Servlet2/register
        --因爲他們是平級,所以相對路徑是register

>>>>>>>>>>>>>>>>4.重定向<<<<<<<<<<<<<<<<<<<<<<
1、重定向:**重要**
>>實用場景
    1)經典實用場景:(如百度搜索)
        --不同服務器之間的跳轉
    2)擴展使用場景
        --解決1個項目內,2個獨立組件之間跳轉問題
    3)重定向的一般使用場景
        --增加、修改、刪除後重定向到查詢。
--res.sendRedirect(目標地址);
2、路徑
--指部署代碼的訪問路徑    
--靜態資源(html/css/js/img等)就是文件在Tomcat存儲的位置
--動態資源(servlet)就是Servlet的訪問路徑(網名)
--項目名
    --req.getContextPath();
--網頁名
    --req.getServletPath();
--在項目中的網頁的絕對路徑
    --req.getRequestURI();
--外網訪問全路徑
    --req.getRequestURL();
--在web中
    URL:資源的真名
    URI:資源的名稱
    --URI包含URL
3.Servlet訪問路徑有3種方式:
    不同的方式其處理請求的能力不同
    1)精確匹配(/abc)
        --只有訪問/abc路徑能處理請求
        --此Servlet只能處理一個請求
    2)通配符(/*)
        -所有的路徑都可以訪問此Servlet
        -此servlet能處理所有請求
    3)後綴(*.hi)
        --所有以hi爲後綴的路徑都可以訪問此Servlet
        --此Servlet可以處理多個請求
        --不允許以斜線開頭

>>>>>>>>>>>>>>>>>>servlet特性<<<<<<<<<<<<<<<<<<<
1.servlet生命週期
    1)實例化(new )
    2)初始化(init())
    3)就緒
    4)銷燬(destory())
>>默認第一次訪問Servlet時會創建並初始化它
>>可以修改成啓動Tomcat時就創建並初始化它
>>對於某個類型的Servlet來說,第1,2,4步只會執行一次,
    第三步可以執行多次,因此某個類型Servlet在tomcat內
    只有一個實例,即單例。

2.  servletconfig 和 ServletContext
    --開發servlet時可能需要讀取一些參數
    --可以自己寫配置文件及工具來設置這些參數
    --也可以直接使用web.xml做配置文件,
        並使用config和context對象做工具來讀取其參數。
    --每個servlet就像一個學生,config就像他的tts賬號。
        即config和servlet是一對一的關係,每個servlet都會有一個config對象。
    --context就是教室,可以爲所有學生服務,
        即context和servlet是一對多的關係,項目中只有一個context,爲所有的servlet服務。
    config:
    <servlet>
          <servlet-name>login</servlet-name>
          <servlet-class>web.LoginServlet</servlet-class>
          <!-- 給當前Servlet預置一個參數,此參數在調用Servlet.init方法之前,被對應的config對象讀取,一個init-param 
          標籤對應一條數據-->
          <init-param>
              <param-name>maxOnline</param-name>
              <param-value>1000</param-value>
          </init-param>
      </servlet>

    --ServletConfig cfg = getServletConfig();
    --String maxOnline = cfg.getInitParameter("maxOnline");

    --config 典型的使用場景:
        1.假設壓偶作一個網遊,網限制在線人數。
        2.在用戶登錄時判斷是否已經達到了上線maxOnline 
        3.該參數贏是可以配置的,並且僅僅是在登錄的Servlet中使用,因此使用config即可。
    --context 典型使用場景:
        1.項目中包含很多查詢功能,如查詢員工,部門等
        2.這些查詢功能一般都有分頁
        3.每頁顯示的行數(size)是需要可配置的
        4.由於該參數多個功能都要公用,所以用context
        --ServletContext ctx = getServletContext();
        --ctx.setAttribute("count", 0);
    --context的特殊用法:
        1.可以在程序運行的任何階段你用它來存取變量
        2.其存儲的變量可以在多個Servlet間共用
        案例:統計網站流量(訪問量)
        
3.Servlet線程安全問題
    1.什麼時候會出現線程安全問題
        --多個線程同時修改一份數據時
        --對象、成員變量存儲在堆中,多線程共用
        --局部變量存儲在棧中,每個線程有自己的棧幀
        >>多個人同時修改對象或成員變量時
    2.如何解決線程安全問題
        --加鎖
        synchronized (this) {
            代碼塊
        }

########################### JSP ################################
--JSP(Java Server Page)是Sun公司制定的一種服務器端動態頁面技術的組件規範,
--以“.jsp”爲後綴的文件中既包含HTML靜態標記用於表現頁面,
--也包含特殊的代碼,用於生成動態內容。
---JSP的實現底層是TOMCAT自動生成一個類來實現Servlet接口,將JSP轉換爲java。
-- #JSP是特殊的Servlet#
1.JSP包含三種類型的Java代碼:
    --JSP表達式(方便輸出)
    --JSP小腳本(完成相對較長的邏輯運算)
    --JSP聲明(添加屬性或方法)(一般不使用)
2.JSP表達式:最終會成爲service()方法中使用out.print語句的輸出
    實例:     <%=3+5%>
            <%=add()%>
            <%=xx.getName()%>
            <%=xx.getName()+“abc”%>
    ◆注意:表達式結束不需要寫分號。
3.JSP小腳本:最終會成爲Servlet中Service方法的一部分
    例:
    <table>
    <%
    List<User> allUser = (List<User>)request.getAttribute(“users“);
    for(User u : allUser){
    %>
        <tr>
            <td> <%=u.getId()%>    </td>
            <td> <%=u.getName()%>  </td>
        </tr>
    <%    }    %>
    </table>
4. JSP頁面中的指令
    --語法:<%@ 指令名  屬性=值 %>
    --常用指令包含以下三種:page、include、taglib
    4.1 page指令
        --可以實現在JSP頁面中導入要用到的Java包,
            也可以對頁面的一些屬性進行設置
        ---例1:
            <%@ page import=“java.util.*,java.sql.*“%>
        ---例2:
            <%@ page contentType=“text/html;charset=utf-8“%>
            <%@ page pageEncoding=“UTF-8“%>
    4.2 include指令
        --主要用於將其他頁面包含在另一個頁面之中
        ---例:<%@ include file=“header.html” %>
    4.3 taglib指令
        --主要用於在JSP中導入JSTL
        --例:<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
5.JSP頁面中的隱含(九個)對象**重要**
    request、
    response、
    out、
    session、
    application(ServletContext)、
    pagecontext、
    page、
    config、
    exception

>>>>>>>>>>>>>>>>>>>>>>>JSP開發要點<<<<<<<<<<<<<<<<<<<<<
1.轉發
  --在Web服務器端處理用戶請求的時候,會有需要多個Web組件配合才能完成的情況。
      一個Web組件(Servlet/JSP)將未完成的處理通過容器轉交給
      另外一個Web組件繼續完成,這個轉交的過程叫做轉發。
    --常見情況是Servlet負責獲取數據,然後將數據轉交給JSP進行展現。
    實現轉發的步驟:
        步驟一:綁定數據到request對象
            request.setAttribute(String name,Object obj);
        步驟二:獲得轉發器
            RequestDispatcher rd = request.getRequestDispatcher(String uri);
        步驟三:實現轉發
            rd.forward(request,response);
    轉發的原理:
    1.請求到達服務器
    2.根據請求信息創建request和response對象
    3.根據請求資源路徑找到對應的Servlet執行處理
    4.Servlet在處理過程中從數據庫獲取到結果信息
    5.Servlet將結果信息綁定在request對象中
    6.Servlet通知容器將req和res對象轉交給list.jsp頁面繼續執行對請求的響應
    7.list.jsp頁面被調用並執行時從傳遞過來的request對象中獲取綁定的數據
        生成結果頁面
    8.服務器將list.jsp頁面的執行結果返回給客戶端。
2.重定向和轉發的區別
    --重定向:瀏覽器發送請求到容器訪問A,A可以發送一個狀態碼302和
        一個Location消息頭到瀏覽器,於是瀏覽器會立即向Location發新的請求。
    --轉發:瀏覽器發送請求到容器訪問A,A可以通知容器去調用B。
        轉發所涉及的各個Web組件會共享同一個request和response對象,
        而重定向不行。
    --說明:當請求到達容器,容器會創建request對象和response對象。
        當響應發送完畢,容器會立即刪除request對象和response對象。
        即,request對象和response對象的生存時間是一次請求與響應期間。
        轉發之後,瀏覽器地址欄的地址不變,重定向會變。
        轉發的地址必須是同一個應用內部某個地址,而重定向沒有這個限制。
        轉發是一件事情未做完,調用另外一個組件繼續做;
        而重定向是一件事情已經做完,再做另外一件事情。

########################### EL和JSTL ################################
>>>爲什麼需要EL和JSTL
    JSP內嵌大量Java代碼,增加了頁面的維護難度,使用簡單的標籤來表現
    複雜的邏輯及簡單的形式表示運算關係就是EL和JSTL出現的原因。
>>>>> EL表達式
1.Bean屬性
    Bean:一個公共的類,按照固定的方式提供屬性的get/set訪問方式。
    1.實現序列化接口
    2.有get/set方法
2.EL表達式實現方式
    --沒有爲name屬性賦過值,頁面輸出“”,不會輸出null
    1)${對象名.屬性名}
        --${user.name}    
        從pageContext、request、session、application中依次查找綁定名爲“user”的對象,找到後調用“getName”方法,將返回值輸出。
    2)${對象名[“屬性名”]} 其他與上面相同
    --對於數組屬性的值可以使用如下表達式訪問:
        ${user.Array[0]}
3.四個預對象
    --EL表達式在取值的時候,會依次調用pageContext、request、
        session、application的getAttribute()方法
4.指定對象的查找範圍
    --例:${sessionScope.user.name}
    --一旦指定了對象所在的範圍,那麼只會在範圍內查找綁定對象,
        不會在找不到的時候再去其他區域中查找了。
    --sessionScope的位置還可以填寫pageScope、requestScope、applicationScope。
5.使用EL表達式獲取請求參數值
    --以下兩種寫法分別等價:
        ${param.username} 與 request.getParameter(“username”);
        ${paramValues.city} 與request.getParameterValues("city");

>>>>> JSTL
1.什麼是JSTL
    Sun 公司 Java 標準規範的 JSTL 由 apache組織負責維護
2.如何使用JSTL
    ①將標籤庫對應的jar包拷貝到WEB-INF/lib目錄下
    ②使用taglib指令在頁面上引入標籤的命名空間和前綴,幫助系統定位對應的類。
    --例:<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
3.c 的核心標籤
    1)if標籤
        <%
            User user = new User();
            user.setName("胡蘿蔔");
            user.setGender("f");
            request.setAttribute("user",user);
        %>
           姓名:${user.name}<br/>
        性別:
        <c:if test="${user.gender =='m'}" var="rs" scope="request">男</c:if>
        <c:if test="${!rs}">女</c:if>    
     2)choose標籤
         --使用choose標籤簡化多個if標籤的判斷
         <%
            User user = new User();
            user.setName("胡蘿蔔");
            user.setGender("x");
            request.setAttribute("user",user);
            %>
        性別:
        <c:choose>
            <c:when test="${user.gender == 'm'}">男</c:when>
            <c:when test="${user.gender =='f'}">女</c:when>
            <c:otherwise>未知</c:otherwise>
        </c:choose>
      3)forEach標籤
          --使用forEach標籤完成對集合的遍歷輸出。
          --其中items屬性爲要遍歷的集合,var屬性爲每次取出來的一個對象,
              varStatus指定當前迭代的狀態
          <table>
            <tr>
                <td>序號</td>
                <td>姓名</td>
                <td>年齡</td>
            </tr>
            <c:forEach items="${users}" var="u" varStatus="s">
                <tr>
                    <td>${s.count}</td>
                    <td>${u.name}</td>
                    <td>${u.age}</td>
                </tr>
            </c:forEach>
        </table>

>>>>>自定義標籤
--如何開發自定義標籤
    1.編寫一個繼承自SimpleTagSupport的Java類:
        import javax.servlet.jsp.tagext.SimpleTagSupport;
        public class HelloTag extends SimpleTagSupport{}
    2.重寫該類的doTag方法,在其中添加處理邏輯:
        import javax.servlet.jsp.JspException;
        import javax.servlet.jsp.JspWriter;
        import javax.servlet.jsp.PageContext;
        import javax.servlet.jsp.tagext.SimpleTagSupport;
        public class HelloTag extends SimpleTagSupport{
                private String info;
                private int qty;
                public void setInfo(String info) {
                    this.info = info;
                }
                public void setQty(int qty) {
                    this.qty = qty;
                }
                @Override
                public void doTag() throws JspException, IOException {
                    PageContext ctx =(PageContext)getJspContext();
                    JspWriter out = ctx.getOut();
                    for(int i=0;i< qty;i++){
                        out.println(info+"<br/>");
                    }
                }
            
        }
    3.在WEB-INF下面新建一個tld文件,用於配置標籤說明文件。代碼如下:
        <?xml version="1.0" encoding="UTF-8" ?>
        <taglib xmlns="http://java.sun.com/xml/ns/j2ee"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
            http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"  
            version="2.0">
        <tlib-version>1.1</tlib-version>
        <short-name>c1</short-name>
        <uri>http://www.tarena.com.cn/mytag</uri>
        <tag>
            <name>hello</name>
            <tag-class>tag.HelloTag</tag-class>
            <body-content>empty</body-content>
            <attribute>
            <name>info</name>
            <required>true</required>
            <rtexprvalue>false</rtexprvalue>
            </attribute>
            <attribute>
                <name>qty</name>
                <required>true</required>
                <rtexprvalue>true</rtexprvalue>
            </attribute>
        </tag>
        </taglib>
    4.標籤在頁面中被引用時的代碼如下:
        <%@taglib uri="http://www.tarena.com.cn/mytag" prefix="c1" %>
        //…  …
        <c1:hello info="hello kitty" qty="${1+5}"/>
    5. 標籤的運行原理
        --容器依據JSP頁面中的uri找到tld文件
            依據標籤中的<c1:hello>hello這個名字找到標籤類tag.HelloTag。
            接下來實例化該標籤,同時屬性值賦給參數,調用doTag方法。

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    ---報錯時使用統一的錯誤頁面
        <!-- 讓tomcat統一處理項目中的異常。有兩種方式,只能使用一個 -->
        <!-- 第一種方式:在tomcat捕獲到某類型異常時,自動轉發到某錯誤頁面 -->
        <error-page>
            <exception-type>java.lang.Exception</exception-type>
            <location>/WEB-INF/error.jsp</location>
        </error-page>
        <!-- 2.在tomcat捕獲到某編號異常時,自動轉發到某錯誤頁面 -->
        <error-page>
            <error-code>500</error-code>
            <location>/WEB-INF/error.jsp</location>    
        </error-page>
        <error-page>
            <error-code>404</error-code>
            <location>/WEB-INF/error.jsp</location>    
        </error-page>
        <error-page>
            <error-code>405</error-code>
            <location>/WEB-INF/error.jsp</location>    
        </error-page>
        <!-- jsp路徑寫成絕對路徑,因爲無法確定那個請求中報錯。
              另外tomcat直到要轉發的jsp一定在當前項目內,
              它會自動在路徑前面追加項目名,因此此處路徑不要寫項目名 -->
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

########################### Cookie和Session ################################
>>cookie和session的用途
    1)通俗的理解
    ---按照如下的規則存儲數據:
        ⑴多個請求可以共用這樣的數據
        ⑵多個servlet可以共用這樣的數據
        ⑶每個瀏覽器單獨存一份數據
    2)專業的理解
    --HTTP是無狀態協議:即一次請求對應一次響應,響應結束後連接即斷開,
        同一個用戶的不同請求對於服務器端來講並不會認爲這兩個請求有什麼關聯性,
        並不會以此區分不同的客戶端
    --cookie和session就是管理狀態,讓服務器記住瀏覽器的
    狀態:用來證明瀏覽器曾經訪問過服務器的數據
>>狀態管理兩種常見模式
    --狀態管理的過程中重要的是數據的保存,只有存下來的數據才能在多次交互中起到記錄的作用,
        所以可以按照管理的數據的存儲方式和位置的不同來區分狀態管理的模式。
    --如果將數據存儲在客戶端,每次向服務器端發請求時都將存在客戶端的數據隨着請求發送到服務器端,
        修改後再發回到客戶端保存的這種模式叫做Cookie。
    --如果將數據存儲在服務器端,並且爲這組數據標示一個編號,只將編號發回給客戶端。
        當客戶端向服務器發送請求時只需要將這個編號發過來,
        服務器端按照這個編號找到對應的數據進行管理的這種模式叫做Session——會話。

>>>>>>>>>>>>>>>>>>>> Cookie <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
1.創建cookie
    --Cookie  c = new Cookie(String name,String value);
    --response.addCookie( c );
    ---例:
        Cookie c = new Cookie("username","Lisa");        
        Cookie c2 = new Cookie("city","NewYork");
        response.addCookie(c);
        response.addCookie(c2);
2.獲取Cookie
    --Cookie[] request.getCookies();
    ---例:
    Cookie[] cookies =  request.getCookies();
    if(cookies!=null){
        for(Cookie c : cookies){
            String cookieName = c.getName();
            String cookieValue = c.getValue();
        }
    }
3.修改Cookie
    --通過setValue方法將新的數據存入到cookie中,
        然後由response響應對象發回到客戶端,對原有舊值覆蓋後即實現了修改
    --使用setValue方法修改了Cookie的值,但是不發回到客戶端的話,
        也不會實現數值的改變
4.Cookie的生存時間
    --默認是關閉瀏覽器Cookie自動銷燬
    --如果希望關閉瀏覽器後Cookie仍存在,則可以通過設置過期時間
        使得Cookie存在硬盤上得以保存更長的時間。
    --void setMaxAge(int seconds);
    seconds > 0 :代表Cookie保存在硬盤上的時長
    seconds = 0 : 代表Cookie的生命時長爲現在,而這一刻稍縱即逝,
        所以馬上Cookie就等同於過了生存時間,所以會被立即刪除。
        這也是刪除Cookie的實現方式。
    seconds < 0 :缺省值,瀏覽器會將Cookie保存在內存中。
5.Cookie編碼
    --Cookie作爲在網絡傳輸的一段字符串文本,只能保存合法的ASCII字符,
        如果要保存中文需要將中文變成合法的ASCII字符,即編碼
    --Cookie c = new Cookie("city",URLEncoder.encode("北京","utf-8"));
6.Cookie解碼
    --服務器讀取客戶端經過編碼之後的信息時,要想能夠正確顯示需要
        將信息解碼後才能輸出。使用URLDecoder的decode()方法即可
    --URLDecoder.decode(c.getValue(),"utf-8")
7.Cookie的路徑問題
    1)什麼是Cookie的路徑問題
    --客戶端存儲Cookie之後,並不是針對同一個應用訪問任何資源時都
        自動發送Cookie到服務器端,而是會進行路徑的判斷。
    --只有符合路徑規範的請求才會發送Cookie到服務器端。
    --客戶端在接受Cookie時會爲該Cookie記錄一個默認路徑,
        這個路徑記錄的是添加這個Cookie的Web組件的路徑。
    --如,當客戶端向 http://localhost:8080/test/file/addCookie.jsp
        發送請求時創建了cookie,那麼該cookie的路徑就是 /test/file.
    2)什麼時候發送Cookie
    --只有當訪問的地址是Cookie的路徑或者其子路徑時,
        瀏覽器才發送Cookie到服務器端。
    --如:Cookie的路徑是/test/file,那麼如果訪問的是/test/file/a.jsp 
        或者 /test/file/b/c.jsp時,都會發送Cookie。
        如果訪問的是 /test/d.jsp,則瀏覽器不會發送Cookie。
    3)如何設置Cookie的路徑
        --設置Cookie的路徑可以使用Cookie的API方法,setPath(String uri);
        ---例:
            Cookie c  = new Cookie(“uname”,“jack”);
            c.setPath(“/test”);
            response.addCookie(c);
    4)Cookie的限制
        (1)Cookie由於存放的位置在客戶端,所以可以通過修改設置被用戶禁止
        (2)只能保存少量數據,長度是有限制的,一般爲4kb左右
        (3)只能保存字符串,不能保留複雜的對象類型數據
        (4)Cookie安全性很低,非常容易通過截取數據包來獲取
        (5)網絡中傳輸的內容也會增加網絡的傳輸量影響帶寬

>>>>>>>>>>>>>>>>>>>> Session <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
1.什麼是Session
    服務器爲不同的客戶端在內存中創建了用於保存數據的Session對象,
    並將用於標識該對象的唯一Id發回給與該對象對應的客戶端。
    當瀏覽器再次發送請求時,SessionId也會被髮送過來,
    服務器憑藉這個唯一Id找到與之對應的Session對象。
    在服務器端維護的這些用於保存與不同客戶端交互時的數據的對象叫做Session。
2.Session創建
    --瀏覽器首次訪問時,服務器會自動給它創建一個session
    --服務器在創建request後,會讓request引用這個session
3.獲取Session
    --HttpSession session = req.getSession();
4.如何使用Session綁定對象
    --Session作爲服務器端爲各客戶端保存交互數據的一種方式,
        採用name-value對的形式來區分每一組數據
    --void session.setAttribute(String name,Object obj);
    --獲取綁定數據或移除綁定數據
        --void session.getAttribute(String name);
        --void session.removeAttribute(String name);
5.如何刪除Session對象
    --void  invalidate()
    --該方法會使得服務器端與該客戶端對應的Session對象不再被Session容器管理,
        進入到垃圾回收的狀態
6. Session超時
    1)什麼是Session超時
        --Session會以對象的形式佔用服務器端的內存
        --Web服務器缺省的超時時間設置一般是30分鐘。
        --一旦Session對象存在的時間超過了這個缺省的時間限制則認爲是Session超時,
            Session會失效,不能再繼續訪問
    2)如何修改Session的缺省時間限制
    --設置session超時的時間:服務器每個一段時間就會檢查用戶的空閒時間,
          若該用戶的空閒時間已經超過了配置的時間,則將它的session銷燬,單位爲:分鐘
          <session-config>
              <session-timeout>10</session-timeout>
          </session-config>
7. Session優缺點
    優點:
        (1)Session對象的數據保存在服務器安全較高
        (2)能夠保存豐富的數據類型
        (3)能夠保存更多的數據,Cookie只能保存大約4kb的字符串。
    缺點:
    --Session的安全性是以犧牲服務器資源爲代價的,
        如果用戶量過大,會嚴重影響服務器的性能。
8.瀏覽器禁用Cookie的後果
    --Session對象的查找依靠的是SID,而這個ID保存在客戶端時是以
        Cookie的形式保存的。一旦瀏覽器禁用Cookie,那麼SID無法保存,
        Session對象將不再能使用。
9.什麼是URL重寫
    --解決瀏覽器禁用Cookie
    --瀏覽器在訪問服務器的某個地址時,會使用一個改寫過的地址,
        即在原有地址後追加SessionID,這種重新定義URL內容的方式叫做URL重寫。
    --如:原有地址的寫法爲http://localhost:8080/test/some
        重寫後的地址寫法爲http://localhost:8080/test/some;jsessionid=4E113CB3
    --如果是重定向,使用如下代碼代替response.sendRedirect()
        --response.encodeRedirectURL(String url);

########################### 過濾器和監聽器 ################################
>>>>>>>>>>>>>>>>>>>>>>>>> 過濾器 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<    
--過濾器是Servlet2.3規範之中一種特殊的Web組件,
    可以作爲Servlet的輔助性插件存在。
---作用:
    --常用來做項目中的一些共性的需求
    --如:記錄日誌、過濾敏感詞、權限檢查
    --過濾器會以極低的耦合度來處理這樣的需求
    >>共性的需求:幾乎每個請求都要做的事情
1.如何編寫過濾器
    1)編寫一個實現了Filter接口的類
        --public class CommentFilter implements Filter{}
    2)實現Filter接口的三個方法,過濾邏輯在doFilter方法中實現
        --Filter接口中共定義了三個方法,分別是init,doFilter,destroy方法。
        --init方法在創建Filter時會被調用,且只調用一次,
            一般在該方法中做一些數據的準備工作,可以通過傳入的FilterConfig
            參數獲取在web.xml文件中配置提供給過濾器的初始參數。
        --destroy方法只有在銷燬過濾器對象時被調用一次,用於釋放一些資源的操作
        --doFilter方法內編寫過濾器的具體處理邏輯,會被多次執行.
            --該方法共有三個參數:
                request、response:請求和響應用於獲取數據以及追加數據
                FilterChain:過濾器鏈,負責多過濾器的傳遞。
        --執行FilterChain的doFilter會調用後續的過濾器或者servlet。
             --chain.doFilter(request,response)
                 若調用該方法,則請求繼續,若不調用,則請求中斷
    3)在Web程序中註冊過濾器
     <filter>
          <filter-name>guoLv</filter-name>
          <filter-class>web.GuolvFilter</filter-class>
      </filter>
      <filter-mapping>
          <filter-name>guoLv</filter-name>
          <!-- 聲明此filter過濾過濾那些請求 -->
          <url-pattern>/*</url-pattern>
      </filter-mapping>
    4)把過濾器和Web應用一起打包部署
        --將編譯後的過濾器和其他Web組件類合在一起,
            連同web.xml文件放進應用程序結構中即可。
2.過濾器的執行流程
    (1)客戶端發來請求
    (2)進入過濾器的doFilter方法中
    (3)在doFilter方法中執行chain.doFilter()方法,則將控制權交到Servlet.service()方法,
    (4)執行service()方法中的業務邏輯
    (5)業務邏輯執行結束後,回到過濾器的doFilter()方法中,執行chain.doFilter()方法後面的代碼
    (6)該部分有代碼就會執行,執行結束後,將response對象返回給客戶端    
    --過濾器對servlet執行前後都有過濾效果
3.過濾器的優先級
    --優先級是web.xml文件中<filter-mapping>的聲明順序來決定的
4.過濾器的生命週期
    1)啓動服務器時,它會創建filter。
    2)關閉服務器時它會銷燬filter
    --服務器只啓動一次,所以filter是單例的
    --每個filter解決一個業務,他們的調用順序以配置文件的順序爲準
5.初始化參數
    <filter>
        <filter-name>filter1</filter-name>
        <filter-class>web.CommentFilter1</filter-class>
        <!-- 初始化參數 -->
        <init-param>
          <param-name>illegalStr</param-name>
          <param-value>胡蘿蔔</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>filter1</filter-name>
        <url-pattern>/comment</url-pattern>
    </filter-mapping>  
6. 讀取初始化參數
    private FilterConfig config;    
    public void init(FilterConfig fc) throws ServletException {
        config = fc;
    }
    public void doFilter(ServletRequest req, 
                        ServletResponse res, FilterChain chain) 
                        throws IOException, ServletException {
        String illegalStr = config.getInitParameter("illegalStr");
        // … …
    }
    public void destroy() {// … …}

>>>>>>>>>>>>>>>>>>>>>>>>> 監聽器 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<    
--servlet規範中定義的一種特殊組件,用來監聽servlet容器產生的事件並進行響應的處理。
1.生命週期相關的事件
    容器創建或者銷燬request,session,ServletContext時產生的事件。
    --如:統計在線人數
2. 綁定數據相關的事件
    --調用(request,response,ServletContext)三個對象的
        setAttribute,removeAttribute方法時產生的事件。
3.如何編寫監聽器
    step1:寫一個java類,實現相應的監聽器接口(共有8個接口)。
        要依據監聽的事件類型來選擇相應的監聽器接口,
        比如要監聽session對象的創建和銷燬,要實現HttpSessionListener。
    step2:在監聽器接口方法中,實現相應的監聽處理邏輯。
        比如,session對象被刪除了,將人數減1。
    step3:註冊(在web.xml文件中配置即可)。
4.編寫Java類
    public class CountListener implements HttpSessionListener{
        private int count = 0;
        public void sessionCreated(HttpSessionEvent arg0){
            System.out.println("sessionCreated…");
            count ++;
        }
        public sessionDestroyed(HttpSessionEvent arg0){
            System.out.println("session destroyed…");
            count--;
        }
    }
5.實現處理邏輯
    public void sessionCreated(HttpSessionEvent e){
        System.out.print("sessionCreated…");
        HttpSession session = e.getSession();
        ServletContext ctx = session.getServletContext();
        ctx.setAttribute("count",count);
    }
6.註冊監聽器
    <listener>
        <listener-class>web.CountListener</listener-class>
    </listener>
7.監聽器的應用場景    
    系統框架級別的代碼經常需要檢測容器中數據或對象的變化,
    以一個不受人爲控制因素的觸發爲執行時機,
    所以對於需要根據數據變化來做出自動反饋的功能都可以使用到監聽器.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章