Servlet入門實踐

本文主要介紹servlet,包括入門到升入,基本上能夠對servlet有一個很好的認識;java

1servlet介紹:

  Servlet(Server Applet),全稱Java Servlet,未有中文譯文。是用Java編寫的服務器端程序。其主要功能在於交互式地瀏覽和修改數據,生成動態Web內容。狹義的Servlet是指Java語言實現的一個接口,廣義的Servlet是指任何實現了這個Servlet接口的類,通常狀況下,人們將Servlet理解爲後者。
手把手教你創建一個繼承servlet的類:mysql

  1. 在webcontent點擊右鍵選擇other,選擇servlet,這裏就建成了servlet的類
  2. 重寫doGet和doPost方法
public class TestServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setCharacterEncoding("utf-8");
        PrintWriter out = response.getWriter();
        out.println("hello peace");
    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
  1. 修改web.xml或者加上webServlet註解:
    修改web.xml:在根標籤下加入一下代碼
<!-- 配置一個servlet -->
  <!-- servlet的配置 -->
  <servlet>
  <!-- servlet的內部名稱,自定義。儘可能有意義 -->
       <servlet-name>TestServlet</servlet-name>
        <!-- servlet的類全名: 包名+簡單類名 -->
       <servlet-class>com.rlovep.servlet.TestServlet</servlet-class>
       <!-- servlet的映射配置 -->
  </servlet>
  <servlet-mapping>
  <!-- servlet的內部名稱,必定要和上面的內部名稱保持一致!! -->
      <servlet-name>TestServlet</servlet-name>
      <!-- servlet的映射路徑(訪問servlet的名稱) -->
      <url-pattern>/TestServlet</url-pattern>
  </servlet-mapping>

或者在類定義上加上webServlet的註解(注意二者只能有一個)
注意:1.不要在web.xml根標籤中指定metadata-complete="true".2。不要在web.xml中配置servlet
修改後的servlet類:git

@WebServlet("/TestServlet")//設置servlet的訪問路徑爲/TestServlet;或者這樣寫@WebServlet(name="TestServlet",urlPatterns={"/TestServlet"})
public class TestServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setCharacterEncoding("utf-8");
        PrintWriter out = response.getWriter();
        out.println("hello peace");
    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
  1. 訪問http://localhost:8080/HttpSer/TestServlet便可看到結果。

2servlet的路徑映射:

<url-pattern>/TestServlet</url-pattern>或者:@WebServlet(urlPatterns={"/TestServlet"})
匹配方式 url-pattern 地址欄
精確匹配 /TestServlet
/TestServlet/test
http://localhost:8080/HttpSer/TestServlet
http://localhost:8080/HttpSer/TestServlet/test
模糊匹配 /*
/TestServlet/*
/*.do
http://localhost:8080/HttpSer/任意路徑
http://localhost:8080/HttpSer/TestServlet/任意路徑
http://localhost:8080/HttpSer/任意路徑.do

注意
1)url-pattern要麼以 / 開頭,要麼以開頭。 例如, TestServlet是非法路徑。
2)不能同時使用兩種模糊匹配,例如 /TestServlet/
.do是非法路徑
3)當有輸入的URL有多個servlet同時被匹配的狀況下:
  3.1 精確匹配優先。(長的最像優先被匹配)
  3.2 之後綴名結尾的模糊url-pattern優先級最低!!!github

3servlet生命週期:

  1. 生命週期的引入:
    Servlet的生命週期: servlet類對象何時建立,何時調用什麼方法,何時銷燬。
    之前的對象: new Student(); stu.study(); stu=null;
    Servlet程序的生命週期由tomcat服務器控制的!!!!
  2. Servlet重要的四個生命週期方法:
    構造方法: 建立servlet對象的時候調用。默認狀況下,第一次訪問servlet的時候建立servlet對象 只調用1次。證實servlet對象在tomcat是單實例的。
    init方法: 建立完servlet對象的時候調用。只調用1次。
    service方法: 每次發出請求時調用。調用n次。
    destroy方法: 銷燬servlet對象的時候調用。中止服務器或者從新部署web應用時銷燬servlet對象。只調用1次。
  3. 代碼演示:
@WebServlet(name="TestServlet",urlPatterns={"/TestServlet"})
public class TestServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
     int i=0;
    /**
     * 1.構造方法,只被調用一次
     */
    public TestServlet() {
        super();
        System.out.println("構造方法>>>>");
    }
    /**
     * 2.init初始化方法,在構造方法後只被調用一次
     * 有參數的init方法會調用init方法;;通常覆蓋無參數的init方法;
     */
     @Override
    public void init() throws ServletException {
        // TODO Auto-generated method stub
        super.init();
        System.out.println("inti>>>>");
    }
  /**
     * 3.service方法,發生請求和響應時調用的方法,次數不限
     * 通常是重寫doget和dopost,此去只是方便演示
     */
    @Override
    protected void service(HttpServletRequest arg0, HttpServletResponse arg1) throws ServletException, IOException {
        System.out.println("service>>>" +i++);
    }
  /**
   * 4.destory方法,只有在中止服務器和從新部署web應用時調用
   */
    @Override
    public void destroy() {
        System.out.println("destory");
        super.destroy();
    }
}
#輸出結果:http://localhost:8080/HttpSer/TestServlet。連續訪問四次,獲得下面的結果:
構造方法>>>>
inti>>>>
service>>>0
service>>>1
service>>>2
service>>>3
Oct 11, 2015 8:53:52 PM org.apache.catalina.core.StandardContext reload
INFO: Reloading Context with name [/HttpSer] has started
destory
  1. 僞代碼演示:
Tomtcat內部代碼運行:
1)經過映射找到到servlet-class的內容,字符串: com.rlovep.serlvet.TestServlet
2)經過反射構造TestServlett對象
     2.1 獲得字節碼對象
         Class clazz = class.forName(" com.rlovep.serlvet.TestServlet");
    2.2 調用無參數的構造方法來構造對象
          Object obj = clazz.newInstance();     ---1.servlet的構造方法被調用
3)建立ServletConfig對象,經過反射調用init方法
    3.1 獲得方法對象
         Method m = clazz.getDeclareMethod("init",ServletConfig.class);
     3.2 調用方法
        m.invoke(obj,config);           --2.servlet的init方法被調用
4)建立request,response對象,經過反射調用service方法
     4.1 獲得方法對象
        Methodm m =clazz.getDeclareMethod("service",HttpServletRequest.class,HttpServletResponse.class);
    4.2 調用方法
    m.invoke(obj,request,response); --3.servlet的service方法被調用
5)當tomcat服務器中止或web應用從新部署,經過反射調用destroy方法
     5.1 獲得方法對象
        Method m = clazz.getDeclareMethod("destroy",null);
    5.2 調用方法
         m.invoke(obj,null);          --4.servlet的destroy方法被調用
  1. 圖像演示以下:
    1

4自動加載servlet:

默認狀況下,第一次訪問servlet的時候建立servlet對象。若是servlet的構造方法或init方法中執行了比較多的邏輯代碼,那麼致使用戶第一次訪問sevrlet的時候比較慢。
改變servlet建立對象的時機: 提早到加載web應用的時候!!!
在servlet的配置信息中,加上一個 或者加上註解(loadOnStartup=1)便可: web

<servlet>
  <!-- servlet的內部名稱,自定義。儘可能有意義 -->
       <servlet-name>TestServlet</servlet-name>
        <!-- servlet的類全名: 包名+簡單類名 -->
       <servlet-class>com.rlovep.serlvet.TestServlet</servlet-class>
       <load-on-startup>1</load-on-startup>
  </servlet>
或者:
@WebServlet(name="TestServlet",loadOnStartup=1,urlPatterns={"/TestServlet"})

5多用戶問題:

注意: servlet對象在tomcat服務器是單實例多線程的。能夠有多個用戶;
由於servlet是多線程的,因此當多個線程同時訪問了servlet的共享數據,如成員變量,可能會引起線程安全問題。
解決辦法:
1)把使用到共享數據的代碼塊進行同步(使用synchronized關鍵字進行同步)
2)建議在servlet類中儘可能不要使用成員變量。若是確實要使用成員,必須同步。並且儘可能縮小同步代碼塊的範圍。(哪裏使用到了成員變量,就同步哪裏!!),以免由於同步而致使併發效率下降。sql

6Servlet經常使用對象:

servlet:有幾個比較有用的對象:apache

1.HttpServletRequest   請求對象   http協議中已講
2.HttpServletResponse  響應對象  http協議中已講
3.ServletConfig       servlet配置對象
4.ServletContext    Servlet的上下文對象。對整個web應用有效
5.HttpSession        會話對象,當一個用戶向服務器發送第一個請求時,服務器爲其創建一個session,併爲此session建立一個標識號;

ServletConfig對象介紹:

ServletConfig對象: 主要是用於加載servlet的初始化參數。在一個web應用能夠存在多個ServletConfig對象(一個Servlet對應一個ServletConfig對象)
能夠直接從getServletConfig方法;或者本身在有參的init中得到 .
在web.xml中建立參數:同樣有兩種方法:api

<servlet>
  <!-- servlet的內部名稱,自定義。儘可能有意義 -->
       <servlet-name>TestConfig</servlet-name>
        <!-- servlet的類全名: 包名+簡單類名 -->
       <servlet-class>com.rlovep.serlvet.TestConfig</servlet-class>
       <init-param>
            <param-name>name</param-name>
            <param-value>peace</param-value>
       </init-param>
  </servlet>
或者:
@WebServlet(urlPatterns={"/TestConfig"},
        initParams={@WebInitParam(name="driver",value="com.mysql*")
                    ,@WebInitParam(name="url",value="jdbc*"),
                    @WebInitParam(name="user",value="root"),
                    @WebInitParam(name="pass",value="123456")})

測試以下:瀏覽器

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ServletConfig servletConfig = getServletConfig();
        //獲得servlet的名字
        System.out.println(servletConfig.getServletName());
        //根據參數名獲取參數值
        String name=servletConfig.getInitParameter("user");
        System.out.println(name+">>>>>");
        //獲取全部參數名稱
        Enumeration<String> names = servletConfig.getInitParameterNames();
        while(names.hasMoreElements()){
            String s=names.nextElement();
            System.out.println(s+"="+servletConfig.getInitParameter(s));
        }
    }

ServletContext對象介紹:

1. 引入
ServletContext對象 ,叫作Servlet的上下文對象。表示一個當前的web應用環境。一個web應用中只有一 個ServletContext對象。
2. 對象引用的獲得
建立時機:加載web應用時建立ServletContext對象。
獲得對象: 從ServletConfig對象的getServletContext方法獲得或者直接調用ServletContext servletContext = getServletContext();
3. 核心apitomcat

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)

4. 演示以下

ServletContext servletContext = getServletContext();
        //獲得當前web應用路徑
        System.out.println("路徑:"+servletContext.getContextPath());
        //根據參數名得到參數值
        System.out.println("AAA="+servletContext.getInitParameter("AAA"));
        //獲取全部參數名稱
        Enumeration<String> names = servletContext.getInitParameterNames();
        while(names.hasMoreElements()){
            String s=names.nextElement();
            System.out.println(s+":"+servletContext.getInitParameter(s));
        }
        //設置域對象,整個web應用有效
        servletContext.setAttribute("name","peace");
        servletContext.setAttribute("age", "23");
        //得到域對象
        System.out.println("name"+servletContext.getAttribute("name"));
        System.out.println("age"+servletContext.getAttribute("age"));
        //刪除域對象
        servletContext.removeAttribute("age");
        System.out.println("age"+servletContext.getAttribute("age"));

7.轉發和重定向;

域對象介紹:

域對象:做用是用於保存數據,獲取數據。能夠在不一樣的動態資源(servlet)之間共享數據。
案例:

#經過重定向,使用實體內容傳遞數據,通常只能存儲字符
Servlet1 傳數據:name=eric 
        response.sendRedirect("/Servlet2?name=eric")            
Servlet2接收:
        String request.getParameter("name");
#經過域對象傳遞:能夠傳遞任何數據;
ServletContext就是一個域對象,上面有介紹怎麼用
    保存數據:void setAttribute(java.lang.String name, java.lang.Object object)
    獲取數據: java.lang.Object getAttribute(java.lang.String name)
    刪除數據: void removeAttribute(java.lang.String name)
ServletContext域對象:做用範圍在整個web應用中有效!!!
全部域對象:
HttpServletRequet 域對象  測試;
ServletContext域對象
HttpSession 域對象
PageContext域對象

重定向:

重定向是服務器告訴瀏覽器,從新請求另外一頁面,請求信息丟失更新
a)地址欄會改變,變成重定向到地址。
b)重定向能夠跳轉到當前web應用,或其餘web應用,甚至是外部域名網站。
c)不能在重定向的過程,把數據保存到request中。
測試以下:

1.創建一個TestRedect servlet:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        /**
         * 保存數據到request域對象
         */
        request.setAttribute("name", "rose");
            //重定向
                /**
                 * 注意:能夠跳轉到web應用內,或其餘web應用,甚至其餘外部域名。
                 */
        //request域數據會丟失
        response.sendRedirect("/HttpSer/GetData");
        //重定向到外部域名:
        //response.sendRedirect("www.baidu.com");
    }
2.創建一個GetData的servlet
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        PrintWriter out = response.getWriter();
        out.println("hello");
        System.out.println("得到域對象"+request.getAttribute("name"));
    }

現象以下:
1.地址欄從http://localhost:8080/HttpSer/TestRedect變爲http://localhost:8080/HttpSer/GetData;
2.request域對象數據丟失:得到域對象null

轉發:

轉發是服務器將請求信號封裝後轉發到另外一個servlet頁面,請求信息會保存
a)地址欄不會改變
b)轉發只能轉發到當前web應用內的資源
c)能夠在轉發過程當中,能夠把數據保存到request域對象中
測試以下:

1.創建一個TestRedect servlet:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    /**
         * 保存數據到request域對象
         */
        request.setAttribute("name", "rose");
        //轉發    
        /**
         * 注意:不能轉發當前web應用之外的資源。
         */
        /*RequestDispatcher rd = this.getServletContext().getRequestDispatcher("/GetDataServlet");
        rd.forward(request, response);*/
        this.getServletContext().
        getRequestDispatcher("/GetData").forward(request, response);
    }
2.創建一個GetData的servlet
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        PrintWriter out = response.getWriter();
        out.println("hello");
        System.out.println("得到域對象"+request.getAttribute("name"));
    }

現象以下:
1.地址欄沒有變化
2.request域對象數據沒有丟失:得到域對象rose
來自一條小鯊魚(rlovep.com)
代碼下載

相關文章
相關標籤/搜索