Servlet、JSP總結(1)

Servlet、JSP總結(1)

1、Servlet

Servlet簡介

Java Servlet是和平臺無關的服務器端組件,它運行在Servlet容器中。Servlet容器負責Servlet和客戶的通訊以及調用Servlet的方法**,Servlet和客戶的通訊採用「請求/響應」的模式。** Servlet可完成以下功能:html

  • 建立並返回基於客戶請求的動態HTML頁面。
  • 建立可嵌入到現有HTML 頁面中的部分HTML 頁面(HTML 片斷)。
  • 與其它服務器資源(如數據庫或基於Java的應用程序)進行通訊。

Servlet容器響應客戶請求的工程

ServletAPI

使用 JavaEE 版的 Eclipse 開發動態的 WEB 工程(JavaWEB 項目)

1). 把開發選項切換到 JavaEE 2). 能夠在 Window -> Show View 中找到 Package Explorer, 並把其拖拽到開發區的左邊 3). 在 Servers 面板中新建 Tomcat 服務器. 必定要關聯到 Tomcat 安裝的根目錄 4). 新建一個 Dynamic Web Project. 其中 Target Runtime 需選擇 Tomcat6.0 5). 開發 Java WEB 應用 6). 能夠經過 run on server 來運行 WEB 項目.java

Servlet容器響應客戶請求的過程

①Servlet引擎檢查是否已經裝載並建立了該Servlet的實例對象。若是是,則直接執行第④步,不然,執行第②步。mysql

②裝載並建立該Servlet的一個實例對象:調用該 Servlet 的構造器web

③調用Servlet實例對象的init()方法。sql

④建立一個用於封裝請求的ServletRequest對象和一個表明響應消息的ServletResponse對象,而後調用Servlet的service()方法並將請求和響應對象做爲參數傳遞進去。數據庫

⑤WEB應用程序被中止或從新啓動以前,Servlet引擎將卸載Servlet,並在卸載以前調用Servlet的destroy()方法。express

Servlet 的 HelloWorld

1). 建立一個 Servlet 接口的實現類. public class HelloServlet implements Servlet編程

2). 在 web.xml 文件中配置和映射這個 Servlet設計模式

<!-- 配置和映射 Servlet -->
<servlet>
	<!-- Servlet 註冊的名字 -->
	<servlet-name>helloServlet</servlet-name>
	<!-- Servlet 的全類名 -->
	<servlet-class>com.atguigu.javaweb.HelloServlet</servlet-class>
</servlet>

<servlet-mapping>
	<!-- 須要和某一個 servlet 節點的 serlvet-name 子節點的文本節點一致 -->
	<servlet-name>helloServlet</servlet-name>
	<!-- 映射具體的訪問路徑: / 表明當前 WEB 應用的根目錄. -->
	<url-pattern>/hello</url-pattern>
</servlet-mapping>

3).Servlet 容器: 運行 Servlet、JSP、Filter 等的軟件環境.數組

1). 能夠來建立 Servlet, 並調用 Servlet 的相關生命週期方法. 2). JSP, Filter, Listener, Tag ...

Servlet 生命週期的方法: 如下方法都是由 Serlvet 容器負責調用.

1). 構造器: 只被調用一次. 只有第一次請求 Servlet 時, 建立 Servlet 的實例. 調用構造器. 這說明 Serlvet 的單實例的! 2). init 方法: 只被調用一次. 在建立好實例後當即被調用. 用於初始化當前 Servlet. 3). service: 被屢次調用. 每次請求都會調用 service 方法. 實際用於響應請求的. 4). destroy: 只被調用一次. 在當前 Servlet 所在的 WEB 應用被卸載前調用. 用於釋放當前 Servlet 所佔用的資源.

4).load-on-startup 參數:

1). 配置在 servlet 節點中:

<servlet>
	<!-- Servlet 註冊的名字 -->
	<servlet-name>secondServlet</servlet-name>
	<!-- Servlet 的全類名 -->
	<servlet-class>com.atguigu.javaweb.SecondServlet</servlet-class>
	<!-- 能夠指定 Servlet 被建立的時機 -->
	<load-on-startup>2</load-on-startup>
</servlet>

2). load-on-startup: 能夠指定 Serlvet 被建立的時機. 若爲負數, 則在第一次請求時被建立.若爲 0 或正數, 則在當前 WEB 應用被Serlvet 容器加載時建立實例, 且數組越小越早被建立.

5).關於 serlvet-mapping:

1). 同一個Servlet能夠被映射到多個URL上,即多個 <servlet-mapping> 元素的<servlet-name>子元素的設置值能夠是同一個Servlet的註冊名。

2). 在Servlet映射到的URL中也可使用 * 通配符,可是隻能有兩種固定的格式: 一種格式是「 .擴展名」,另外一種格式是以正斜槓(/)開頭並以「/」結尾。

<servlet-mapping>
	<servlet-name>secondServlet</servlet-name>
	<url-pattern>/*</url-pattern>
</servlet-mapping>

OR

<servlet-mapping>
	<servlet-name>secondServlet</servlet-name>
	<url-pattern>*.do</url-pattern>
</servlet-mapping>

注意: 如下的既帶 / 又帶擴展名的不合法.

<servlet-mapping>
	<servlet-name>secondServlet</servlet-name>
	<url-pattern>/*.action</url-pattern>
</servlet-mapping>

ServletConfig: 封裝了 Serlvet 的配置信息, 而且能夠獲取 ServletContext 對象

Servlet在有些狀況下可能須要訪問Servlet容器或藉助Servlet容器訪問外部的資源,因此,Serlvet引擎須要將表示Servlet容器的對象傳遞給Servlet。另外,在web.xml文件中爲某個Servlet設置的友好名稱和初始化參數等信息也須要傳遞給該Servlet

Servlet引擎將表明Servlet容器的對象(ServletContext)和Servlet的配置參數信息一併封裝到一個稱爲ServletConfig的對象中,並在初始化Servlet實例對象時傳遞給Servlet。ServletConfig接口則用於定義ServletConfig對象須要對外提供的方法,以便在Servlet程序中能夠調用這些方法來獲取有關信息。

Servlet引擎調用Servlet的實例對象的init(ServletConfig config)方法將ServletConfig對象傳遞給Servlet。Servlet.getServletConfig()方法必須返回init(ServletConfig config)方法傳遞進來的這個ServletConfig對象的引用。

1). 配置 Serlvet 的初始化參數

<servlet>
	<servlet-name>helloServlet</servlet-name>
	<servlet-class>com.atguigu.javaweb.HelloServlet</servlet-class>
	
	<!-- 配置 Serlvet 的初始化參數。 且節點必須在 load-on-startup 節點的前面 -->
	<init-param>
		<!-- 參數名 -->
		<param-name>user</param-name>
		<!-- 參數值 -->
		<param-value>root</param-value>
	</init-param>
	
	<init-param>
		<param-name>password</param-name>
		<param-value>1230</param-value>
	</init-param>
	
	<load-on-startup>-1</load-on-startup>
	
</servlet>

2). 獲取初始化參數:

> getInitParameter(String name): 獲取指定參數名的初始化參數
> getInitParameterNames(): 獲取參數名組成的 Enumeration 對象. 

String user = servletConfig.getInitParameter("user");
System.out.println("user: " + user);

Enumeration<String> names = servletConfig.getInitParameterNames();
while(names.hasMoreElements()){
	String name = names.nextElement();
	String value = servletConfig.getInitParameter(name);
	System.out.println("^^" + name + ": " + value);
}

3). 獲取 Serlvet 的配置名稱(瞭解)

ServletContext

Servlet引擎爲每一個WEB應用程序都建立一個對應的ServletContext對象,ServletContext對象被包含在ServletConfig對象中,調用ServletConfig.getServletContext方法能夠返回ServletContext對象的引用。

因爲一個WEB應用程序中的全部Servlet都共享同一個ServletContext對象,因此,ServletContext對象被稱之爲 application 對象(Web應用程序對象)

1). 能夠由 SerlvetConfig 獲取:

ServletContext servletContext = servletConfig.getServletContext();

2). 該對象表明當前 WEB 應用: 能夠認爲 SerlvetContext 是當前 WEB 應用的一個大管家. 能夠從中獲取到當前 WEB 應用的各個方面的信息.

①. 獲取當前 WEB 應用的初始化參數

設置初始化參數: 能夠爲全部的 Servlet 所獲取, 而 Servlet 的初始化參數只用那個 Serlvet 能夠獲取.

<!-- 配置當前 WEB 應用的初始化參數 -->
<context-param>
	<param-name>driver</param-name>
	<param-value>com.mysql.jdbc.Driver</param-value>
</context-param>

方法:

getInitParameter getInitParameterNames

代碼:

ServletContext servletContext = servletConfig.getServletContext();
		
String driver = servletContext.getInitParameter("driver");
System.out.println("driver:" + driver);

Enumeration<String> names2 = servletContext.getInitParameterNames();
while(names2.hasMoreElements()){
	String name = names2.nextElement();
	System.out.println("-->" + name); 
}

②. 獲取當前 WEB 應用的某一個文件在服務器上的絕對路徑, 而不是部署前的路徑

getRealPath(String path);

代碼:

String realPath = servletContext.getRealPath("/note.txt");
System.out.println(realPath);

③. 獲取當前 WEB 應用的名稱:

getContextPath()

代碼:

String contextPath = servletContext.getContextPath();
System.out.println(contextPath);

④. 獲取當前 WEB 應用的某一個文件對應的輸入流.

getResourceAsStream(String path): path 的 / 爲當前 WEB 應用的根目錄.

代碼:

InputStream is2 = servletContext.getResourceAsStream("/WEB-INF/classes/jdbc.properties");

⑤. 和 attribute 相關的幾個方法:

HTTP簡介

  • WEB瀏覽器與WEB服務器之間的一問一答的交互過程必須遵循必定的規則,這個規則就是HTTP協議。
  • HTTP是 hypertext transfer protocol(超文本傳輸協議)的簡寫,它是 TCP/IP 協議集中的一個應用層協議,用於定義WEB瀏覽器與WEB服務器之間交換數據的過程以及數據自己的格式。
  • HTTP協議的版本 HTTP/1.0、HTTP/1.一、HTTP-NG

HTTP的會話方式

一個請求行、若干消息頭、以及實體內容,其中的一些消息頭和實體內容都是可選的,消息頭和實體內容之間要用空行隔開

一個狀態行、若干消息頭、以及實體內容其中的一些消息頭和實體內容都是可選的,消息頭和實體內容之間要用空行隔開

GET 請求和 POST 請求:

1). 使用GET方式傳遞參數:

①. 在瀏覽器地址欄中輸入某個URL地址或單擊網頁上的一個超連接時,瀏覽器發出的HTTP請求消息的請求方式爲GET。 ②. 若是網頁中的<form>表單元素的 method 屬性被設置爲了「GET」,瀏覽器提交這個FORM表單時生成的HTTP請求消息的請求方式也爲GET。 ③. 使用GET請求方式給WEB服務器傳遞參數的格式:

http://www.atguigu.com/counter.jsp?name=lc&password=123

④. 使用GET方式傳送的數據量通常限制在 1KB 如下。

2). 使用 POST 方式傳遞參數:

①. POST 請求方式主要用於向 WEB 服務器端程序提交 FORM 表單中的數據: form 表單的 method 置爲 POST ②. POST 方式將各個表單字段元素及其數據做爲 HTTP 消息的實體內容發送給 WEB 服務器,傳送的數據量要比使用GET方式傳送的數據量大得多。

如何在 Serlvet 中獲取請求信息:

1). Servlet 的 service() 方法用於應答請求: 由於每次請求都會調用 service() 方法

public void service(ServletRequest request, ServletResponse response)
			throws ServletException, IOException

​ ServletRequest: 封裝了請求信息. 能夠從中獲取到任何的請求信息. ServletResponse: 封裝了響應信息, 若是想給用戶什麼響應, 具體可使用該接口的方法實現.

這兩個接口的實現類都是服務器給予實現的, 並在服務器調用 service 方法時傳入.

2). ServletRequest: 封裝了請求信息. 能夠從中獲取到任何的請求信息.

①. 獲取請求參數:

String getParameter(String name): 根據請求參數的名字, 返回參數值. 
若請求參數有多個值(例如 checkbox), 該方法只能獲取到第一個提交的值. 

String[] getParameterValues(String name): 根據請求參數的名字, 返回請求參數對應的字符串數組. 

Enumeration getParameterNames(): 返回參數名對應的 Enumeration 對象, 
相似於 ServletConfig(或 ServletContext) 的 getInitParameterNames() 方法. 

Map getParameterMap(): 返回請求參數的鍵值對: key: 參數名,  value: 參數值, String 數組類型.

②. 獲取請求的 URI:

HttpServletRequest httpServletRequest = (HttpServletRequest) request;
	
String requestURI = httpServletRequest.getRequestURI();
System.out.println(requestURI); //  /day_29/loginServlet

③. 獲取請求方式:

String method = httpServletRequest.getMethod();
System.out.println(method); //GET

④. 如果一個 GET 請求, 獲取請求參數對應的那個字符串, 即 ? 後的那個字符串.

String queryString = httpServletRequest.getQueryString();
System.out.println(queryString); //user=atguigu&password=123456&interesting=game&interesting=party&interesting=shopping

⑤. 獲取請求的 Serlvet 的映射路徑

String servletPath = httpServletRequest.getServletPath();
System.out.println(servletPath);  //  /loginServlet

⑥. 和 attribute 相關的幾個方法:

3). HttpServletRequest: 是 SerlvetRequest 的子接口. 針對於 HTTP 請求所定義. 裏邊包含了大量獲取 HTTP 請求相關的方法.

4). ServletResponse: 封裝了響應信息, 若是想給用戶什麼響應, 具體可使用該接口的方法實現.

①. getWriter(): 返回 PrintWriter 對象. 調用該對象的 print() 方法, 將把 print() 中的參數直接打印 到客戶的瀏覽器上.

②. 設置響應的內容類型: response.setContentType("application/msword");

③. void sendRedirect(String location): 請求的重定向. (此方法爲 HttpServletResponse 中定義.)

GenericServlet:

1). 是一個 Serlvet. 是 Servlet 接口和 ServletConfig 接口的實現類. 可是一個抽象類. 其中的 service 方法爲抽象方法

2). 若是新建的 Servlet 程序直接繼承 GenericSerlvet 會使開發更簡潔.

3). 具體實現:

①. 在 GenericServlet 中聲明瞭一個 SerlvetConfig 類型的成員變量, 在 init(ServletConfig) 方法中對其進行了初始化 ②. 利用 servletConfig 成員變量的方法實現了 ServletConfig 接口的方法 ③. 還定義了一個 init() 方法, 在 init(SerlvetConfig) 方法中對其進行調用, 子類能夠直接覆蓋 init() 在其中實現對 Servlet 的初始化. ④. 不建議直接覆蓋 init(ServletConfig), 由於若是忘記編寫 super.init(config); 而仍是用了 SerlvetConfig 接口的方法, 則會出現空指針異常. ⑤. 新建的 init(){} 並不是 Serlvet 的生命週期方法. 而 init(ServletConfig) 是生命週期相關的方法.

public abstract class GenericServlet implements Servlet, ServletConfig {
    /** 如下方法爲 Servlet 接口的方法 **/
    @Override
    public void destroy() {}

    @Override
    public ServletConfig getServletConfig() {
        return servletConfig;
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    private ServletConfig servletConfig;

    @Override
    public void init(ServletConfig arg0) throws ServletException {
        this.servletConfig = arg0;
        init();
    }

    public void init() throws ServletException{}

    @Override
    public abstract void service(ServletRequest arg0, ServletResponse arg1)
            throws ServletException, IOException;

    /** 如下方法爲 ServletConfig 接口的方法 **/
    @Override
    public String getInitParameter(String arg0) {
        return servletConfig.getInitParameter(arg0);
    }

    @Override
    public Enumeration getInitParameterNames() {
        return servletConfig.getInitParameterNames();
    }

    @Override
    public ServletContext getServletContext() {
        return servletConfig.getServletContext();
    }

    @Override
    public String getServletName() {
        return servletConfig.getServletName();
	}
}

HttpServlet:

1). 是一個 Servlet, 繼承自 GenericServlet. 針對於 HTTP 協議所定製.

2). 在 service() 方法中直接把 ServletReuqest 和 ServletResponse 轉爲 HttpServletRequest 和 HttpServletResponse. 並調用了重載的 service(HttpServletRequest, HttpServletResponse)

在 service(HttpServletRequest, HttpServletResponse) 獲取了請求方式: request.getMethod(). 根據請求方式有建立了 doXxx() 方法(xxx 爲具體的請求方式, 好比 doGet, doPost)

@Override
 public void service(ServletRequest req, ServletResponse res)
    throws ServletException, IOException {
    HttpServletRequest  request;
    HttpServletResponse response;

    try {
        request = (HttpServletRequest) req;
        response = (HttpServletResponse) res;
    } catch (ClassCastException e) {
        throw new ServletException("non-HTTP request or response");
    }
    service(request, response);
}

public void service(HttpServletRequest request,HttpServletResponse response)throws ServletException, IOException {
	//1. 獲取請求方式.
	String method = request.getMethod();
    //2. 根據請求方式再調用對應的處理方法
    if("GET".equalsIgnoreCase(method)){
        doGet(request, response);
    }else if("POST".equalsIgnoreCase(method)){
        doPost(request, response);
    }
}

public void doPost(HttpServletRequest request, HttpServletResponse response) 
		throws ServletException, IOException{
	// TODO Auto-generated method stub
	
}

public void doGet(HttpServletRequest request, HttpServletResponse response) 
		throws ServletException, IOException {
	// TODO Auto-generated method stub
	
}

3). 實際開發中, 直接繼承 HttpServlet, 並根據請求方式複寫 doXxx() 方法便可.

4). 好處: 直接由針對性的覆蓋 doXxx() 方法; 直接使用 HttpServletRequest 和 HttpServletResponse, 再也不須要強轉.

2、JSP

創建對JSP的直觀認識

  • JSP頁面是由HTML語句和嵌套在其中的Java代碼組成的一個普通文本文件,JSP 頁面的文件擴展名必須爲.jsp。 在JSP頁面中編寫的Java代碼須要嵌套在<%和%>中,嵌套在<%和%>之間的Java代碼被稱之爲腳本片斷(Scriptlets),沒有嵌套在<%和%>之間的內容被稱之爲JSP的模版元素。
  • JSP中的Java代碼可使用out.println語句將其餘Java程序代碼產生的結果字符串輸出給客戶端,也可使用System.out.println語句將它們打印到命令行窗口。
  • JSP文件就像普通的HTML文件同樣,它們能夠放置在WEB應用程序中的除了WEB-INF及其子目錄外的其餘任何目錄中,JSP頁面的訪問路徑與普通HTML頁面的訪問路徑形式也徹底同樣。
  • 在JSP頁面中也可使用一種稱之爲JSP表達式的元素,只需將要輸出的變量或表達式直接封裝在<%= 和 %>之中,就能夠向客戶端輸出這個變量或表達式的運算結果。在JSP表達式中嵌套的變量或表達式後面不能有分號。

WHY

JSP 是簡 Servlet 編寫的一種技術, 它將 Java 代碼和 HTML 語句混合在同一個文件中編寫, 只對網頁中的要動態產生的內容採用 Java 代碼來編寫,而對固定不變的靜態內容採用普通靜態 HTML 頁面的方式編寫。

Java Server Page: Java 服務器端網頁. 在 HTML 頁面中編寫 Java 代碼的頁面.

JSP 能夠放置在 WEB 應用程序中的除了 WEB-INF 及其子目錄外的其餘任何目錄中, JSP 頁面的訪問路徑與普通 HTML 頁面的訪問路徑形式也徹底同樣

helloword

新建一個 JSP 頁面, 在 body 節點內的 <% %> 便可編寫 Java 代碼.

<body>
	<% 
		Date date = new Date();
		System.out.print(date); 
	%>
</body>

JSP運行原理

SP 本質上是一個 Servlet.

每一個JSP 頁面在第一次被訪問時, JSP 引擎將它翻譯成一個 Servlet 源程序, 接着再把這個 Servlet 源程序編譯成 Servlet 的 class 類文件. 而後再由WEB容器(Servlet引擎)像調用普通Servlet程序同樣的方式來裝載和解釋執行這個由JSP頁面翻譯成的Servlet程序。

JSP隱含對象

沒有聲明就可使用的對象. JSP頁面一共有 9 個隱含對象.

public void _jspService(HttpServletRequest request, HttpServletResponse response)
        throws java.io.IOException, ServletException {

    PageContext pageContext = null;
    HttpSession session = null;
    ServletContext application = null;
    ServletConfig config = null;
    JspWriter out = null;
    Object page = this;

	//...
	
	//使用  <% %> 編寫的代碼在此位置. 能夠用到 request, response, pageContext, session
	//application, config, out, page 這 8 個隱含對象. (實際上還可使用一個叫 exception 的隱含對象)
    
}

①. request: HttpServletRequest 的一個對象. * ②. response: HttpServletResponse 的一個對象(在 JSP 頁面中幾乎不會調用 response 的任何方法.)

③. pageContext: 頁面的上下文, 是 PageContext 的一個對象. 能夠從該對象中獲取到其餘 8 個隱含對象. 也能夠從中獲取到當前 頁面的其餘信息. (學習自定義標籤時使用它) * ④. session: 表明瀏覽器和服務器的一次會話, 是 HttpSession 的一個對象. 後面詳細學習. *

⑤. application: 表明當前 WEB 應用. 是 ServletContext 對象. * ⑥. config: 當前 JSP 對應的 Servlet 的 ServletConfig 對象(幾乎不使用). 若須要訪問當前 JSP 配置的初始化參數, 須要經過映射的地址才能夠.

映射 JSP:

<servlet>
  	<servlet-name>hellojsp</servlet-name>
  	<jsp-file>/hello.jsp</jsp-file>
  	<init-param>
  		<param-name>test</param-name>
  		<param-value>testValue</param-value>
  	</init-param>
  </servlet>
  
  <servlet-mapping>
  	<servlet-name>hellojsp</servlet-name>
	<url-pattern>/hellojsp</url-pattern>  	
  </servlet-mapping>

⑦. out: JspWriter 對象. 調用 out.println() 能夠直接把字符串打印到瀏覽器上. * ⑧. page: 指向當前 JSP 對應的 Servlet 對象的引用, 但爲 Object 類型, 只能調用 Object 類的方法(幾乎不使用)

⑨. exception: 在聲明瞭 page 指令的 isErrorPage="true" 時, 纔可使用. *

JSP語法

1)腳本程序<% %> ,JSP腳本片段(scriptlet)是指嵌套在<% 和 %>之中的一條或多條Java程序代碼。 多個腳本片段中的代碼能夠相互訪問,單個腳本片段中的Java語句能夠是不完整的,可是,多個腳本片段組合後的結果必須是完整的Java語句

<% 
	Date date = new Date();
	out.print(date);
%>

2). JSP表達式:供了將一個 java 變量或表達式的計算結果輸出到客戶端的簡化方式, 它將要輸出的變量或表達式直接封裝在<%= 和 %>之中。

<% 
	Date date = new Date();
	out.print(date);
%>

<%= date %>

3).模板元素:jsp中html元素

4).JSP 聲明: JSP 聲明將 Java 代碼封裝在<%!和 %>之中,它裏面的代碼將被插入進 Servle t的 _jspService 方法的外面(在 JSP 頁面中幾乎從不這樣使用)

區別: JSP 註釋能夠阻止 Java 代碼的執行.

和屬性相關的方法:

1). 方法

  • void setAttribute(String name, Object o): 設置屬性
  • Object getAttribute(String name): 獲取指定的屬性
  • Enumeration getAttributeNames(): 獲取全部的屬性的名字組成的 Enumeration 對象
  • removeAttribute(String name): 移除指定的屬性

2). pageContext, request, session, application 對象都有這些方法! 這四個對象也稱之爲域對象.

  • pageContext: 屬性的做用範圍僅限於當前 JSP 頁面
  • request: 屬性的做用範圍僅限於同一個請求.
  • session: 屬性的做用範圍限於一次會話: 瀏覽器打開直到關閉稱之爲一次會話(在此期間會話不失效)
  • application: 屬性的做用範圍限於當前 WEB 應用. 是範圍最大的屬性做用範圍, 只要在一處設置屬性, 在其餘各處的 JSP 或 Servlet 中均可以獲取到.

請求的轉發與重定向

本質區別: 請求的轉發只發出了一次請求, 而重定向則發出了兩次請求.

具體:

①. 請求的轉發: 地址欄是初次發出請求的地址. 請求的重定向: 地址欄再也不是初次發出的請求地址. 地址欄爲最後響應的那個地址

②. 請求轉發: 在最終的 Servlet 中, request 對象和中轉的那個 request 是同一個對象. 請求的重定向: 在最終的 Servlet 中, request 對象和中轉的那個 request 不是同一個對象.

③. 請求的轉發: 只能轉發給當前 WEB 應用的的資源 請求的重定向: 能夠重定向到任何資源.

④. 請求的轉發: / 表明的是當前 WEB 應用的根目錄 請求的重定向: / 表明的是當前 WEB 站點的根目錄.

1).RequestDispatcher接口

RequestDispatcher實例對象是由Servlet引擎建立的,它用於包裝一個要被其餘資源調用的資源(例如,Servlet、HTML文件、JSP文件等),並能夠經過其中的方法將客戶端的請求轉發給所包裝的資源。

•RequestDispatcher接口中定義了兩個方法:forward方法和include方法。

•forward和include方法接收的兩個參數必須是傳遞給當前Servlet的service方法的那兩個ServletRequest和ServletResponse對象,或者是對它們進行了包裝的ServletRequestWrapper 或ServletResponseWrapper對象。

•獲取RequestDispatcher對象的方法:

ServletContext.getRequestDispatcher (參數只能是以「/」開頭的路徑)

ServletContext.getNamedDispatcher

ServletRequest.getRequestDispatcher(參數能夠是不以「/」開頭的路徑)

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ForwardServlet extends HttpServlet {
	
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("ForwardServlet's doGet");
		
		request.setAttribute("name", "abcde");
		System.out.println("ForwardServlet's name: " + request.getAttribute("name"));
		
		//請求的轉發.
		//1. 調用 HttpServletRequest 的 getRequestDispatcher() 方法獲取  RequestDispatcher 對象
		//調用 getRequestDispatcher() 須要傳入要轉發的地址
		String path = "testServlet";
		RequestDispatcher requestDispatcher = request.getRequestDispatcher("/" + path);
		
		//2. 調用 HttpServletRequest 的 forward(request, response) 進行請求的轉發. 
		requestDispatcher.forward(request, response); 
	}

}

2).用sendRedirect方法實現請求重定向

sendRedirect 方法不只能夠重定向到當前應用程序中的其餘資源,它還能夠重定向到同一個站點上的其餘應用程序中的資源,甚至是使用絕對URL重定向到其餘站點的資源。

​ 若是傳遞給sendRedirect 方法的相對URL以「/」開頭,則是相對於整個WEB站點的根目錄,而不是相對於當前WEB應用程序的根目錄。

package com.atguigu.javaweb;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class RedirectServlet extends HttpServlet {
	
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("RedirectServlet's doGet");
		
		request.setAttribute("name", "xyzmn");
		System.out.println("RedirectServlet's name: " + request.getAttribute("name"));
		
		
		//執行請求的重定向, 直接調用 response.sendRedirect(path) 方法,
		//path 爲要重定向的地址
		String path = "testServlet";
		response.sendRedirect(path);
	}

}

3).請求重定向與請求轉發的比較

  • RequestDispatcher.forward方法只能將請求轉發給同一個WEB應用中的組件;而HttpServletResponse.sendRedirect 方法還能夠重定向到同一個站點上的其餘應用程序中的資源,甚至是使用絕對URL重定向到其餘站點的資源。
  • 若是傳遞給HttpServletResponse.sendRedirect 方法的相對URL以「/」開頭,它是相對於整個WEB站點的根目錄;若是建立RequestDispatcher對象時指定的相對URL以「/」開頭,它是相對於當前WEB應用程序的根目錄。
  • 調用HttpServletResponse.sendRedirect方法重定向的訪問過程結束後,瀏覽器地址欄中顯示的URL會發生改變,由初始的URL地址變成重定向的目標URL;調用RequestDispatcher.forward 方法的請求轉發過程結束後,瀏覽器地址欄保持初始的URL地址不變。
  • HttpServletResponse.sendRedirect方法對瀏覽器的請求直接做出響應,響應的結果就是告訴瀏覽器去從新發出對另一個URL的訪問請求;RequestDispatcher.forward方法在服務器端內部將請求轉發給另一個資源,瀏覽器只知道發出了請求並獲得了響應結果,並不知道在服務器程序內部發生了轉發行爲。
  • RequestDispatcher.forward方法的調用者與被調用者之間共享相同的request對象和response對象,它們屬於同一個訪問請求和響應過程;而HttpServletResponse.sendRedirect方法調用者與被調用者使用各自的request對象和response對象,它們屬於兩個獨立的訪問請求和響應過程。

JSP指令

JSP指令(directive)是爲JSP引擎而設計的, 它們並不直接產生任何可見輸出, 而只是告訴引擎如何處理JSP頁面中的其他部分。

在目前的JSP 2.0中,定義了page、include 和 taglib這三種指令

1)page指令: page指令用於定義JSP頁面的各類屬性, 不管page指令出如今JSP頁面中的什麼地方, 它做用的都是整個JSP頁面, 爲了保持程序的可讀性和遵循良好的編程習慣, page指令最好是放在整個JSP頁面的起始位置。

Page指令的經常使用屬性:

①. import 屬性: 指定當前 JSP 頁面對應的 Servlet 須要導入的類. <%@page import="java.text.DateFormat"%>

②. session 屬性: 取值爲 true 或 false, 指定當前頁面的 session 隱藏變量是否可用, 也能夠說訪問當前頁面時是否必定要生成 HttpSession 對象. <%@ page session="false" %>

③. errorPage 和 isErrorPage:

  • errorPage 指定若當前頁面出現錯誤的實際響應頁面時什麼. 其中 / 表示的是當前 WEB 應用的根目錄. <%@ page errorPage="/error.jsp" %>
  • 在響應 error.jsp 時, JSP 引擎使用的請求轉發的方式. \
  • isErrorPage 指定當前頁面是否爲錯誤處理頁面, 能夠說明當前頁面是否可使用 exception 隱藏變量. 須要注意的是: 若指定 isErrorPage="true", 並使用 exception 的方法了, 通常不建議可以直接訪問該頁面.
  • 如何使客戶不能直接訪問某一個頁面呢 ? 對於 Tomcat 服務器而言, WEB-INF 下的文件是不能經過在瀏覽器中直接輸入地址的方式來訪問的. 但經過請求的轉發是能夠的!
  • 還能夠在 web.xml 文件中配置錯誤頁面:
<error-page>
    <!-- 指定出錯的代碼: 404 沒有指定的資源, 500 內部錯誤. --
    <error-code>404</error-code>
    <!-- 指定響應頁面的位置 -->
    <location>/WEB-INF/error.jsp</location>
</error-page>

<error-page>
    <!-- 指定異常的類型 -->
    <exception-type>java.lang.ArithmeticException</exception-type>
    <location>/WEB-INF/error.jsp</location>
</error-page>

④. contentType: 指定當前 JSP 頁面的響應類型. 實際調用的是 response.setContentType("text/html; charset=UTF-8"); 一般狀況下, 對於 JSP 頁面而言其取值均爲 text/html; charset=UTF-8. charset 指定返回的頁面的字符編碼是什麼. 一般取值爲 UTF-8

⑤. pageEncoding: 指定當前 JSP 頁面的字符編碼. 一般狀況下該值和 contentType 中的 charset 一致.

⑥. isELIgnored: 指定當前 JSP 頁面是否可使用 EL 表達式. 一般取值爲 false.

2).include指令<%@ include file="b.jsp" %>

1). include 指令用於通知 JSP 引擎在翻譯當前 JSP 頁面時將其餘文件中的內容合併進當前 JSP 頁面轉換成的 Servlet 源文件中, 這種在源文件級別進行引入的方式稱之爲靜態引入, 當前JSP頁面與靜態引入的頁面緊密結合爲一個Servlet。

2). file屬性的設置值必須使用相對路徑

3). 若是以 / 開頭,表示相對於當前WEB應用程序的根目錄(注意不是站點根目錄),不然,表示相對於當前文件。

細節:

  • 除了指令元素以外,被引入的文件中的其餘元素都被轉換成相應的Java源代碼,而後插入進當前JSP頁面所翻譯成的Servlet源文件中,插入位置與include指令在當前JSP頁面中的位置保持一致。
  • 引入文件與被引入文件是在被JSP引擎翻譯成Servlet的過程當中進行合併,而不是先合併源文件後再對合並的結果進行翻譯。當前JSP頁面的源文件與被引入文件的源文件能夠採用不一樣的字符集編碼,即便在一個頁面中使用page指令的pageEncoding或contentType屬性指定了其源文件的字符集編碼,在另一個頁面中還須要用page指令的pageEncoding或contentType屬性指定其源文件所使用的字符集 。
  • Tomcat 5.x在訪問JSP頁面時,能夠檢測它所引入的其餘文件是否發生了修改,若是發生了修改,則從新編譯當前JSP頁面
  • file屬性的設置值必須使用相對路徑,若是以「/」開頭,表示相對於當前WEB應用程序的根目錄(注意不是站點根目錄),不然,表示相對於當前文件。

JSP標籤(JSP行爲)

JSP還提供了一種稱之爲Action的元素,在JSP頁面中使用Action元素能夠完成各類通用的JSP頁面功能,也能夠實現一些處理複雜業務邏輯的專用功能。

Action元素採用XML元素的語法格式,即每一個Action元素在JSP頁面中都以XML標籤的形式出現。

JSP規範中定義了一些標準的Action元素,這些元素的標籤名都以jsp做爲前綴,而且所有采用小寫,例如,jsp:includejsp:forward等等

1).<jsp:include >標籤

jsp:include標籤用於把另一個資源的輸出內容插入進當前JSP頁面的輸出內容之中,這種在JSP頁面執行時的引入方式稱之爲動態引入。

page屬性用於指定被引入資源的相對路徑,它也能夠經過執行一個表達式來得到。

flush屬性指定在插入其餘資源的輸出內容時,是否先將當前JSP頁面的已輸出的內容刷新到客戶端。

2).<jsp:include >標籤與include指令的比較

  • <jsp:include >標籤是在當前JSP頁面的執行期間插入被引入資源的輸出內容,當前JSP頁面與被動態引入的資源是兩個彼此獨立的執行實體,被動態引入的資源必須是一個能獨立被WEB容器調用和執行的資源。include指令只能引入遵循JSP格式的文件,被引入文件與當前JSP文件共同合被翻譯成一個Servlet的源文件。
  • 使用<jsp:include >標籤和include指令均可以把一個頁面的內容分紅多個組件來生成,開發者沒必要再把頁眉和頁腳部分的相同HTML代碼複製到每一個JSP文件中,從而能夠更輕鬆地完成維護工做,可是都應注意最終的輸出結果內容應遵循HTML語法結構,例如,若是當前頁面產生了<html>、</html>、<body>、</body>等標記,那麼在被引入文件中就不能再輸出<html>、</html>、<body>、</body>等標記。
  • <jsp:include >標籤對JSP引擎翻譯JSP頁面的過程不起做用,它是在JSP頁面的執行期間才被調用,所以不會影響兩個頁面的編譯。因爲include指令是在JSP引擎翻譯JSP頁面的過程當中被解釋處理的,因此它對JSP引擎翻譯JSP頁面的過程起做用,若是多個JSP頁面中都要用到一些相同的聲明,那麼就能夠把這些聲明語句放在一個單獨的文件中編寫,而後在每一個JSP頁面中使用include指令將那個文件包含進來。
  • <jsp:include >標籤使用page屬性指定被引入資源的相對路徑,而include指令使用file屬性指定被引入資源的相對路徑

3).<jsp:forward >標籤

<jsp:forward >標籤用於把請求轉發給另一個資源。 語法: <jsp:forward page="relativeURL | <%=expression%>" />

page屬性用於指定請求轉發到的資源的相對路徑,它也能夠經過執行一個表達式來得到

RequestDispatcher.forward方法、PageContext.forward方法、jsp:forward

籤的區別

調用RequestDispatcher.forward方法的JSP腳本代碼的先後不能有JSP模版內容。

調用PageContext.forward方法的JSP腳本代碼的後面不能有JSP模版內容。

<Jsp:forward >標籤的先後都能有JSP模版內容。

4).<jsp:param >標籤

當使用jsp:includejsp:forward標籤引入或將請求轉發給的資源是一個能動態執行的程序時,例如Servlet和JSP頁面,那麼,還可使用jsp:param標籤向這個程序傳遞參數信息。 語法1:

<jsp:include page="relativeURL | <%=expression%>">
	<jsp:param name="parameterName" value="parameterValue|<%=expression %>" />
</jsp:include >

語法2:

<jsp:forward page="relativeURL | <%=expression%>">
	<jsp:param name="parameterName" value="parameterValue|<%=expression %>" />
</jsp:include>

<jsp:param > 標籤的name屬性用於指定參數名,value屬性用於指定參數值。在<jsp:include >和<jsp:forward >標籤中可使用多個<jsp:param >標籤來傳遞多個參數。

關於中文亂碼

1). 在 JSP 頁面上輸入中文, 請求頁面後不出現亂碼: 保證

contentType="text/html; charset=UTF-8", pageEncoding="UTF-8"

charset 和 pageEncoding 的編碼一致, 且都支持中文. 一般建議取值爲UTF-8還需保證瀏覽器的顯示的字符編碼也和請求的 JSP 頁面的編碼一致.

2). 獲取中文參數值: 默認參數在傳輸過程當中使用的編碼爲 ISO-8859-1

①. 對於 POST 請求: 只要在獲取請求信息以前(在調用 request.getParameter 或者是 request.getReader 等), 調用 request.setCharacterEncoding("UTF-8") 便可.

②. 對於 GET 請求: 前面的方式對於 GET 無效. 能夠經過修改 Tomcat 的 server.xml 文件的方式.

參照 http://localhost:8989/docs/config/index.html 文檔的 useBodyEncodingForURI 屬性. 爲 Connector 節點添加 useBodyEncodingForURI="true" 屬性便可.

<Connector connectionTimeout="20000" port="8989" protocol="HTTP/1.1" redirectPort="8443" useBodyEncodingForURI="true"/>

3、MVC設計模式

JavaEE開發中經常使用的組件

  • commons-beansutils
  • commons-dbcp
  • commons-dbutils
  • commons-fileupload
  • commons-logging
  • hibernate-refease
  • jbpm

MVC的概念

MVC是Model-View-Controller的簡稱,即模型-視圖-控制器。MVC是一種設計模式,它把應用程序分紅三個核心模塊:模型、視圖、控制器,它們各自處理本身的任務。

1).模型(model)

模型是應用程序的主體部分,模型表示業務數據和業務邏輯

一個模型能爲多個視圖提供數據。

因爲應用於模型的代碼只需寫一次就能夠被多個視圖重用,因此提升了代碼的可重用性。

2).視圖(view)

•視圖是用戶看到並與之交互的界面,做用以下:

  • 視圖向用戶顯示相關的數據。
  • 接受用戶的輸入。
  • 不進行任何實際的業務處理。

2).控制器(controler)

•控制器接受用戶的輸入並調用模型和視圖去完成用戶的需求。

•控制器接收請求並決定調用哪一個模型組件去處理請求,而後決定調用哪一個視圖來顯示模型處理返回的數據。

4、會話與狀態管理

  • HTTP協議是一種無狀態的協議,WEB服務器自己不能識別出哪些請求是同一個瀏覽器發出的 ,瀏覽器的每一次請求都是徹底孤立的
  • 即便 HTTP1.1 支持持續鏈接,但當用戶有一段時間沒有提交請求,鏈接也會關閉。
  • 怎麼才能實現網上商店中的購物車呢:某個用戶從網站的登陸頁面登入後,再進入購物頁面購物時,負責處理購物請求的服務器程序必須知道處理上一次請求的程序所獲得的用戶信息。
  • 做爲 web 服務器,必須可以採用一種機制來惟一地標識一個用戶,同時記錄該用戶的狀態

如何實現有狀態的會話

WEB服務器端程序要能從大量的請求消息中區分出哪些請求消息屬於同一個會話,即能識別出來自同一個瀏覽器的訪問請求,這須要瀏覽器對其發出的每一個請求消息都進行標識屬於同一個會話中的請求消息都附帶一樣的標識號,而屬於不一樣會話的請求消息老是附帶不一樣的標識號,這個標識號就稱之爲會話ID(SessionID)。

在 Servlet 規範中,經常使用如下兩種機制完成會話跟蹤

  • Cookie
  • Session

Cookie機制

  • cookie機制採用的是在客戶端保持 HTTP 狀態信息的方案
  • Cookie是在瀏覽器訪問WEB服務器的某個資源時,由WEB服務器在HTTP響應消息頭中附帶傳送給瀏覽器的一個小文本文件。
  • 一旦WEB瀏覽器保存了某個Cookie,那麼它在之後每次訪問該WEB服務器時,都會在HTTP請求頭中將這個Cookie回傳給WEB服務器。
  • 底層的實現原理: WEB服務器經過在HTTP響應消息中增長Set-Cookie響應頭字段將Cookie信息發送給瀏覽器,瀏覽器則經過在HTTP請求消息中增長Cookie請求頭字段將Cookie回傳給WEB服務器。
  • 一個Cookie只能標識一種信息,它至少含有一個標識該信息的名稱(NAME)和設置值(VALUE)。
  • 一個WEB站點能夠給一個WEB瀏覽器發送多個Cookie,一個WEB瀏覽器也能夠存儲多個WEB站點提供的Cookie。
  • 瀏覽器通常只容許存放300個Cookie,每一個站點最多存放20個Cookie,每一個Cookie的大小限制爲4KB。
相關文章
相關標籤/搜索