<1>精研Servlet,HttpServlet的實現追究

提早聲明:我的說的不必定對,若有錯誤之處,請批評指出. html

Servlet的優勢:

servlet能夠很好地替代公共網關接口(Common Gateway Interface,CGI)腳本。一般CGI腳本是用Perl或者C語言編寫的,它們老是和特定的服務器平臺緊密相關。而servlet是用Java編寫的,因此它們一開始就是平臺無關的。這樣,Java編寫一次就能夠在任何平臺運行(write once,run anywhere)的承諾就一樣能夠在服務器上實現了。servlet還有一些CGI腳本所不具有的獨特優勢: java

  • 一、servlet是持久的。servlet只需Web服務器加載一次,並且能夠在不一樣請求之間保持服務(例如一次數據庫鏈接)。與之相反,CGI腳本是短暫的、瞬態的。每一次對CGI腳本的請求,都會使Web服務器加載並執行該腳本。一旦這個CGI腳本運行結束,它就會被從內存中清除,而後將結果返回到客戶端。CGI腳本的每一次使用,都會形成程序初始化過程(例如鏈接數據庫)的重複執行。
  • 二、servlet是與平臺無關的。如前所述,servlet是用Java編寫的,它天然也繼承了Java的平臺無關性。
  • 三、servlet是可擴展的。因爲servlet是用Java編寫的,它就具有了Java所能帶來的全部優勢。Java是健壯的、面向對象的編程語言,它很容易擴展以適應你的需求。servlet天然也具有了這些特徵。
  • 四、servlet是安全的。從外界調用一個servlet的唯一方法就是經過Web服務器。這提供了高水平的安全性保障,尤爲是在你的Web服務器有防火牆保護的時候。
  • 五、setvlet能夠在多種多樣的客戶機上使用。因爲servlet是用Java編寫的,因此你能夠很方便地在HTML中使用它們,就像你使用applet同樣。

但值得注意的是Servlet並不侷限於Web領域(或者說是HTTP協議相關).你可能要本身去擴展javax.servlet.GenericServlet .上面第三點就是這個意思.
好比說:擴展javax.servlet.GenericServlet實現一個Servlet,搞搞電子郵件的smtp(Simple Mail Transfer Protocol 即簡單郵件傳輸協議)服務器,你就是基於SMTP協議擴展了GenericServlet ,也許你會叫它SMTPServlet.咱們用的HttpServlet不就這個命名規範嘛.
綜上所述,Servlet能夠在各類協議下良好的運行應用程序. web

也許如今不少人再也不寫Servlet,但Servlet是心臟,Servlet放在剛出世的時候,仍是很是NB的.到如今,各類成熟好用的東西不少了.但不能忘本.....再深點說  爲何要這麼設計,體現了什麼?我還真是說不上來了,我以爲上面的幾點也已經代表爲何了.就是Java對協議的一個設計.....

JSP的本質就是Servlet,或者說(是吧,開始說的是java,汗)JavaWeb開發的本質也就是Servlet+JDBC.任何性質的框架技術最底層的依然是基於他們2個.所以若是本身想寫一套如SSH那樣的框架技術,Java最底層的東西是必須掌握的. 數據庫

Servlet被稱爲"服務器端小程序."是運行在服務器端的程序,用於處理以及響應客戶端的請求. 編程

HTTP 目前支持 7 種請求方法: GET  POST   PUT  DELETE  TARCE,HEAD  OPTIONS .前四個都是客戶端請求數據這類相關的方法. 小程序

  • GET      請求獲取由Request-URI所標識的資源。
  • POST Request-URI所標識的資源後附加新的數據。
  • PUT 請求服務器存儲一個資源,並用Request-URI做爲其標識。
  • DELETE 請求服務器刪除由Request-URI所標識的資源。

  • TRACE 請求服務器回送收到的請求信息,主要用語測試或診斷。
  • HEAD 請求獲取由Request-URI所標識的資源的響應消息報頭。
  • OPTIONS 請求查詢服務器的性能,或查詢與資源相關的選項和需求。

我在這裏只是列出HTTP的請求方法,具體的HTTP協議請參考這篇文章:http://my.oschina.net/zhaoqian/blog/90315 瀏覽器

Servlet是個特殊的類,這個類必須繼承HttpServlet.Servlet提供了相對於HTTP數據請求的四個方法的請求(其餘三個也提供了,但我懶得寫了,不多用到). 緩存

  • doGet:用於響應上面綠色字體的GET請求.
  • doPost:用於響應客戶端的POST請求.
  • doPut:用於響應客戶端的PUT請求.
  • doDelete:用於響應客戶端的Delete請求.

事實上,HTTP這個大好青年被浪費了,大部分咱們就是使用GET/POST請求,至於PUT/DELETE都不知道被遺棄到哪裏去了.但最近幾年興起的一種REST模型的WEB服務,讓HTTP協議發出了第二春.具體詳見:http://my.oschina.net/zhaoqian/blog/90321 安全

而諸如Struts2,SpringMVC這類的框架,也就是使用GET/POST,但工做時間久後,愈加的感受到,不少新技術,不必去追,所須要的是,搞清楚追底層的,以不變的底層去應對萬變的新技術. 服務器

Servlet的示例代碼:

package org.credo.test;

import java.io.IOException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * <P>Project: Credo's Base</P>
 * <P>Description:Servlet3.0的第一個測試. </P>
 * <P>Copyright (c) 2012 LionCredo.All Rights Reserved.</P>
 * @author <a href="zhaoqianjava@qq.com">LionCredo</a>
 */
@WebServlet(name="firstServlet",urlPatterns="/firstServlet")
public class ServletTest1 extends HttpServlet{

	private static final long serialVersionUID = -2149324298582445679L;
	
	@Override
	public void init(ServletConfig config) throws ServletException {
		//初始化Servlet的時候,能夠在這裏完成某些初始化的方法.
		super.init(config);
	}
	
	@Override
	protected void service(HttpServletRequest arg0, HttpServletResponse arg1) throws ServletException, IOException {
		//大部分時候,對於全部請求都是同樣的話,能夠重寫HttpServlet的Service方法來替代doGet/doPost這些方法.
		super.service(arg0, arg1);
	}
	
	@Override
	public void destroy() {
		// 在銷燬Servlet以前,須要完成某些資源的回收,好比關閉數據庫連接等,能夠寫在這裏.
		super.destroy();
	}
}

HttpServlet

public abstract class javax.servlet.http

Extends: GenericServlet

Implements: java.io.Serializable

提供將要被子類化以建立適用於 Web 站點的 HTTP servlet 的抽象類。HttpServlet 的子類至少必須重寫一個方法,該方法一般是如下這些方法之一:

 •doGet,若是 servlet 支持 HTTP GET 請求 
•doPost,用於 HTTP POST 請求 
•doPut,用於 HTTP PUT 請求 
•doDelete,用於 HTTP DELETE 請求 
•init 和 destroy,用於管理 servlet 的生命週期內保存的資源 
•getServletInfo,servlet 使用它提供有關其自身的信息 

幾乎沒有理由重寫 service 方法。service 經過將標準 HTTP 請求分發給每一個 HTTP 請求類型的處理程序方法(上面列出的 doXXX 方法)來處理它們。 
一樣,幾乎沒有理由重寫 doOptions 和 doTrace 方法。 
servlet 一般運行在多線程服務器上,所以應該意識到 servlet 必須處理併發請求並當心地同步對共享資源的訪問。共享資源包括內存數據(好比實例或類變量)和外部對象(好比文件、數據庫鏈接和網絡鏈接)。有關在 Java 程序中處理多個線程的更多信息,請參見 Java Tutorial on Multithreaded Programming。 

上面是查閱官方的API所得的說明,實際上javaweb開發中,不多有web開發徹底嚴格的使用Http協議.因此說大好青年浪費不是沒道理的,但商業的實現手段就是商業的實現手段,技術永遠是其次的.固然,REST這個嘛,第二春....再詳細的方法就看HttpServlet的源碼或者API.

另外,爲何不重寫servlet的service方法有更詳細的文章:http://my.oschina.net/dtkking/blog/89443

===========================================

一個Servlet繼承抽象類HttpServlet,而HttpServlet繼承GenericServlet,

abstract  GenericServlet

Implements: Servlet, ServletConfig, java.io.Serializable
Extended by: HttpServlet
定義通常的、與協議無關的 servlet。要編寫用於 Web 上的 HTTP servlet,請改成擴展 javax.servlet.http.HttpServlet。 
GenericServlet 實現 Servlet 和 ServletConfig 接口。servlet 能夠直接擴展 GenericServlet,儘管擴展特定於協議的子類(好比 HttpServlet)更爲常見。 
GenericServlet 使編寫 servlet 變得更容易。它提供生命週期方法 init 和 destroy 的簡單版本,以及 ServletConfig 接口中的方法的簡單版本。GenericServlet 還實現 log 方法,在 ServletContext 接口中對此進行了聲明。 
要編寫通常的 servlet,只需重寫抽象 service 方法便可。 

剝離了一大堆註釋的源碼:

package javax.servlet;

import java.io.IOException;
import java.util.Enumeration;

public abstract class GenericServlet implements Servlet, ServletConfig,
        java.io.Serializable {

    private static final long serialVersionUID = 1L;

    //java語言的關鍵字,變量修飾符,若是用transient聲明一個實例變量,當對象存儲時,它的值不須要維持。   
    //Java的serialization提供了一種持久化對象實例的機制。
    //當持久化對象時,可能有一個特殊的對象數據成員,咱們不想用serialization機制來保存它。
    //爲了在一個特定對象的一個域上關閉serialization,能夠在這個域前加上關鍵字transient。
    //當一個對象被串行化的時候,transient型變量的值不包括在串行化的表示中,然而非transient型的變量是被包括進去的。
    private transient ServletConfig config;

    public GenericServlet() {
        //構造方法
    }

    @Override
    public void destroy() {
        //銷燬
    }

    @Override
    public String getInitParameter(String name) {
        return getServletConfig().getInitParameter(name);
    }

    @Override
    public Enumeration<String> getInitParameterNames() {
        return getServletConfig().getInitParameterNames();
    }

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

     */
    @Override
    public ServletContext getServletContext() {
        return getServletConfig().getServletContext();
    }

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

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

    public void init() throws ServletException {
        // NOOP by default
    }

    public void log(String msg) {
        getServletContext().log(getServletName() + ": " + msg);
    }

    public void log(String message, Throwable t) {
        getServletContext().log(getServletName() + ": " + message, t);
    }

    @Override
    public abstract void service(ServletRequest req, ServletResponse res)
            throws ServletException, IOException;

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

能夠看到,HttpServlet,是基於Http協議擴展了GenericServlet的抽象類.

GenericServlet是實現了Servlet,ServletConfig,以及必須的Serializable序列化.下面主要看實現的2個接口,Servlet,ServletConfig都定義了那些接口.

===========================================================

public interface javax.servlet

Implemented by: FacesServlet, GenericServlet, JspPage
定義全部 servlet 都必須實現的方法。 
servlet 是運行在 Web 服務器中的小型 Java 程序。servlet 一般經過 HTTP(超文本傳輸協議)接收和響應來自 Web 客戶端的請求。 

要實現此接口,能夠編寫一個擴展 javax.servlet.GenericServlet 的通常 servlet,或者編寫一個擴展 javax.servlet.http.HttpServlet 的 HTTP servlet。 

此接口定義了初始化 servlet 的方法、爲請求提供服務的方法和從服務器移除 servlet 的方法。這些方法稱爲生命週期方法,它們是按如下順序調用的: 
1.構造 servlet,而後使用 init 方法將其初始化。 
2.處理來自客戶端的對 service 方法的全部調用。 
3.從服務中取出 servlet,而後使用 destroy 方法銷燬它,最後進行垃圾回收並終止它。 

除了生命週期方法以外,此接口還提供了 getServletConfig 方法和 getServletInfo 方法,servlet 可以使用前一種方法得到任何啓動信息,然後一種方法容許 servlet 返回有關其自身的基本信息,好比做者、版本和版權。 

能夠看源碼,API,均可以發現servlet是一個接口.定義了五個方法.

package javax.servlet;

import java.io.IOException;

public interface Servlet {

    public void init(ServletConfig config) throws ServletException;

    public ServletConfig getServletConfig();
    
    public void service(ServletRequest req, ServletResponse res)
            throws ServletException, IOException;

    public String getServletInfo();
    
    public void destroy();
}

 public interface javax.servlet  ServletConfig 

Implemented by: GenericServlet
 servlet 容器使用的 servlet 配置對象,該對象在初始化期間將信息傳遞給 servlet。 

看上圖Servlet接口中有 getServletConfig.從這個接口的定義能夠結合起來.

package javax.servlet;

import java.util.Enumeration;

public interface ServletConfig {

    public String getServletName();

    public ServletContext getServletContext();

    public String getInitParameter(String name);

    public Enumeration<String> getInitParameterNames();
}

==========================================================================

能夠看到,正常下咱們使用的的 Servlet extend httpServlet,

而後實質上的httpServlet extends GenericServlet ,

GenericServlet實現implements 

1.接口Servlet, 2.接口ServletConfig,以及 3.java.io.Serializable.

具體的接口定義和抽象類的實現,能夠看看源代碼,不過話說回來,我如今的目的也就是搞清楚,而非是本身寫,那樣精力消耗太大.畢竟源碼是輕易得到的,想看明白就好了.

=====================================================================================================

HttpServletRequest , HttpServletResponse 

下一個將粗略說下HttpServletRequest , HttpServletResponse .這兩個寫下就知道是什麼狀況了.

HttpServletRequest , HttpServletResponse,在Servlet裏是什麼意思,一目瞭然.

Web基於HTTP的開發中,這兩貨是每天用的東西.二者都是接口.

HttpServletRequest, HttpServletResponse對象簡介:

客戶端對於Servlet的每次訪問請求,Servlet容器(如Tomcat)都會建立一個封裝HTTP請求的對象和一個表明HTTP響應的對象,當調用Servlet的doGet或doPost方法時,這兩個對象會做爲參數被傳遞進去



HttpServletRequest對象表明客戶端的請求,當客戶端經過HTTP協議訪問服務器時,所發出的HTTP請求消息被封裝在此對象之中,經過這個對象提供的方法,便可得到客戶端發出的請求信息。

HttpServletRequest對象最基本的應用是獲取瀏覽器傳遞給Web服務器的請求參數信息


請求參數:
▪GET方式下,URL地址後的附加信息
▪POST方式下,HTTP請求消息中的實體內容部分



具體的示例嘛...:日,不想寫了,這些太簡單了,隨便去網上找的DEMO看啦.

讀取請求參數的方法
經過HttpServletRequest對象的如下方法讀取GET/POST方式下傳遞的參數
getParameter
getParameterValues

HttpServletResponse對象表明服務器端對客戶端的響應,用於封裝HTTP響應消息

輸出響應正文(實體內容)輸出響應正文的方法

▪getWriter
–返回一個(文本)字符輸出流對象
–專用於輸出內容爲文本字符的網頁文檔
▪getOutPutStream
–返回一個字節輸出流對象
–若是要輸出二進制格式的響應正文,應該使用該方法
public class Servlet1 extends HttpServlet {
   public void doGet(HttpServletRequest request, HttpServletResponse response){
		response.setContentType("text/html");
		PrintWriter out = response.getWriter();
		String userName = request.getParameter("userName");
           //經過PrintWriter類型對象out的println方法,輸出內容至瀏覽器
		out.println("username:"+userName+"<br/>");
		//顯式清理緩存和關閉
		out.flush();
		out.close();	
}
如上示例.

HttpServletResponse其它經常使用方法

}字符集編碼問題
}重定向
具體百度下吧,不想寫了,我遁了.......
相關文章
相關標籤/搜索