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>");