Java之Servlet

 

Servlet規範了JavaWeb項目的結構
Servlet的規範約束了服務器如何來實現Servlet規範,如何解析JavaWeb項目的結構。

Java就是經過接口來約束

Servlet規範的jar就在tomcat的lib目錄下面,文件名:servlet-api.jar,其中還有webSocket-api.jar
建立servlet先只用servlet-api.jar便可。html

 

1、開始使用Servlet規範開發JavaWeb項目:java

而後開始配置:ios

注意:<url-pattern>裏面的資源名稱必需要用"/"開頭web

源碼:api

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
 3   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4   xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
 5                       http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
 6   version="3.1"
 7   metadata-complete="true">
 8   
 9   <servlet>
10       <!-- 配置Servlet類的全限定名 -->
11       <servlet-name>HelloServlet</servlet-name>
12       <servlet-class>com.demo.testServlet.HelloServlet</servlet-class>
13   </servlet>
14   
15   <!-- Servlet映射,用來訪問資源名稱,經過helloHeYang就能夠訪問資源 -->
16   <servlet-mapping>
17       <servlet-name>HelloServlet</servlet-name>
18       <url-pattern>/helloHeYang</url-pattern>
19   </servlet-mapping>
20 
21    
22 </web-app>

另外:瀏覽器

Servlet中的方法含義:緩存

public void init(ServletConfig config):Servlet的初始化操做方法tomcat

public void service(ServletRequest req, ServletResponse res):處理請求和響應的方法安全

public void destroy():資源回收服務器

public ServletConfig getServletConfig():獲取Servlet的配置信息

public String getServletInfo():獲取Servlet的相關的信息(做者/版本)

 1     @Override
 2     public void init(ServletConfig config) throws ServletException {
 3         // TODO Auto-generated method stub
 4         System.out.println("init初始化方法");
 5     }
 6 
 7     @Override
 8     public ServletConfig getServletConfig() {
 9         // TODO Auto-generated method stub
10         System.out.println("getServletConfig獲取Servlet配置信息");
11         return null;
12     }
13 
14     @Override
15     public void service(ServletRequest req, ServletResponse res)
16             throws ServletException, IOException {
17         // TODO Auto-generated method stub
18         System.out.println("service(ServletRequest req, ServletResponse res)處理請求和響應");
19     }
20 
21     @Override
22     public String getServletInfo() {
23         // TODO Auto-generated method stub
24         System.out.println("getServletInfo():獲取Servlet的相關的信息(做者/版本)");
25         return null;
26     }
27 
28     @Override
29     public void destroy() {
30         // TODO Auto-generated method stub
31         System.out.println("destroy():資源回收");
32     }

啓動tomcat服務器以後,而後打開瀏覽器:

---------------------------------------------------------------------------------------------------------------

Servlet的生命週期方法:

public void init(ServletConfig config):Servlet的初始化操做方法(在被第一次訪問的時候執行)

public void service(ServletRequest req, ServletResponse res):處理請求和響應的方法(每次訪問都會執行)

public void destroy():資源回收(在服務器正常關閉的時候執行)

----------------------------------------------------------------------------------------------

Servlet的生命週期方法的執行順序:

Servlet是單例的(在其整個應用中只有一個對象)

執行順序:

1.調用公共無參數的構造器建立對象(只會在第一次訪問的時候執行)

2.執行init方法(只會在第一次訪問的時候執行)

3.執行服務方法(每次訪問都會執行)

4.執行destroy方法(在服務器被正常關閉的時候執行),不要將關閉資源的操做放到該方法中

注意:在Servlet類中必須保證有一個公共的無參數的構造器(使用反射建立對象,類的Class實例.newInstance())

   類中的默認構造器的訪問權限和類的訪問權限一致

 

2、Servlet的請求流程:

1.經過瀏覽器發送請求

http://localhost:8080/demo/helloHeYang

2.Tomcat解析請求路徑

協議:http

主機地址:localhost

端口:8080,肯定訪問的是該主機上的哪個程序

上下文的路徑:server.xml文件中配置的信息,/demo

資源名稱:訪問的資源是什麼,/helloHeYang,在項目下的web.xml文件中配置的<url-pattern>的文本

3.根據上下文的路徑去找到server.xml文件中的<Context>節點,肯定項目的根路徑

    若是沒有找到,返回404錯誤

    反之,執行第4步

4.根據資源名稱去項目下的WEB-INF下的web.xml文件中找到<url-pattern>文本內容爲/hello的節點

能夠肯定找到Servlet對應的<servlet-name>

   

5.根據<Servlet-name>找到Servlet 的全限定名

6.使用反射建立對象

Tomcat中的緩存池:

Map<String, Servlet> cache=new HashMap<>();

Servlet obj = cache.get("類的全限定名");

if(obj==null){

     //若是是第一次訪問:

     Object obj2 = Class.forName("類的全限定名").newInstance();

    //將建立好的對象放到緩存池中

    cache.put("類的全限定名",obj2);

} else {

    //不是第一次訪問:

    //GOTO 7;

}

7.調用init方法進行初始化操做

    建立ServletConfig對象,調用init(config)

8.執行service(ServletRequest req, ServletResponse resp),

    執行以前先建立ServletRequest , ServletResponse 兩個對象

9.給瀏覽器一個響應信息

 

3、Servlet初始化參數

在Servlet類中定義初始化參數,會將代碼寫死,應該將配置信息放到web.xml文件中

問題:如何將配置好的初始化參數獲取到?

解決方案:使用ServletConfig來獲取

------------------------------------------------------------------------------------

ServletConfig中的經常使用方法:

public String getServletName():獲取Servlet的名稱,配置中的<servlet-name>文本

public ServletContext getServletContext():獲取Servlet的上下文信息

-------------------------------------

獲取初始化參數的相關方法:

public String getInitParameter(String name):根據指定的名稱獲取當前的Servlet中的初始化參數

public Enumeration<String> getInitParameterNames():獲取當前Servlet中的全部的初始化參數的名稱

Enumeration:迭代器(Iterator)

關鍵代碼:

 1     @Override
 2     public void init(ServletConfig config) throws ServletException {
 3         // TODO Auto-generated method stub
 4         System.out.println("init初始化方法");
 5         
 6         // 初始化方法的參數
 7         System.out.println(config.getServletName());
 8         System.out.println(config.getInitParameter("encoding"));
 9         System.out.println("----------------------------------");
10         Enumeration<String> inits = config.getInitParameterNames();
11         while (inits.hasMoreElements()) {
12             String name = inits.nextElement();
13             System.out.println("name");
14             System.out.println(name+"--->"+config.getInitParameter(name));
15         }
16         
17     }

 ------------------------------------------------------------

目前的初始化參數只是爲當前的Servlet作的配置,若是在多個Servlet中有相同的配置,那麼該配置就重複了---解決方案(使用全局的初始化參數)。

 

4、Servlet繼承體系

其實咱們實際開發中須要繼承HttpServlet這個關鍵的類,下面咱們就來本身實現這個類,而後體會它裏面的繼承體系,瞭解它內部的關聯性。

首先是自定義一個 HelloServlet,而且實現Servlet,ServletConfig兩個接口以及接口的全部的方法。

 1 import java.io.IOException;
 2 import java.util.Enumeration;
 3 
 4 import javax.servlet.Servlet;
 5 import javax.servlet.ServletConfig;
 6 import javax.servlet.ServletContext;
 7 import javax.servlet.ServletException;
 8 import javax.servlet.ServletRequest;
 9 import javax.servlet.ServletResponse;
10 
11 public class HelloServlet implements Servlet,ServletConfig{
12 
13     // 聲明私有的全局變量
14     private ServletConfig config;
15     
16     public void init(){
17         // 事實上,若是子類沒有用super方法,就不會被調用
18         System.out.println("調用了父類的init方法");
19     }
20     
21     @Override
22     public void init(ServletConfig config) throws ServletException {
23         // TODO Auto-generated method stub
24         System.out.println("HelloServlet:init初始化方法");
25         this.config = config;
26         init();
27     }
28     @Override
29     public ServletConfig getServletConfig() {
30         // TODO Auto-generated method stub
31         System.out.println("HelloServlet:getServletConfig獲取Servlet配置信息");
32         return config;// 在這裏直接返回ServletConfig對象
33     }
34     @Override
35     public void service(ServletRequest req, ServletResponse res)
36             throws ServletException, IOException {
37         // TODO Auto-generated method stub
38         System.out.println("HelloServlet:service(ServletRequest req, ServletResponse res)處理請求和響應");
39         
40     }
41     @Override
42     public String getServletInfo() {
43         // TODO Auto-generated method stub
44         System.out.println("getServletInfo():獲取Servlet的相關的信息(做者/版本)");
45         return null;
46     }
47     @Override
48     public void destroy() {
49         // TODO Auto-generated method stub
50         System.out.println("HelloServlet:destroy():資源回收");
51     }
52 
53     
54     // 爲何要實現ServletConfig的接口,爲了使用接口裏面的方法,方便子類調用
55     
56     @Override
57     public String getServletName() {
58         // TODO Auto-generated method stub
59         return config.getServletName();
60     }
61 
62     @Override
63     public ServletContext getServletContext() {
64         // TODO Auto-generated method stub
65         return config.getServletContext();
66     }
67 
68     @Override
69     public String getInitParameter(String name) {
70         // TODO Auto-generated method stub
71         return config.getInitParameter(name);
72     }
73 
74     @Override
75     public Enumeration<String> getInitParameterNames() {
76         // TODO Auto-generated method stub
77         return config.getInitParameterNames();
78     }
79 
80 }

而後再建立一個MyHttpServlet繼承HelloServlet,來處理http請求和響應的類

 1 import java.io.IOException;
 2 
 3 import javax.servlet.ServletException;
 4 import javax.servlet.ServletRequest;
 5 import javax.servlet.ServletResponse;
 6 import javax.servlet.http.HttpServletRequest;
 7 import javax.servlet.http.HttpServletResponse;
 8 
 9 // 單獨一個子類處理service方法
10 
11 public class MyHttpServlet extends HelloServlet {
12     @Override
13     public void service(ServletRequest req, ServletResponse res)
14             throws ServletException, IOException {
15         // TODO Auto-generated method stub
16         
17         
18         // 若是要訪問http協議的方法,須要強轉類型
19         HttpServletRequest request = (HttpServletRequest) req;
20         HttpServletResponse response = (HttpServletResponse) res;
21         service(req, res);
22     }
23     
24     public void service(HttpServletRequest req,HttpServletResponse res){
25 //        super.service(req, res);
26     }
27 }

最後再建立一個子類HelloSubServlet,直接繼承自MyHttpServlet,注意不是繼承最前面的HelloServlet基類哦。

 1 import java.io.IOException;
 2 
 3 import javax.servlet.ServletException;
 4 import javax.servlet.ServletRequest;
 5 import javax.servlet.ServletResponse;
 6 import javax.servlet.http.HttpServletRequest;
 7 import javax.servlet.http.HttpServletResponse;
 8 
 9 public class HelloSubServlet extends MyHttpServlet {
10     
11     /*
12     @Override
13     public void init(ServletConfig config) throws ServletException {
14         // TODO Auto-generated method stub
15         super.init(config);
16     }
17     * 因爲config已經做爲父類中全局變量來處理了,因此以上方法實際上是多餘了
18     * 可是又須要調用父類的初始化servlet方法init(ServletConfig...)方法,
19     * 若是子類沒有實現,就會去找父類方法,若是子類實現了,而子類中沒有用super調用父類方法,父類方法就不會執行
20     * 因此就採用在父類中聲明一個init空的方法,而後在init(ServletConfig...)調用,而後子類只要重寫init()方法便可
21     * 
22     * 可是,前提是:若是子類重寫了init(ServletConfig...),就必定要記得要用super調用父類一樣的方法
23     */
24     
25     @Override
26     public void init() {
27         // 全部初始化的方法寫在這裏
28         System.out.println("HelloSubServlet初始化方法");
29     }
30     
31     @Override
32     public void service(HttpServletRequest req, HttpServletResponse res) {
33         super.service(req, res);
34         
35         // 由於子類實現了ServletConfig的接口方法,因此能夠直接調用便可。
36         String name = this.getInitParameter("name");
37         System.out.println(name);
38     };   40 }

而後仔細體會他們之間的關係。

下面是展現直接開發須要知道的繼承體系:

 

 

5、HttpServletRequest經常使用的方法

HttpServletRequest接口:處理基於HTTP協議的請求信息

經常使用的方法:

String getContextPath()  :獲取上下文的路徑

String getHeader(String name)  :根據名稱獲取請求頭信息

String getMethod()  :獲取請求的類型

String getRequestURI()  :獲取請求的資源路徑

StringBuffer getRequestURL():獲取請求的全路徑

String getParameter(String name)  :根據名稱獲取請求參數的值

String getRemoteAddr()  :獲取請求的客戶端的地址

---------------------------------------------------------------

ServletConfig中的getInitParameter(String name)

獲取web.xml文件中配置的初始化參數的值

HttpServletRequest中的getParameter(String name)

獲取用戶提交的參數值

 

6、簡單案例

通常狀況下,一個表單對應一個Servlet。

在webapp目錄下建立一個register.html

 1 <!DOCTYPE html>
 2 <html>
 3 <head>
 4 <meta charset="UTF-8">
 5 <title>Insert title here</title>
 6 </head>
 7 <body>
 8 <!-- action:表單提交到哪一個頁面
 9 method: 提交方式
10     get:提交以後,表單中的數據會顯示到地址欄中(不安全)
11     post:提交以後,表單中的數據不會顯示到地址中
12 enctype:application/x-www-form-urlencoded(默認)
13     上傳文件:multipart/form-data
14  -->
15 <form action="/demo/register" method="post" enctype="application/x-www-form-urlencoded">
16 姓名:<input type="text" name="name">
17 <br>
18 密碼:<input type="password" name="password">
19 <br>
20 <br>
21 性別:
22 <input type="radio" name="sex" value="男" checked>23 <input type="radio" name="sex" value="女">24 <br>
25 職業:
26 <input type="checkbox" name="java" value="java">Java
27 <input type="checkbox" name="c" value="c">C
28 <input type="checkbox" name="IOS" value="ios">IOS
29 
30 <br>
31 <br>
32 城市:
33 <select name="address">
34 <option value="1">成都</option>
35 <option value="2" selected="selected">上海</option>
36 <option value="3">廣州</option>
37 </select>
38 
39 <br>
40 <br>
41 評論:
42 <textarea name="textarea" rows="10" cols="40">在這裏輸入文本。。。</textarea>
43 
44 <br>
45 <br>
46 <input type="submit" value="提交">
47 <input type="reset" value="重置">
48 <br>
49 
50 </form>
51 
52 </body>
53 </html>

而後建立一個RegisterServlet.class

 1 package com.demo.request;
 2 
 3 import java.io.IOException;
 4 import java.util.Map;
 5 
 6 import javax.servlet.ServletException;
 7 import javax.servlet.http.HttpServlet;
 8 import javax.servlet.http.HttpServletRequest;
 9 import javax.servlet.http.HttpServletResponse;
10 
11 public class RegisterServlet extends HttpServlet {
12 
13     /**
14      * 
15      */
16     private static final long serialVersionUID = 1L;
17 
18     
19     @Override
20     protected void service(HttpServletRequest req, HttpServletResponse resp)
21             throws ServletException, IOException {
22         // TODO Auto-generated method stub
23         
24         System.out.println("開始執行這段代碼。");
25         
26         // 一、獲取請求參數
27         String name = req.getParameter("name");
28         String password = req.getParameter("password");
29         
30         System.out.println("name"+name+" password"+password);
31         
32         Map<String,String[]> map = req.getParameterMap();
33         String name2 = map.get("name")[0];
34         System.out.println("name2"+name2);
35         // 二、調用方法來處理業務邏輯
36         
37         // 三、控制頁面跳轉
38     }
39     
40 }

還要在web.xml中寫好配置代碼:

 1 <!-- 配置的是子類Servlet -->
 2   <servlet>
 3       <!-- 配置Servlet類的全限定名 -->
 4       <servlet-name>RegisterServlet</servlet-name>
 5       <servlet-class>com.demo.request.RegisterServlet</servlet-class>
 6       <init-param>
 7           <param-name>encoding</param-name>
 8           <param-value>UTF-8</param-value>
 9           <param-name>name</param-name>
10           <param-value>hahaha</param-value>
11       </init-param>
12   </servlet>
13   
14   <!-- Servlet映射,用來訪問資源名稱,經過helloHeYang就能夠訪問資源 -->
15   <servlet-mapping>
16       <servlet-name>RegisterServlet</servlet-name>
17       <url-pattern>/register</url-pattern>
18   </servlet-mapping>

 

Toncat中默認處理請求參數的編碼方式默認是ISO-8859-1,只有一個字節,因此中文會亂碼。

--解決方案:

  方式一:

  方式二:

    Post:

      // 將處理請求參數的編碼改成UTF-8

      req.setCharacterEncoding("UTF-8");

    Get:

      在service.xml文件中須要設置的配置(可能默認是URIEncoding="ISO-8859-1"):

1 <Connector port="8080" protocol="HTTP/1.1"
2                connectionTimeout="20000"
3                redirectPort="8443"  URIEncoding="UTF-8"/>

另外規定:提交表單只能用POST請求。

 

HttpServletResponse接口:處理基於HTTP協議的響應信息

經常使用的方法:

PrintWriter getWriter()  :向頁面輸出字符流

ServletOutputStream getOutputStream()  :向頁面輸出字節流,實現文件下載

以上兩個方法不能被同時調用

 void setCharacterEncoding(String charset)  :設置響應信息的字符編碼

向頁面輸出一個html內容,必需要下面兩個設置

resp.setCharacterEncoding("UTF-8");

resp.setContentType("text/html");:MIME的類型

上面兩個設置能夠合在一行代碼中

resp.setContentType("text/html; charset=UTF-8");

         // 處理響應
        resp.setContentType("text/html;charset=UTF-8");
        PrintWriter out = resp.getWriter();
        
        out.print("<thml>");
        out.print("<head>");
        out.print("<title>");
        out.print("你好");
        out.print("</title>");
        out.print("</head>");
        out.print("<body>");
        out.print("<font color='red'>你好</font>,世界");
        out.print("</body>");
        out.print("</html>");    
相關文章
相關標籤/搜索