http協議以及Servlet
1.1 http協議
協議:是指雙方按照一定的規則進行某種行爲
http協議:(超文本傳輸協議)定義了瀏覽器域服務器之間的相互通信的規則
請求協議:瀏覽器端發送給服務器端
響應協議:服務器端發送給瀏覽器端
1.1.1 http之請求協議
請求格式如下,如果瀏覽器不按照這個格式服務器將無法識別
請求格式: 請求首行; 請求頭信息; 空行; 請求體; |
GET /javaWEB1/index.jsp HTTP/1.1 //請求方式爲GET請求,路徑是javaWEB1/index.jsp 協議版本1.1 Accept: text/html, application/xhtml+xml, */* //接受參數類型*/*表示所有 Accept-Language: zh-CN //接受語言是中文 User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0) //瀏覽器版本,操作系統類型 Accept-Encoding: gzip, deflate //接受編碼,壓縮以及解壓縮 Host: localhost:8888 //主機名稱 Connection: Keep-Alive //連接狀態 存活 Cookie: JSESSIONID=03A34AAB1E01103D443520A7F0B88DC5 //後面再講 //空格 |
1、GET/javaWEB1/index.jsp HTTP/1.1 //請求方式爲GET請求,路徑是javaWEB1/index.jsp 協議版本1.1
2、Host:localhost:8888 請求主機名爲localhost,端口號爲8888
3、User-Agent 發送一些關於瀏覽器的信息給服務器,例如瀏覽器版本,操作系統的版本等。
1.1.2 http之響應協議
響應協議格式如下:
響應首行; 響應頭信息; 空行; 響應體。 |
在剛纔的JavaWEB中服務器響給瀏覽器的內容如下
HTTP/1.1 200 OK //協議版本 狀態碼 狀態碼的解釋 Server: Apache-Coyote/1.1 //服務器名稱 Content-Type: text/html;charset=UTF-8 //文本類型以及編碼 Content-Length: 619 //文本大小 Date: Thu, 08 Jun 2017 02:58:18 GMT //時間 //空格
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">//響應體 <html> ............響應具體內容........ </html> |
1、HTTP/1.1 200OK:表示協議版本號爲1.1版本,狀態碼爲200,表示請求成功,OK是對狀態碼的解釋
2、Server:Apache-Coyote/1.1:服務器的名稱
3、Content-Type:text/html;charset=UTF-8:響應文本類型以及編碼格式
響應協議狀態碼所表示的含義: 200:表示請求成功 404:表示資源路徑沒有找到 405:請求的方式有問題(get、post等) 500:表示服務器的錯誤 302:表示重定向(服務器沒有資源,提供一個url地址給瀏覽器訪問)
|
1.2 Servlet組件
Servlet是我們JavaWeb三大組件之一,(Servlet和filter、listener),Servlet屬於動態資源,服務器將瀏覽器發出的請求交給servlet來處理。接收請求數據,處理請求信息,完成響應。
一句話總結:servlet處理瀏覽器的請求,並且處理請求然後完成對瀏覽器的響應
注意:
一個功能的Servlet只能被Tomcat創建一次,很多次訪問都是訪問同一個Servlet(線程不安全)
實現Servlet的三種方式:
1.實現Servlet接口
2.繼承GenericServlet類
3.繼承HttpServlet類(重點掌握,常用)
1.2.1 Servlet接口
1.2.1.1 Servlet的實現方法
我們在新建類時實現Servlet接口,將會在servlet中實現如下方法
@Override public void destroy() { }
@Override public ServletConfig getServletConfig() { return null; }
@Override public String getServletInfo() { return null; }
@Override public void init(ServletConfig arg0) throws ServletException { }
@Override public void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException { } |
注意:
在servlet大部分的方法都是由服務器,即tomcat來調用,並且方法中的類類型參數,也就是對象也是由服務器來創建,服務器已經將固化代碼寫入,我們只需寫其中的邏輯實現,直接使用即可。
1.2.1.1.1 Servlet中的生命週期
Method Summary |
|
|
destroy |
getServletConfig |
|
|
getServletInfo |
|
init |
|
service |
服務器會在servlet第一次被調用時來創建servlet對象,並且一個servlet只被創建一個對象。
|
|
|
1.2.1.1.2 Servlet中的參數
1、ServletConfig一個ServletConfig對應一段web.xml文件中的<servlet>元素,每個servlet都有自己的ServletConfig。
ServletConfig對象對應web.xml文件中的<servlet>元素。例如你想獲取當前Servlet在web.xml文件中的配置名,那麼可以使用servletConfig.getServletName()方法獲取!
ServletConfig本身來講是一個接口,具體的實現類是由tomcat來完成的,這並不是我們所關心的問題
ServletConfig中提供方法有
Method Summary |
|
|
getInitParameter |
|
getInitParameterNames |
getServletContext |
|
|
getServletName |
1.getInitParameter( String name) 可以獲取初始化參數值
2.getInitParameterNames() 獲得一個存有所有param-name值的枚舉集合
3.getServletContext() 獲取上下文
4.getServletName() 獲取servlet名稱(不用)
web.xml文件配置: <servlet> <servlet-name>BServlet</servlet-name> //表示給該servlet一個名字用於標識 <servlet-class>com.edu118.servlet.BServlet</servlet-class> //該servlet所在的路徑 <init-param> <param-name>p1</param-name> <param-value>v1</param-value> </init-param> <init-param> <param-name>p2</param-name> <param-value>v2</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>BServlet</servlet-name> <url-pattern>/BServlet</url-pattern> //映射一個URL地址讓瀏覽器訪問,必須以“/”開始對命名規範沒有要求
</servlet-mapping>
<!--瀏覽器訪問地址:http://localhost:8080/day02/BServlet -->
|
public void init(ServletConfig config)throws ServletException { String parameter = config.getInitParameter("p1"); System.out.println(parameter); System.out.println("---------------");
Enumeration<String> parameterNames =config.getInitParameterNames(); //迭代器遍歷 while(parameterNames.hasMoreElements()){ System.out.println(config.getInitParameter(parameterNames.nextElement())); } } |
結果: v1 --------------- v1 v2 |
2、ServletRequest和ServletResponse是Servlet#service() 方法的兩個參數,一個是請求對象,一個是響應對象,可以從ServletRequest對象中獲取請求數據,可以使用ServletResponse對象完成響應。你以後會發現,這兩個對象就像是一對恩愛的夫妻,永遠不分離,總是成對出現
Request:
a) String s = httprquest.getLocalAddr(); --獲取瀏覽器訪問服務器的ip地址
b) String name = httprquest.getMethod(); --獲取訪問的方式(get或post等)
Response:
a) getWriter():獲取字符響應流,使用該流可以向客戶端輸出響應信息。例如response.getWriter().print(“<h1>HelloJavaWeb!</h1>”);
b) void setCharacterEncoding(String encoding):用來設置字符響應流的編碼
1.2.2 GenericServlet類
源碼
public abstract class GenericServlet implements Servlet, ServletConfig, java.io.Serializable {
private static final long serialVersionUID = 1L;
private transient ServletConfig config;
public GenericServlet() { // NOOP } @Override public void destroy() { // NOOP by default } @Override public String getInitParameter(Stringname) { return getServletConfig().getInitParameter(name); }
@Override public Enumeration<String> getInitParameterNames() { return getServletConfig().getInitParameterNames(); } @Override public ServletConfig getServletConfig() { returnconfig; } @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, Throwablet) { getServletContext().log(getServletName() + ": " + message, t); }
@Override public abstract void service(ServletRequestreq, ServletResponse res) throws ServletException, IOException;
@Override public String getServletName() { returnconfig.getServletName(); } } |
模擬GenericServlet類
public class EServlet implements Servlet { //定義一個全局變量,使繼承EServlet的類都可以使用 private ServletConfigconfig; //初始化 public void init(ServletConfig config)throws ServletException { this.config =config; /* * 對init初始化進行補充,讓繼承EServlet的類可以再次實現對servlet的初始化 * 並且不影響config這個變量 */ init(); }
public void init() {
} //重寫ServletConfig接口中的方法 //對接口中的方法進行實現 public Enumeration<String> getInitParameterNames() { return getServletConfig().getInitParameterNames();
}
public String getInitParametername(Stringname){ return getServletConfig().getInitParameter(name); }
public ServletContext getServletContext(){ return getServletConfig().getServletContext();
}
public String getServletName(){ return getServletConfig().getServletName(); } public ServletConfig getServletConfig() { // TODO Auto-generated method stub return null; }
public void service(ServletRequest req, ServletResponseres) throws ServletException, IOException { // TODO Auto-generated method stub
}
public String getServletInfo() { // TODO Auto-generated method stub return null; }
public void destroy() { // TODO Auto-generated method stub
}
} |
1.2.3 HttpServlet類
HttpServlet是對GenericServlet的一個繼承,它除了有GenericServlet的service(ServletRequest,ServletResponse)方法之外,還有自身的service(HttpServletRequest,HttpServletResponse)來對Http協議的支持。
|
service |
|
service |
Httpservlet的工作流程如下:
1.瀏覽器發出請求,服務器首先會運行生命週期方法service
2.然後將service(ServletRequest,ServletResponse)強轉爲支持http的servlet
3.獲取請求方法,根據請求方式來調用doGet還是doPost方法(這兩個方法是由我們自己來覆蓋的,需要注意的是當請求方式在servlet沒有對應的方法複寫會出現405錯誤)
1.3 ServletContext域
ServletContext是JavaWeb四大域之一,每一個項目都有且只有一個ServletContext,作用範圍是整個web項目用於不同的servlet之間進行通信的。可以在不同的servlet中來獲取這個ServletContext從而到達共享數據的目的,在服務器啓動的時候被創建,在服務器關閉的時候被銷燬。
1.3.1 ServletContext域對象的獲取
因爲我們新建的servlet類都是繼承自HttpServlet類,而HttpServlet類繼承自GnericServlet類,GenericServlet類中有getServletContext()的方法來獲取ServletContext對象。所以可以直接使用this.getServletContext()獲取
1.3.2 ServletContext的域功能
四個功能方法:
1、voidsetAttribute(String name,Object value):
void setAttribute(String name,Object value):存儲數據 設置域屬性以及域屬性的值。域屬性的名稱爲name,域屬性的值爲value。如果多次調用該方法設置相同的name域屬性名稱,那麼會覆蓋上一次設置的值。 |
2、ObjectgetAttribute(String name):
Object getAttribute(String name):獲取數據 通過域屬性的名稱name獲取對應的域屬性值value,如果域對象中沒有該域屬性,會自動幫你創建該域屬性。-->String value =(String)ServletContext.getAttribute(name); |
3、voidremoveAttribute(String name):
void removeAttribute(String name):用來移除ServletContext對象中的域屬性 |
4、Enumeration<String>getAttributeNames():
Enumeration<String> getAttributeNames():獲取所有域屬性的名稱。 返回的是一個枚舉集合,通過迭代器進行迭代。使用方法與Vector的迭代方式一樣。 |
1.3.3 ServletContext獲取資源的相關路徑
1.3.3.1 獲取真實路徑
String getRealPath(): 獲取與給定的虛擬路徑相對應的真實路徑。
獲取a.txt的真實路徑:
String realPath= servletContext.getRealPath(“/a.txt”);
(realPath的值爲a.txt文件的絕對路徑:F:\tomcat6\webapps\hello\a.txt;)
1.3.3.2 獲取資源流
獲取a.txt資源流:
InputStream in =servletContext.getResourceAsStream(“/a.txt”);
獲取b.txt資源流:
InputStream in =servletContext.getResourceAsStream(“/WEB-INF/b.txt”);
獲取指定目錄下所有資源路徑:
Set set =context.getResourcePaths("/WEB-INF");
System.out.println(set);
注意,本方法必須以“/”開頭!!!
訪問網站統計訪問量的小案例:
@Override protected void doGet(HttpServletRequest req, HttpServletResponseresp) throws ServletException, IOException { // 獲得ServletContext域對象 ServletContext context =this.getServletContext(); // 獲得一個屬性,如果這個屬性沒有就自動幫你創建 Integer countNum = (Integer)context.getAttribute("count"); // 判斷是否是第一次訪問網站 if (countNum ==null) { //設置屬性值 context.setAttribute("count", 1); // count = (Integer)context.getAttribute("count"); } else { context.setAttribute("count",countNum++); } //更新了屬性值然後重新賦值 countNum = (Integer)context.getAttribute("count"); // 輸出一下 System.out.println(countNum); PrintWriter writer = resp.getWriter(); writer.println("<h1>" +countNum + "</h1>"); } |