Servlets & JSP

wxainn發表於2017-07-31

Servlets & JSP

java開發:

  • cs(client、server)
    客戶端、伺服器。必須安裝客戶端,服務端更新客戶端必須更新才能應用。 如大型遊戲、qq。
  • bs(browser、server)。 瀏覽器、伺服器。通過瀏覽器就能訪問,不需要安裝客戶端。

bs原理
瀏覽器–應用程式伺服器–資料庫伺服器

bs結構程式完全部署在應用程式伺服器中,基於請求和響應,基於http協議。一次請求對應一次響應。

tomcat伺服器–小型開源免費的應用程式伺服器,預設埠號8080。學習、開發中應用tomcat伺服器,專案上線應用收費的應用程式伺服器weblogic….

Tomcat目錄:
  • bin 啟動、關閉tomcat伺服器應用的一些命令
  • conf 配置檔案
  • lib jar包
  • webapps 部署到伺服器中的應用程式
  • work Tomcat把由JSP生成的Servlet放於此目錄下。

URL格式:
http://ip地址:tomcat的埠號/專案名/訪問的路徑

請求的方式:

  • get: 顯示提交、不安全、、不能直接支援中文。
      表單的method屬性設定為get時(預設)
      使用者的輸入資訊會在位址列顯示
      輸入url
      點選連結

  • post: 隱式提交、安全、支援中文。
      表單的method屬性設定為post時

Servlet API

Servlet介面
    └─GenericServlet抽象類
        └─HttpServlet抽象類(基於http協議),我們所使用的servlet根基類。

ServletRequest、ServletResponse
    └─HttpServletRequest、HttpServletResponse。基於http協議的請求、響應

javax.servlet Interface Servlet
All Known Implementing Classes:
GenericServlet

Servlet

javax.servlet
Interface Servlet
All Known Implementing Classes: GenericServlet

ServletConfig

javax.servlet
Interface ServletConfig
All Known Implementing Classes:
GenericServlet

ServletContext

javax.servlet
Interface ServletContext

ServletRequest

javax.servlet
Interface ServletRequest
All Known Subinterfaces:
HttpServletRequest

ServletResponse

javax.servlet
Interface ServletResponse
All Known Subinterfaces:
HttpServletResponse

GenericServlet

javax.servlet
Class GenericServlet
java.lang.Object
 └─javax.servlet.GenericServlet
All Implemented Interfaces:
java.io.Serializable, Servlet, ServletConfig
Direct Known Subclasses:
HttpServlet

HttpServlet

javax.servlet.http
abstract Class HttpServlet
java.lang.Object
 └─javax.servlet.GenericServlet
  └─javax.servlet.http.HttpServlet
All Implemented Interfaces:
java.io.Serializable, Servlet, ServletConfig

HttpServletRequest

javax.servlet.http
Interface HttpServletRequest
All Superinterfaces:
ServletRequest

HttpServletResponse

javax.servlet.http
Interface HttpServletResponse
All Superinterfaces:
ServletResponse

RequestDispatcher

javax.servlet
Interface RequestDispatcher

自定義Servlet類的建立

  1. 繼承自HttpServlet類。
  2. 重寫doGet()方法、doPost()方法。
  3. Web.xml檔案中配置Servlet類(或servlet註解)。

路徑問題:

tomcat預設埠號:8080,修改tomcat的埠號:

<!--tomcat--conf資料夾--server.xml中修改埠號-->
<Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />

專案除錯:

  • 如果修改了web.xml 必須重新啟動伺服器
  • 修改了java程式碼,需要重新部署
  • 修改了頁面程式碼,不需要重新部署

web.xml: 最先被載入的配置檔案

  • 配置servlet(配置訪問路徑)
  • 配置歡迎頁面,一般用於設定主頁

容器如何處理請求:

  1. 使用者點選一個連結,其URL指向一個servlet而不是靜態頁面。
  2. 容器“看出來”這個請求要的是一個servlet,所以容器建立兩個物件:HTTPServletRequestHttpServletResponse
  3. 容器根據請求中的URL找到正確的servlet,為這個請求建立或分配一個執行緒,並把請求和相應物件傳遞給這個servlet執行緒。
  4. 容器呼叫servlet的service()方法。根據請求的不同型別,service()方法會呼叫doGet()或doPost()方法。
  5. doGet()或doPost()方法生成動態頁面,並把這個頁面“填入”響應物件。要記住,容器還有相應物件的一個引用。
  6. 執行緒結束,容器把響應物件轉換為一個Http響應,把它傳送給客戶,然後刪除請求和相應物件。

servlet的生命週期:

HTTP請求 → 解析請求 → 建立servlet例項 → 呼叫init()方法 → 呼叫service()方法 → 輸出響應資訊 → 響應 → 呼叫destroy()方法。

  • 例項化階段:Servlet容器呼叫建構函式。
  • 初始化階段:容器呼叫init()方法。
  • 請求處理階段:如果請求Servlet,則容器呼叫service()方法(service()方法根據請求的方式呼叫doGet()或doPost()方法)。
  • 銷燬階段:銷燬例項之前呼叫destroy()方法。

servlet採用多執行緒單例項的模式:

  • 第一次訪問servlet:例項化階段–初始化階段–請求處理階段
  • 第二次及以上訪問servlet:請求處理階段。

servlet中不應該自定義成員變數。

Servlet介面

定義了所有Servlet要實現的方法。

Servlet常用方法:

方法名稱 功能描述
public void init(ServletConfig config) 由servlet容器呼叫,用於完成Servlet物件在處理客戶請求前的初始化工作
public void service(ServletRequest req, ServletResponse) 由servlet容器呼叫,用來處理客戶端的請求
public void destroy() 由servlet容器呼叫,釋放Servlet物件所使用的資源
public ServletConfig getServletConfig() 返回ServletConfig物件,該物件包含此servlet的初始化和啟動引數。返回的ServletConfig物件是傳遞給init()方法的物件
public String getServletInfo() 返回有關servlet的資訊,比如作者、版本和版權。返回的字串是純文字。

ServletConfig介面

在Servlet初始化過程中獲取配置資訊,一個Servlet只有一個ServletConfig物件。

ServletConfig常用方法:

方法名稱 功能描述
public String getInitParameter(String name) 獲取web.xml中設定的以name命名的初始化引數值
public ServletContext getServletContext() 返回Servlet的上下文物件引用

GenericServlet抽象類

提供了Servlet與ServletConfig介面的預設實現方法。

Servlet介面的常用方法:

方法名稱 功能描述
public void init(ServletConfig config) 呼叫Servlet介面中的init()方法。此方法還有一無參的過載方法,其功能與此方法相同
public String getInitParameter(Stringname) 返回名稱為name的初始化引數的值
public ServletContext getServletContext() 返回ServletContext物件的引用

HttpServlet抽象類

繼承於GenericServlet,處理HTTP協議的請求和響應。

HttpServlet的常用方法:

方法名稱 功能描述
public void service(ServletRequest req, ServletResponse res) 呼叫GenericServlet類中service()方法的實現
public void service(HttpServletRequest req, HttpServletResponse res) 接收HTTP請求,並將它們分發給此類中定義的doXXX()方法
public void doXXX(HttpServletRequest req, HttpServletResponse res) 根據請求方式的不同,分別呼叫相應的處理方法,例如doGet()、doPost()等

ServletRequest介面

獲取客戶端的請求資料。

ServletRequest介面常用方法:

方法名稱 功能描述
public Object getAttribute(String name) 獲取名稱為name的屬性值
public void setAttribute(String name, Object object) 在請求中儲存名稱為name的屬性
public void removeAttribute(String name) 清除請求中名字為name的屬性

HttpServletRequest介面

除了繼承ServletRequest介面中的方法,還增加了一些用於讀取請求資訊的方法。

HttpServletRequest的常用方法:

方法名稱 功能描述
public String getContextPath() 返回請求URI中表示請求上下文的路徑,上下文路徑是請求URI的開始部分
public Cookie[] getCookies() 返回客戶端在此次請求中傳送的所有cookie物件
public HttpSession getSession() 返回和此次請求相關聯的session,如果沒有給客戶端分配session,則建立一個新的session
public String getMethod() 返回此次請求所使用的HTTP方法的名字,如GET、POST

RervletResopnse介面

向客戶端傳送響應資料。

RervletResopnse介面的常用方法:

方法名稱 功能描述
public PrintWriter getWriter() public PrintWriter getWriter()
public String getCharacterEncoding() 返回在響應中傳送的正文所使用的字元編碼
public void setCharacterEncoding() 設定傳送到客戶端的響應的字元編碼
public void setContentType(String type) 設定傳送到客戶端的響應的內容型別,此時響應的狀態屬於尚未提交

HttpServletResponse介面

除了繼承ServletResopnse介面中的方法,還增加了新的方法。

HttpServletResopnse的常用方法:

方法名稱 功能描述
public void addCookie(Cookie cookie) 增加一個cookie到響應中,這個方法可多次呼叫,設定多個cookie
public void addHeader(String name,String value) 將一個名稱為name,值為value的響應報頭新增到響應中
public void sendRedirect(String location) 傳送一個臨時的重定向響應到客戶端,以便客戶端訪問新的URL
public void encodeURL(String url) 使用session ID對用於重定向的URL進行編碼

ServletContent介面

獲取Servlet上下文。

ServletContext常用方法:

方法名稱 功能描述
public String getInitParameter(String name) 獲取名稱為name的系統範圍內的初始化引數值,系統範圍內的初始化引數可以在部署描述符中使用context-param元素定義
public void setAttribute(String name, Object object) 設定名稱為name的屬性
public Object getAttribute(String name) 獲取名稱為name的屬性
public String getRealPath(String path) 返回引數所代表目錄的真實路徑
public void log(String message) 記錄一般日誌資訊

字元編碼:

  GBK2312、GBK、BIG5、ISO8859-1(預設採用此字符集)、UTF-8、

能讀取文字框內中文內容不亂碼:

request.setCharacterEnding("utf-8");

輸出中文內容不亂碼:

resopnse.setContentType("text/html; charset=utf-8");

每種檔案都有各自的內容型別(mine-type),在servers>web.xml檔案中有定義,html對應–text/html。

初始化引數:

  • servlet類初始化引數:在web.xml中的servlet節點中配置,有效範圍是當前servlet類。
  • servlet上下文物件的初始化引數(ServletContext):在web.xml中配置,有效範圍是當前專案中所有servlet類。
<!--Servlet初始化引數配置-->
<web-app>
    <servlet>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>org.jbit.servlet.HelloServlet</servlet-class>
        <init-param>
            <param-name>initParam</param-name>
            <param-value>Hello Servlet</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/HelloServlet</url-pattern>
    </servlet-mapping>
</web-app>
<!--獲取Servlet初始化引數-->
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    System.out.println("處理請求時,doGet()方法被呼叫。");
    String initParam = getInitParameter("initParam");
    System.out.println(initParam);
}
<!--配置Servlet上下文-->
<web-app>
    <context-param>
        <param-name>contextParam</param-name>
        <param-value>Hello Servlet</param-value>
    </context-param>
    <!--省略其他配置-->
</web-app>
<!--讀取Servlet上下文-->
public class HelloServlet extends HttpServlet {
    // …省略其他程式碼
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("處理請求時,doGet()方法被呼叫。");
        String initParam = getInitParameter("initParam");
        String contextParam = this.getServletContext().getInitParameter("contextParam");
        System.out.println("Servlet初始化引數" + initParam);
        System.out.println("系統初始化引數" + contextParam);
    }
}

servlet類列印html程式碼輸出:

resopnse.setContentType("text/html; charset=utf-8");
PrinterWriter out = request.getWriter();
out.println("<h1>HELLO WORLD</h1>");

頁面跳轉的兩種方式:

  • 請求轉發:
    1. 轉發是在伺服器端發揮作用,通過forward()將提交資訊在多個頁面間進行傳遞。
    2. 客戶端瀏覽器的位址列不會顯示出轉向後的地址。
  • 重定向:
    1. 重定向是在客戶端發揮作用,通過請求新的地址實現頁面轉向,不能攜帶資料。
    2. 在位址列中可以顯示轉向後的地址。
//重定向
response.sendRedirect("URL");

//請求轉發
RequestDispather dispather = request.getResquestDispather("URL");
dispather.forword(request, reponse);

  web伺服器儲存在客戶端的一系列文字資訊。

//建立Cookie物件
Cookie cookie = new Coolie(String key, String value);
//寫入Cookie
response.addCookie();
//讀取Cookie
Coolies[] cookies = request.getCookies();

Cookie物件的常用方法:void setMaxAge(int second)、 void setValue(String key)、 String getName()、 String getValue()、 String getMaxAge()。

使用部署檔案將URL對映到sevlet

將servlet部署到Web容器時,會建立一個相當簡單的XML文件,這稱為部署描述檔案(DD),部署描述檔案會告訴容器如何執行你的servlet和JSP。

部署描述檔案(DD)提供了一種“宣告”機制來定製Web應用,而無需修改原始碼!

DD的優點:

  • 儘量少改動已經測試通過的原始碼。
  • 即使你手上並沒有原始碼,也可以對應用功能進行調整。
  • 不用重新編譯和測試任何程式碼,也可以讓你的應用適應不同的資源(如資料可)。
  • 可以更容易地維護安全資訊,如訪問控制列表和安全形色。
  • 非程式設計師也可以以修改和部署Web應用,而你可以留出精力,做出有意思的事情,比如看看你的行裝是否適合夏威夷之旅。

servlet的存在就是要為客戶服務。servlet的任務時得到一個客戶的請求,在發出一個響應。

service()方法總是在自己的棧中呼叫。容器執行多個執行緒來處理對一個servlet的多個請求。

誰來實現HttpServletRequest和HttpServletResponse介面?這些類在API中嗎?——容器不在。他們要由開發商來實現。

HttpSession

javax.servlet.http.HttpSession介面表示一個會話,我們可以把一個會話內需要共享的資料儲存到HttpSession物件中!

通常把HttpSession直接稱為Session。

獲取Session物件:

HttpSession session = request.getSession();

常用方法:void setAttribute(String key, Object value)、 Object getAttribute(String key)、 void invalidate()、 String getId()、 void setMaxInactiveInterval()、 int getMaxInactiveInterval()、 void removeAttribute()。

注意:存值時,key相同value會覆蓋。session失效,其中的值會消失。

session的生命週期:開啟瀏覽器session有效,關閉瀏覽器/呼叫invalidata()方法/超時session失效(銷燬),預設有效時間為20分鐘。

手動設定session失效:

//使用session的方法
session.setMaxInactiveInterval(int second);

//配置檔案,就近有效原則,專案下的web.xml優先順序高於Tomcat中的web.xml。
<seesion-config>
    <session-timeout>int minutes</session-timeout>
</session-config>

session與視窗的關係:

  • 每個session物件都與瀏覽器一一對應,重新開啟一個瀏覽器,相當於重新建立一個session物件(版本不同可能會有差異)。
  • 通過超連結開啟的新視窗,新視窗的session與其父視窗的session相同。

session的應用場合:
- 登入成功後儲存使用者物件。
- 安全退出。
- 後臺頁面的訪問控制。

Servlet下載

package gacl.response.study;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.URLEncoder;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * 檔案下載
 */
public class ResponseDemo02 extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        downloadChineseFileByOutputStream(response);//下載中文檔案
    }

    /**
     * 下載中文檔案,中文檔案下載時,檔名要經過URL編碼,否則會出現檔名亂碼
     * @param response
     * @throws FileNotFoundException
     * @throws IOException
     */
    private void downloadChineseFileByOutputStream(HttpServletResponse response)
            throws FileNotFoundException, IOException {
        String realPath = this.getServletContext().getRealPath("/download/張家界國家森林公園.JPG");//獲取要下載的檔案的絕對路徑
        String fileName = realPath.substring(realPath.lastIndexOf("\\")+1);//獲取要下載的檔名
        //設定content-disposition響應頭控制瀏覽器以下載的形式開啟檔案,中文檔名要使用URLEncoder.encode方法進行編碼,否則會出現檔名亂碼
        response.setHeader("content-disposition", "attachment;filename="+URLEncoder.encode(fileName, "UTF-8"));
        InputStream in = new FileInputStream(realPath);//獲取檔案輸入流
        int len = 0;
        byte[] buffer = new byte[1024];
        OutputStream out = response.getOutputStream();
        while ((len = in.read(buffer)) > 0) {
            out.write(buffer,0,len);//將緩衝區的資料輸出到客戶端瀏覽器
        }
        in.close();
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}

JSP

JSP內建物件

JSP內建物件是由web容器創造出來的一組物件。常用的JSP內建物件有:out、 request、 response、 session、 application。

  • out 物件:用於向客戶端輸出資訊。
  • request物件:主要用於處理客服端的請求。
  • response物件:用於響應客戶請求並向客戶端輸出資訊。
  • session物件:用於記錄會話狀態的相關資訊。
  • application物件:實現使用者之間的資料共享。

指令元素:(3個)
<%@指令元素名 屬性名=”屬性值” 屬性名2=”屬性值2”… %>

page指令
通過page指令的屬性設定頁面的屬性資訊
import 導包
contentType 內容型別、字符集
每個jsp頁面第一行必須是page指令

指令碼元素:三個(java程式碼)
小指令碼<% %> java程式碼
表示式<%= %> 輸出
宣告<%! %> 方法 (不常用)

註釋:
html註釋 響應給使用者時檢視原始檔可以看到
jsp註釋 響應後檢視原始檔不可以看到
小指令碼中應用java註釋

jsp處理流程(執行過程)
翻譯階段 .jsp—.java (Servlet類)
編譯階段 .java—.class
執行階段 將顯示內容顯示給使用者

為什麼第一次訪問jsp頁面慢,頁面內容不改時再次訪問速度變快?
第一次訪問jsp頁面時需要經歷翻譯-編譯-執行階段
頁面內容不改時再訪問 可以重用.class檔案 直接執行(只經歷執行階段)

jsp與servlet的關係
實質是一個技術
jsp首先會翻譯成一個Servlet類再編譯、執行
jsp、servlet都能實現頁面顯示、處理程式碼
jsp顯示更好
servlet處理更好
jsp和servlet搭配應用

tomcat伺服器 work資料夾–jsp所翻譯的.java、編譯的.class檔案

jsp頁面報錯的程式碼行數–.java檔案行數

調錯:
404 路徑、run as on Server
500 語法錯誤,拋異常,檢視異常資訊,提示錯誤行數
應用system.out…輸出
瀏覽器中右鍵檢視原始檔(jsp)

jsp指令元素
page
include 引入頁面、包含頁面
<%@include file=”頁面路徑”%>

jsp的作用範圍
page 僅在當前頁面有效
pageContext物件
request 在當前請求中有效的
點選連結、輸入url、表單提交、重新整理頁面 請求有效(誕生)
頁面跳轉(路徑變化了) 重新整理頁面 請求失效了 會產生新的請求
如果在request作用範圍中存值,必須採用請求轉發跳轉,跳轉後頁面中可以獲取到request中的值。
session 當前會話中有效
開啟瀏覽器session有效
關閉瀏覽器、session超時、session手動解除安裝(session.invalidate())session失效
application 當前應用程式中有效
開啟伺服器時application有效
關閉伺服器時application失效

作用範圍從小到大
page–request–session–application
ServletContext

應用:
page 用的很少
request 一般用來存用一次的資料
session 一般用來存使用者資訊、購物車(跟蹤)
application 範圍最大的 一般用來存公有資訊、計算訪問人數

原則:
能用小的就不用大的

請求轉發和重定向
如果在request作用範圍中存值,必須採用請求轉發跳轉。
其他情況重定向

cookie和session的對比:

  • session:在伺服器端儲存使用者資訊,session中儲存的是Object型別,隨會話結束而將其儲存的資料銷燬,儲存重要資訊。
  • 在客戶端儲存使用者資訊,cookie中儲存的是字串,cookie可以長期儲存在客戶端,用來儲存不重要資訊。

相關文章