Head first:servlet and jsp 筆記

  1. 常用端口:HTTP在TCP的端口80上運行;telnet在端口23,FTP在端口21,SSH(secure shell 遠程登錄協議)在端口22

  2. CGI:CGI(Common Gateway Interface) 是WWW技術中最重要的技術之一,有着不可替代的重要地位。CGI是外部應用程序(CGI程序)與WEB服務器之間的接口標準,是在CGI程序和Web服務器之間傳遞信息的過程。CGI規範允許Web服務器執行外部程序,並將它們的輸出發送給Web瀏覽器,CGI將Web的一組簡單的靜態超媒體文檔變成一個完整的新的交互式媒體。
    Common Gateway Interface,簡稱CGI。在物理上是一段程序,運行在服務器上,提供同客戶端HTML頁面的接口。這樣說大概還不好理解。那麼我們看一個實際例子:現在的個人主頁上大部分都有一個留言本。留言本的工作是這樣的:
    先由用戶在客戶端輸入一些信息,如評論之類的東西。接着用戶按一下“發佈或提交”(到目前爲止工作都在客戶端)
    瀏覽器把這些信息傳送到服務器的CGI目錄下特定的CGI程序中,於是CGI程序在服務器上按照預定的方法進行處理。在本例中就是把用戶提交的信息存入指定的文件中。然後CGI程序給客戶端發送一個信息,表示請求的任務已經結束。此時用戶在瀏覽器裏將看到“留言結束”的字樣。整個過程結束。

  3. web服務器自己不做的兩件事:不提供動態內容,不保存數據。這兩件事都是通過web服務器輔助應用(可能是CGI或者servlet)來實現的

  4. JSP:把java放到html的解決方案,而不是把html放到java(println)

  5. 什麼是容器:servlet沒有main()方法,它們受控於另一個java應用,這個java應用稱爲容器。tomcat就是這樣一個容器。如果web服務器應用(如Apache或Nignx)得到一個指向某servlet的請求(而不是其他請求,如請求一個普通的靜態HTML頁面),此時服務器不是把這個請求交給servlet本身,而是交給部署該servlet的容器。要由容器向servlet提供HTTP請求和響應,而且要由容器調用servlet的方法,如doPost()或者doGet()

  6. Apache,nginx和tomcat的關係和區別(https://www.zhihu.com/question/32212996
    Apache的全稱應該叫做Apache HTTP Server,它跟nginx一樣,都是一種HTTP Server。HTTP Server本質上也是一種應用程序——它通常運行在服務器之上,綁定服務器的IP地址並監聽某一個tcp端口來接收並處理HTTP請求,這樣客戶端(一般來說是IE, Firefox,Chrome這樣的瀏覽器)就能夠通過HTTP協議來獲取服務器上的網頁(HTML格式)、文檔(PDF格式)、音頻(MP4格式)、視頻(MOV格式)等等資源。
    一個 HTTP Server 關心的是 HTTP 協議層面的傳輸和訪問控制,所以在 Apache/Nginx 上你可以看到代理、負載均衡等功能。客戶端通過 HTTP Server 訪問服務器上存儲的資源(HTML 文件、圖片文件等等)。通過 CGI 技術,也可以將處理過的內容通過 HTTP Server 分發,但是一個 HTTP Server 始終只是把服務器上的文件如實的通過 HTTP 協議傳輸給客戶端。
    而tomcat是一個servlet/JSP的容器。是一個應用服務器(application server)。應用服務器,是一個應用執行的容器。它首先需要支持開發語言的 Runtime(對於 Tomcat 來說,就是 Java),保證應用能夠在應用服務器上正常運行。其次,需要支持應用相關的規範,例如類庫、安全方面的特性。對於 Tomcat 來說,就是需要提供 JSP/Sevlet 運行需要的標準類庫、Interface 等。爲了方便,應用服務器往往也會集成 HTTP Server 的功能,但是不如專業的 HTTP Server 那麼強大,所以應用服務器往往是運行在 HTTP Server 的背後,執行應用,將動態的內容轉化爲靜態的內容之後,通過 HTTP Server 分發到客戶端。
    tomcat本身也有HTTP Server的功能。與HTTP Server相比,Tomcat能夠動態的生成資源並返回到客戶端。Apache HTTP Server和Nginx都能夠將某一個文本文件的內容通過HTTP協議返回到客戶端,但是這個文本文件的內容是固定的——也就是說無論何時、任何人訪問它得到的內容都是完全相同的,這樣的資源我們稱之爲靜態資源。動態資源則與之相反,在不同的時間、不同的客戶端訪問得到的內容是不同的,例如:包含顯示當前時間的頁面顯示當前IP地址的頁面Apache HTTP Server和Nginx本身不支持生成動態頁面(但它們可以通過其他模塊來支持例如通過Shell、PHP、Python腳本程序來動態生成內容)。如果想要使用Java程序來動態生成資源內容,使用這一類HTTP服務器很難做到。Java Servlet技術以及衍生的Java Server Pages技術可以讓Java程序也具有處理HTTP請求並且返回內容(由程序動態控制)的能力,Tomcat正是支持運行Servlet/JSP應用程序的容器(Container)
    Tomcat運行在JVM之上,它和HTTP服務器一樣,綁定IP地址並監聽TCP端口,同時還包含以下職責:管理Servlet程序的生命週期,將URL映射到指定的Servlet進行處理與Servlet程序合作處理HTTP請求——根據HTTP請求生成HttpServletResponse對象並傳遞給Servlet進行處理,將Servlet中的HttpServletResponse對象生成的內容返回給瀏覽器
    雖然Tomcat也可以認爲是HTTP服務器,但通常它仍然會和Nginx配合在一起使用:動靜態資源分離——運用Nginx的反向代理功能分發請求:所有動態資源的請求交給Tomcat,而靜態資源的請求(例如圖片、視頻、CSS、JavaScript文件等)則直接由Nginx返回到瀏覽器,這樣能大大減輕Tomcat的壓力。
    負載均衡,當業務壓力增大時,可能一個Tomcat的實例不足以處理,那麼這時可以啓動多個Tomcat實例進行水平擴展,而Nginx的負載均衡功能可以把請求通過算法分發到各個不同的實例進行處理

  7. 容器能提供什麼?
    1)通信支持:利用容器提供的方法,你能輕鬆地讓servlet跟web服務器對話。不需要自己建立serversocket,監聽端口,創建流等。
    2)生命週期管理。容器會負責加載類,實例化和初始化servlet,調用servlet方法,垃圾回收servlet實例等等
    3)多線程支持:容器會自動爲它接收的每個servlet請求創建一個新的java線程。針對客戶的請求,如果servlet已經運行完相應的HTTP服務方法,這個線程就會結束。這並不是說不用考慮線程安全,還是會遇到同步問題的,但是這樣確實能讓你少做很多工作
    4)聲明方式實現安全:利用容器,可以使用xml部署描述文件來配置和修改安全性,而不必將其硬編碼寫到servlet代碼中
    5)JSP支持:容器負責把JSP翻譯成真正的java

  8. 一個servlet可以有3個名字
    分別是:
    1)用戶訪問的URL名,用戶用戶訪問,是個虛構的名字,完全爲用戶提供
    2)開發部署人員命名的內部名稱,同樣的,這也是個虛擬的名字,只用於部署servlet
    3)servlet實際的文件名,包括類名和包名
    顯然,理論上來說,我們可以直接使用servlet的實際文件名,把它硬編碼寫到所有使用這個servlet的JSP和其他HTML頁面中。比如webapp/shop/userServlet.class.
    但是這樣會存在幾個問題:可維護性和安全性
    實際使用中,是容器來調用servlet,我們配置部署描述文件將URL映射到servlet:

    <servlet>
    <servlet-name>Myservlet</servlet-name> <!-- Myservlet是開發部署人員命名的內部名稱,只用於部署servlet -->
    <servlet-class>com.test.app.oneServlet</servlet-class> <!-- servlet的真實文件名,但是不需要加.class後綴 -->
    </servlet>
    <servlet-mapping>
    <servlet-name>Myservlet</servlet-name> <!-- 這裏的Myservlet就是上面定義的Myservlet,這樣servlet的真實文件就跟url組成了映射關係-->
    <url-pattern>/one</url-pattern>  <!-- /one就是用戶訪問的URL名,這裏是個相對路徑,全路徑類似http://www.123.com/web/one,這樣最終servlet就映射到了/one這個路徑-->
  9. 容器會給每個請求(而不是每個servlet)創建一個新的線程,每個servlet都只有一個實例
  10. servlet的生命中期:init()–service()–doGet()/doPost()–destroy()
  11. 冪等(HTTP冪等方法,是指無論調用這個url多少次,都不會有不同的結果的HTTP方法):根據RESTful設計標準,取東西就要GET(GET就是安全的,冪等的,不會修改服務資源),新增就要POST(POST就是不安全的,非冪等的),修改就要PUT(PUT就要冪等),刪除就是DELETE(DELETE就要冪等)
  12. forward和redirect的區別:forward不走客戶端,地址欄沒有變化;redirect走客戶端,地址欄改變,客戶端會收到301重定向請求
  13. servletConfig可以設定servlet的參數(通過web.xml配置),僅在這個servlet裏面可被訪問(通過方法:

    getServletConfig().getInitParameter("username")):

    配置:

    <web-app>
    <servlet>
    <servlet-name>Myservlet</servlet-name> 
    <servlet-class>com.test.app.oneServlet</servlet-class>
    <init-param>
    <param-name>username</param-name>
    <param-value>zhangsan</param-value>
    </init-param>
    </servlet>
    </web-app>

    另,spring裏的配置:

    <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>
        org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/springmvc-servlet.xml</param-value>
        </init-param>
    </servlet>
  14. servletContext可以設定上下文參數(通過web.xml配置),在整個應用裏面都可被訪問(通過方法:

    getServletContext().getInitParameter("username")):

    配置:

    <web-app>
    <context-param>
    <param-name>username</param-name>
    <param-value>zhangsan</param-value>
    </context-param>
    </web-app>

    另,spring裏的配置:

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/spring-*.xml
        </param-value>
    </context-param>
  15. ServletContextListener上下文監聽者,這個接口有2個方法,分別是contextInittialized(用來監聽
    servletContext的初始化)和contextDestroyed(用來監聽servletContext的銷燬),可以在應用爲用戶提供服務之前運行一些代碼
    ServletContextListener通過web.xml來配置

    <listener>
    <listener-class>
    com.example.MyServletContextListener
    </listener-class>
    </listener>

    另,spring裏的配置:

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
  16. tomcat的熱部署(已經在線上的服務不可能重啓tomcat來更新)

  17. HTTP是一種無狀態連接。瀏覽器與服務器端建立連接,發出請求,得到相應,最後關閉連接。
  18. 爲了識別不同的用戶(在不需要用戶登錄的情況下),容器會在response中發送一個cookie(比如帶有唯一標示JSESSIONID)給客戶端,客戶端會保存這個cookie,然後每次發送請求的時候,在header裏面帶上這個cookie
  19. 如何讓容器發送cookie:
    調用HttpSession session = request.getSession();
  20. 如果客戶端禁用cookie:使用url重寫,類似http://test.com/shop;jsessionid=00A321DB1
    對應的方法是:

    response.encodeURL("result") //result是你的URL

    對於重定向可以使用 :

    response.encodeRedirectURL("/result");

    只能通過上面的方法來進行url重寫,這意味着靜態HTML頁面無法進行重寫,除非你在代碼中動態的生成HTML

  21. session的刪除:
    1)超時
    2)手動調用invalidate()
    3)應用結束(崩潰or取消部署)
    可以在web.xml裏面來配置session的超時時間:

    <web-app> <session-config>
    <session-timeout>15</session-timeout>  <!-- 這裏的單位是分鐘 --> 
    </session-config> </web-app>
  22. cookie實際上就是在客戶端和服務器之間交換的一小段數據(一個鍵值對)。服務器把cookie發送給用戶,用戶做出下一個請求時再把cookie返回給服務器。
    默認的,cookie與session的壽命一樣長,但是你也可以單獨設置。通常我們也會把cookie設置的比較長,這樣即便會話結束了,用戶再次訪問網站時,我們也可以得到用戶的一些信息

  23. 對於集羣環境(有多個JVM,這些JVM可以在相同的物理主機上–虛擬主機,或者在不同的物理主機上),每個JVM,都將有一個ServletContext,每個JVM上的每個servlet都有一個ServletConfig,但是對於每個web應用的一個給定的會話ID,只有一個HttpSession對象,而不論應用分佈在多少個JVM上
    簡單點說,對於集羣環境,ServletContext和ServletConfig都會複製,而HttpSession只是移動(只有唯一的一份)
  24. 你的JSP最終會變成一個完整的servlet在web應用中運行。它與其他的servlet非常相似,只不過這個servlet類會由容器爲你編寫。
    容器拿到你在JSP中寫的代碼,把這些代碼轉換成爲一個servlet類源文件(.java),然後再把這個源文件編譯爲Java servlet類。在此之後,這就是名副其實的servlet了,而且這個servlet的運行並無特別之處,就好像它的代碼都是你自己編寫和編譯的一樣。換句話說,容器會加載這個servlet類,實例化並初始化,爲每個請求建立一個單獨的線程,並調用servlet的service()方法
  25. 在用戶第一次請求某個JSP,jsp文件會被轉化成java文件,進而編譯成一個class文件,在整個JSP的生命週期中,整個轉化和編譯步驟只發生一次。JSP一旦得到轉換和編譯,就跟其他的servlet一樣了。
  26. jsp的內置對象(又叫隱含對象,有9個,不需要預先聲明就可以在腳本代碼和表達式中隨意使用),分別是:

    request 請求對象  類型 javax.servlet.ServletRequest 作用域 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

  27. scriptlet是包含在<% %>之間的Java代碼,寫在JSP文件中,現在已經被EL(表達式語言,expression language)和JSTL(jsp標準標記庫 JSP Standard Tag Library)替代

  28. EL語法:

    ${firstThing.secondThing} or ${firstThing["secondThing"]}

    其中,firstThing可以是EL隱式對象或者屬性

  29. EL函數:
    1)使用TLD標記庫描述文件(擴展名爲.tld,放在/WEB-INF目錄下,提供了定義函數的java類與調用函數的jsp之間的一個映射)
    2)使用taglib來引用對應的TLD文件
    3)使用EL調用函數
  30. JSTL常用標記:

    <c:out>
    <c:forEach>
    <c:if>
    <c:choose><c:when><c:otherwise>
    <c:set>
    <c:import> 類似<jsp:include>
    <c:url>
    <c:catch>
  31. EL提供的更多是一個對象或者一個函數,而JSTL提供的更多的是一個邏輯(比如if else)

  32. war文件:去掉web應用上下文目錄,也就是把WEB-INF之上的一級目錄去掉後,把整個web應用結構壓縮起來。
    不過有個問題,如果沒有包括特定的web應用目錄(例如cnzzdata),容器怎麼知道這個web應用的名稱/上下文呢?
    這取決於你的容器。在tomcat中,war文件的文件名就會成爲web應用的名字。
  33. 應用部署爲war時,唯一的新東西是META-INF目錄(在根目錄下,其中包含一個MANIFEST.MF文件)。你自己可能不會在META-INF目錄中放任何東西,所以不用關心應用是否部署爲一個war,除非你確實需要在MANIFEST.MF文件中指定庫依賴性
  34. WEB-INF下的html和jsp是不可以直接訪問的(META-INF也是如此)
  35. dd配置默認頁面:welcome-file-list.需要注意的是:
    1).welcome-file-list可以配置多個默認頁面,比如:

    <web-app>
    <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>default.jsp</welcome-file>
    </welcome-file-list>
    </web-app>

2).配置多個默認頁面的意義在於,對於不同目錄的請求,會在該目錄下順序查找默認頁面列表裏的頁面
比如按照1中的配置,如果login目錄中有index.html文件,也有default.jsp文件,當你請求:
http://localhost:8080/webtest/login的時候,會跳轉到index.html
而如果search目錄中只有default.jsp文件,當你請求:http://localhost:8080/webtest/search的時候,會跳轉到default.jsp
36. 默認的,servlet會在每一個請求到來時初始化。但是可以通過在dd中配置來完成在部署時加載servlet:

<load-on-startup>1</load-on-startup> <!-- 只要這個值大於0,就表示“在部署或者服務器啓動時初始化這個servlet”,而這個值的大小決定了它的啓動順序(與我們常識相反,1是最先加載的,數字越大越往後)-->

37. web應用安全:
假冒者,非法升級者和竊聽者
認證,授權,機密性和數據完整性
38. tomcat有tomcat-users.xml文件,但是它並不在web應用的目錄中,而是在tomcat的conf/目錄下。而且它應用於tomcat下部署的所用應用。所以在生產階段我們通常不會用tomcat自身的認證機制,其中一個原因是,如果不重啓tomcat就無法修改認證內容
39. 過濾器Filter(面向切面)
請求過濾器可以:
完成安全檢查
重新格式化請求首部或者請求體
建立請求審計或日誌
相應過濾器可以:
壓縮響應流
追加或修改響應流(比如增加水印)
創建一個完全不同的響應
40. 過濾器的生命週期:
1)首先要有一個init()來初始化
2)真正的工作在doFilter()中完成
3)最後是destroy()
41. doFilter的3個參數:
1)ServletRequest(而不是HttpServletRequest)
2)ServletResponse(而不是HttpServletResponse)
3)FilterChain(filter鏈,你可以理解爲它是一個filter管理器或驅動。過濾器並不知道請求所涉及的其他過濾器,也就是說過濾器之間互相是不知道的,servlet更是不知道所有過濾器的存在,但是總有人要知道過濾器的執行順序,這個人就是FilterChain。另外filterChain的doFilter()方法負責明確接下來調用那個filter的doFilter()方法)
引用doFilter()方法的代碼:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws

ServletException, IOException{
chain.doFilter(request, response); //順序執行過濾器,最後調用servlet
}
42. 聲明過濾器

<filter>
<filter-name>BeerRequest</filter-name>
<filter-class>com.example.wen.BeerRequestFilter</filter-class>
<init-param>
<param-name>LogFileName</param-name>
<param-value>UserLog.txt</param-value>
</init-param>
</filter>

聲明對應URL模式的過濾器映射(有點類似servlet的聲明和映射)

<filter-mapping>
<filter-name>BeerRequest</filter-name>
<url-pattern>*.do</url-pattern> <!-- 所有.do的資源都要使用這個過濾器-->
</filter-mapping>

也可以不對應URL,而是對應特定的servlet聲明映射:

<filter-mapping>
<filter-name>BeerRequest</filter-name>
<url-pattern>*.do</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>

還可以對轉發,包含,請求分發或者錯誤處理進行聲明過濾器映射(不是所有的請求都來自於客戶,還可能來自於轉發,或者程序跳轉到錯誤頁面,或者你在代碼中應用了include等等非用戶請求的所有資源):

<filter-mapping>
<filter-name>BeerRequest</filter-name>
<dispatcher>REQUEST</dispatcher> <!-- REQUEST表示對客戶請求啓用過濾器(其實默認就是啓用的)-->
<dispatcher>INCLUDE</dispatcher> <!-- INCLUDE表示對由一個include()調用分發來的請求啓用過濾器 -->
<dispatcher>FORWARD</dispatcher> <!-- FOWARWD表示對由一個forward()調用分發來的請求啓用過濾器 -->
<dispatcher>ERROR</dispatcher> <!-- ERROR表示對錯誤處理器調用的資源啓用過濾器 -->
</filter-mapping>

43. 響應過濾器:
原理:修改chain.doFilter(request, response)中,傳遞給servlet的response,而得到預期內的響應
修改response可以通過包裝器(wrapper):

//包裝器,繼承自HttpServletResponseWrapper系統自帶包裝器
class TestResponseWrapper extends HttpServletResponseWrapper{
//覆蓋你想定製的方法
}
class MyFilter implements Filter{
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain){
TestResponseWrapper warpper = new TestResponseWrapper(response); //用包裝器包裝響應
chain.doFilter(request, warpper);
}
44. 包裝器的一個例子(實現壓縮器)
class TestResponseWrapper extends HttpServletResponseWrapper{
public ServletOutputSteam getOutputStream() throws…{
servletGzupOS = new GzipSOS(resp.getOutputStream()); //這裏resp.getOutputStream()是原本response的輸出流,我們替換成自己的GZIP流,來改變響應,達到響應過濾的目的
return servletGzupOS;
}
}
45. JNDI:java命名和目錄接口(java naming and directory interface),這是一個訪問命名和目錄服務的API。基於JNDI,可以在網絡中的一個集中位置上完成查找。如果你有一些對象,而且希望網絡上的其他程序找到並訪問這些對象,就要向JNDI註冊這些對象。其他程序想使用你的對象時,則可以使用JNDI來查找
46. RMI:遠程方法調用(remote method invocation)
47. 所謂遠程調用,指的是你要調用的對象在另一個JVM中

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