Servlet詳細教程

Servlet簡介

servlet是Server Applet的簡稱,翻譯過來就是服務程序.好吧,這麼說你可能仍是不太懂,簡單的講,這個servlet是運行在服務器上的一個小程序,用來處理服務器請求的.進一步講,咱們知道,通常的網頁程序,是由咱們經過瀏覽器訪問來實現的,在這個過程當中,咱們的瀏覽器發送訪問請求,服務器接收請求,並對瀏覽器的請求做出相應的處理.這就是咱們熟悉的B/S模型(瀏覽器-服務器模型).而servlet就是對請求做出處理的組件,運行於支持Java的應用服務器中.php

Servlet的做用

在servlet剛剛出現的那個年代,servlet的做用十分複雜,既承擔着處理數據的做用,又承擔着展現頁面的做用,美工人員想要參與開發,基本上是不太現實的,畢竟美工不可能再去花時間將頁面作好.
隨着時間的推移,出現了MVC思想,也就是模型-界面-控制器思想,極大的簡便了開發,也明確了servlet的做用.
這裏寫圖片描述
根據上面這張圖,咱們就能知道,servlet在其中承擔的做用是controller,控制器,起到對數據進行操做的做用.
順便補充說明一下,最經典的MVC模型就是JSP+JavaBean+Servlet開發的模式.html

Servlet處理的信息是什麼?

我一直再講,servlet是對數據進行處理的一個控制器,那麼,你必定很好奇,servlet究竟處理的是什麼數據?
這裏你要知道,我以前在其餘文章也講過,咱們的web應用徹底是基於http協議的.http協議有請求報文(request)和響應報文(request),請求報文就是瀏覽器向服務器發送的數據造成的數據對象,同理,相應報文就是服務器向瀏覽器發送的數據造成的信息,而http協議有兩個重要的方法,一個是POST,一個是GET,這兩個方法就是向瀏覽器發送請求的方法.
你應該知道這兩個方法在什麼地方使用,沒錯,就是在前端的表單中使用,好比你登陸CSDN的時候,提交的用戶名和密碼,就是被http協議封裝成請求報文的形式發送到服務器的,這樣,servlet就可以讀取請求報文的內容,並對報文進行處理了.前端

Servlet的開發流程

狹義上講,servlet是servlet是java語言實現的一個類,因此咱們就要根據這個類進行相應的擴展開發.
開發流程以下:java

  • 編寫一個java類,繼承HttpServlet類
  • 重寫HttpServlet類的doGet方法和doPost方法
  • 配置web.xml文件,或者使用註解對servlet進行配置

開發流程就是這個樣子,咱們先來看一下最後一個步驟.web

對servlet進行配置

你必定在想,若是我寫了好幾個servlet,可是前端發送請求的時候,究竟會把請求發送給哪一個servlet呢?我在輸入某個地址的時候,到底是由哪一個servlet進行響應的呢?
這時候servlet的配置就顯得尤其重要.對servlet的配置指定了對前端請求處理到底是經過哪一個servlet.
配置servlet一共有兩種方式,一種是使用web.xml文件配置,另一種就是使用註解配置,下面咱們來詳解介紹這兩種配置方式小程序

  • 使用web.xml文件配置
    注意,servlet的配置內容要寫在webapp內部
<webapp>
<!-- 配置一個servlet -->
  <!-- servlet的配置 -->
  <servlet>
    <!-- servlet的內部名稱,自定義。儘可能有意義 -->
    <servlet-name>MyServlet</servlet-name>
    <!-- servlet的類全名: 包名+簡單類名 -->
    <servlet-class>cn.roobtyan.servlet.FirstServlet</servlet-class>
  </servlet>


  <!-- servlet的映射配置 -->
  <servlet-mapping>
    <!-- servlet的內部名稱,必定要和上面的內部名稱保持一致!! -->
    <servlet-name>MyServlet</servlet-name>
    <!-- servlet的映射路徑(訪問servlet的名稱) -->
    <url-pattern>/first</url-pattern>
  </servlet-mapping>
</webapp>

當你訪問/first的時候,服務器天然就會把請求交給MyServlet進行處理了.瀏覽器

  • 使用@註解配置

新版本的servlet支持使用註解進行配置,這樣極大的簡便了開發.
註解配置以下:安全

@WebServlet(name = "LoginServlet",urlPatterns = {"/login"})
public class LoginServlet extends HttpServlet {

而後,你在訪問/login的時候,服務器一樣就會將處理交由LoginServlet進行處理了.
這樣是否是很是爽?(^-^)
實際上,註解的做用和web.xml的做用是相同的,通常都是推薦使用註解的方式進行開發,這樣十分簡便,可讀性也變的更增強大.
你必定會好奇,以下:ruby

<url-pattern>/first<url-pattern>

服務器

@WebServlet(name = "LoginServlet",urlPatterns = {"/login"})

這裏面的url可不能夠不這麼精確的配置,用一種模糊匹配的方式,就是我訪問某種規則的路徑的時候,統一調用一個servlet,這固然是能夠的了.
這就涉及到映射路徑的問題了

Servlet映射路徑的配置問題

  • 精確匹配
    精確匹配就是咱們上面用的那種方式,使用固定的url來訪問這個servlet,這種沒什麼須要說明的
  • 模糊匹配
    模糊匹配就是比較有意思的了,經過模糊匹配,咱們可讓好多路徑映射到同一個servlet,模糊匹配通常有以下格式
/*              任意路徑都映射到這個servlet
/roobtyan/*     /roobtyan下的任意路徑映射到該servlet
*.(*.do  *.action *.html)   是這樣的:/任意路徑.do/action/html

這裏面有兩點是須要注意的,一是url要麼以/開頭,要麼以*開頭,其餘的都是非法的

Servlet的生命週期

通常來說,servlet只會初始化一次,也就是整個過程當中只存在一個servlet對象,即使是有屢次訪問,依然只有一個對象,這個對象是能夠複用的.我想你必定會好奇這個servlet到底是在何時建立的,因此就來說一下servlet的生命週期,所謂的生命週期咱們在java基礎知識中必定也瞭解過,就是servlet類究竟在何時建立,調用了何種方法,最後在何時被銷燬.咱們以前學過的對象都是本身手動建立,最後由JVM來銷燬的,而servlet的整個生命週期,都是由tomacat,也就是服務器控制的
咱們以一張圖來了解一下:
這裏寫圖片描述
能夠看到,servlet共有三個關鍵的方法,分別是init(),service(),destroy().

  • init方法只會調用一次,只是在建立servlet實例的時候纔會建立
  • service方法,是進行數據處理的,只要接受了一次請求,就會被調用一次
  • destroy方法,銷燬servlet對象的時候調用。中止服務器或者從新部署web應用時銷燬servlet對象,一樣也是調用一次

一個簡單的例子

好了,講了這麼多,你必定是躍躍欲試了,咱們就用一個登陸控制的例子來簡單的看一下servlet開發的步驟.

  • 使用ide新建一個web項目
  • 建立一個前端登陸表單login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>roobtyan登陸控制系統</title>
</head>
<body>
    <h1 align="center" style="color: red;">歡迎您登陸系統後臺</h1><hr/>
    <%--the form start--%>
    <div align="center">
        <form method="post" action="/login">
            Username:<input type="text" name="username"/><br/><br/>
            Password:<input type="password" name="password"/><br/><br/>
            <input type="submit" value="登陸"/>
        </form>
    </div>
</body>
</html>
  • 建立一個登陸成功頁面
    一樣使用jsp頁面
    welcome.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>歡迎頁面</title>
</head>
<body>
    <h1 align="center" style="color: red">Welcome:</h1>
    <% out.println(session.getAttribute("user")); %>
    <hr/>
    <span style="align:center; color:yellow">
        Time:<% out.println(new Date()); %>
    </span>
</body>
</html>
  • 建立LoginServlet.java
public class LoginServlet extends HttpServlet {
    public void service(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
        //設置字符編碼
        request.setCharacterEncoding("utf8");
        //從request對象中獲取username,password
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        //判斷是否爲管理員
        if("administrator".equals(username)&&"123456".equals(password)){
            //登陸成功,設置session
            HttpSession session = request.getSession(true);
            session.setAttribute("user", "管理員,歡迎你!");
        }else {
            session.setAttribute("user","登陸信息錯誤,請檢查用戶名或密碼");
        }
        //將頁面轉發到歡迎頁面
        requestDispatcher = request.getRequestDispatcher("/welcome.jsp");
        requestDispatcher.forward(request,response);        
    }
}
  • 配置servlet
    這裏對於servlet的配置,咱們採起web.xml的方式,主要是由於這種方法相對麻煩,爲了讓你有着更好的理解,就這樣作了.
<servlet>
        <servlet-name>LoginServlet</servlet-name>
        <servlet-class>com.roobtyan.cn.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
        <servlet-name>LoginServlet</servlet-name>
        <url-pattern>/login</url-pattern>
</servlet-mapping>

這樣,咱們的第一個servlet程序就作完了.我想若是你存在疑問的話,應該是在jsp技術上,若是是這樣,那麼請參照個人博客:Jsp技術介紹
還有一個地方你可能存在疑惑,爲何使用request.getParameter方法能夠獲取到提交的表單中的內容呢?這個很好解釋,由於前端使用post或者get方法將表單信息提交到servlet的時候,將表單信息封裝成了request對象,這樣就能夠獲取到了.值得注意的是,表單中的name字段,就是咱們獲取值的根據.
最後一個可能存在疑問位置就是這裏

//將頁面轉發到歡迎頁面
RequestDispatcher requestDispatcher = request.getRequestDispatcher("/welcome.jsp");
requestDispatcher.forward(request,response);

這段代碼我在最後會解釋,其實也挺簡單的
上面的你都注意到了,那你很是厲害了.不過,有一個地方你可能注意不到,那就是這段代碼:

request.setCharacterEncoding("utf8");

設置字符編碼的這部分,若是不設置,會形成亂碼,這仍是須要注意的.關於POST和GET亂碼的解決,請看個人文章:POST和GET亂碼的解決

Servlet自動加載

前面咱們說了,servlet只有在第一次被訪問的時候纔會加載,這確定會形成第一個訪問的人訪問時間較長,由於他須要等待servlet完成加載.那麼,有沒有什麼方法可以使得servlet自動加載呢,就是在啓動服務器的時候就將servlet加載起來呢?
答案是有的,一樣能夠在web.xml中進行配置

<servlet>
    <servlet-name>LoginServlet</servlet-name>
    <servlet-class>cn.roobtyan.LoginServlet</servlet-class>
    <!-- 讓servlet對象自動加載 -->
    <load-on-startup>1</load-on-startup>  
  </servlet>

就是使用的<login-on-startup></login-on-startup>配置的,注意: 其中的整數值越大,建立優先級越低!

Servlet多線程問題

前面咱們講了,一個servlet在服務器中只會存在一個實例,不管是有多少訪問,都掉用的同一個實例,也就是單實例多線程的.這就存在着必定的線程安全問題,好比說,我在servlet中定義了一個局部變量,那麼這個變量的值頗有可能不是我期待的值,因此,在servlet中要儘可能避免使用局部變量.

Servlet中重要的對象

在servlet中共有四個重要的對象:

HttpServletRequest  請求對象:獲取請求信息
HttpServletResponse 響應對象: 設置響應對象
ServletConfig對象    servlet配置對象
ServletContext對象  servlet的上下文對象

前兩個咱們介紹的很多,這兩個的具體內容我回單獨拿出來一章介紹,和HTTP協議一塊介紹,我以爲這樣看起來更能接受一些.
那麼咱們如今就介紹後面兩個

ServletConfig對象

  • 建立時間:在建立完servlet對象的時候,接着建立servletConfig對象.
  • 如何獲得對象:直接使用ServletConfig config = this.getServletConfig();
  • 簡單使用
    這是web.xml的配置文件
<servlet>
    <servlet-name>LoginServlet</servlet-name>
    <servlet-class>cn.roobtyan.LoginServlet</servlet-class>
    <!-- 初始參數: 這些參數會在加載web應用的時候,封裝到ServletConfig對象中 -->
    <init-param>
        <param-name>location</param-name>
        <param-value>doom</param-value>
    </init-param>
  </servlet>

配置文件中的init-param就是配置信息
這個ServletConfig對象共有以下的方法

java.lang.String getInitParameter(java.lang.String name)  根據參數名獲取參數值
java.util.Enumeration getInitParameterNames()            獲取全部參數
ServletContext getServletContext()                       獲得servlet上下文對象
java.lang.String getServletName()                        獲得servlet的名稱

這個對象比較簡單,就不過多介紹,注意,這個對象只能在本身的servlet中使用,超出了範圍就不行了.

ServletContext對象

  • 建立時間:加載web應用時建立ServletContext對象
  • 獲得對象:從ServletConfig對象的getServletContext方法獲得
    這個對象又幾個比較重要的方法,咱們來介紹一下.
  • 做用:在一個web項目中共享數據,管理web項目資源,爲整個web配置公共信息等
java.lang.String getContextPath()   --獲得當前web應用的路徑

java.lang.String getInitParameter(java.lang.String name)  --獲得web應用的初始化參數
java.util.Enumeration getInitParameterNames()  

void setAttribute(java.lang.String name, java.lang.Object object) --域對象有關的方法
java.lang.Object getAttribute(java.lang.String name)  
void removeAttribute(java.lang.String name)  

RequestDispatcher getRequestDispatcher(java.lang.String path)   --轉發(相似於重定向)

java.lang.String getRealPath(java.lang.String path)     --獲得web應用的資源文件
java.io.InputStream getResourceAsStream(java.lang.String path)

具體的方法使用就是這樣,按照API去用就能夠了,我就再也不過多介紹

轉發

轉發

剛纔咱們用到的

RequestDispatcher requestDispatcher = request.getRequestDispatcher("/welcome.jsp");
requestDispatcher.forward(request,response);

這個就是轉發,按照這樣用就能夠了

重定向

與轉發功能類似的是重定向,重定向的使用是這樣的:

response.sendRedirect("/welcome.jsp");

這樣也會訪問到welcome.jsp這個頁面.
這就是以前的Respose對象,我們先這樣用着,後面我回單獨寫一章博客來說解的.

轉發和重定向的區別

雖然兩者最終實現的功能是相同的.可是仍是有很大不一樣的.不一樣之處以下

  • 地址欄變化
    轉發不會改變地址欄中的URL,而重定向則會改變
  • 跳轉範圍
    轉發只能訪問到當前web應用中的內容,而重定向則能夠訪問到任意web應用中的內容
  • request對象做用範圍
    轉發後,在轉發後的頁面中仍然可使用原來的request對象,而重定向,原來的request對象則失去做用.

因此,若是想要在多個頁面使用相同的request對象,那麼只能使用轉發,而不能使用重定向.
好了,以上就是所有要介紹的內容.servlet的生命週期是十分重要的,其餘的只能靠動手實踐才能很好的掌握,本身動動手敲出一個個好玩的例子吧!

結語

感謝您的閱讀,歡迎指正博客中存在的問題,也能夠跟我聯繫,一塊兒進步,一塊兒交流!

微信公衆號:進擊的程序狗
郵箱:roobtyan@outlook.com
我的博客:http://roobtyan.cn
掃描下面的二維碼關注我吧,你將收穫到意想不到的東西喲……
給你們準備了一份很是棒的JAVA的視頻教程,從JAVA基礎一直到JAVAWEB,還有很是強大的項目實戰。
就在個人微信公衆號裏,回覆java就可查看,免費的呦!
這裏寫圖片描述

相關文章
相關標籤/搜索