jsp调用servlet_宇宙最全Servlet详解!!
第五章:Servlet
定義:
Servlet簡介:
Servlet是sun公司提供的一門用于開發(fā)動態(tài)web資源的技術。
Sun公司在其API中提供了一個servlet接口,用戶若想用發(fā)一個動態(tài)web資源(即開發(fā)一個Java程序向瀏覽器輸出數(shù)據(jù)),需要完成以下2個步驟: 1、編寫一個Java類,實現(xiàn)servlet接口。 2、把開發(fā)好的Java類部署到web服務器中。
按照一種約定俗成的稱呼習慣,通常我們也把實現(xiàn)了servlet接口的java程序,稱之為Servlet。
總的來講:運行在Servlet容器中的Java類,可以接受請求并產生響應,是MVC思想的控制層=
那Servlet和我們之前編寫的do_XXX.jsp有啥區(qū)別?
如Test.jsp在運行時首先解析成一個Java類Test_jsp.java,而這個Test_jsp.java繼承于org.apache.jasper.runtime.HttpJspBase類,而HttpJspBase又是繼承自HttpServlet的類,由此可以得出一個結論,就是JSP在運行時會被Web容器翻譯為一個Servlet
也可以打開Servlet源碼來查看一下基礎關系圖:
[面試題]:
jsp和Servlet有啥區(qū)別?
jsp頁面繼承于org.apache.jasper.runtime.HttpJspBase類,而HttpJspBase又是繼承自HttpServlet的類,由此可以得出一個結論,就是JSP在運行時會被Web容器翻譯為一個Servlet,他們本質上都是同一個東西,只不過jsp注重頁面的顯示,Servlet更注重流程的控制。servlet體系結構:
servlet的生命周期:

Servlet運行過程圖:
servlet接口里面的方法:
servlet的生命周期:
servlet體系結構:

其中,init( ),service( ),destroy( )是Servlet生命周期的方法。代表了Servlet從“出生”到“工作”再到“死亡 ”的過程。Servlet容器(例如TomCat)會根據(jù)下面的規(guī)則來調用這三個方法:
1.init( ),當Servlet第一次被請求時,Servlet容器就會開始調用這個方法來初始化一個Servlet對象出來,但是這個方法在后續(xù)請求中不會在被Servlet容器調用,就像人只能“出生”一次一樣。我們可以利用init( )方法來執(zhí)行相應的初始化工作。調用這個方法時,Servlet容器會傳入一個ServletConfig對象進來從而對Servlet對象進行初始化。
2.service( )方法,每當請求Servlet時,Servlet容器就會調用這個方法。就像人一樣,需要不停的接受老板的指令并且“工作”。第一次請求時,Servlet容器會先調用init( )方法初始化一個Servlet對象出來,然后會調用它的service( )方法進行工作,但在后續(xù)的請求中,Servlet容器只會調用service方法了。
3.destory,當要銷毀Servlet時,Servlet容器就會調用這個方法,就如人一樣,到時期了就得死亡。在卸載應用程序或者關閉Servlet容器時,就會發(fā)生這種情況,一般在這個方法中會寫一些清除代碼。
public class MyFirstServlrt implements Servlet { ? ?@Override ? ?public void init(ServletConfig servletConfig) throws ServletException { ? ? ? ?System.out.println("Servlet正在初始化"); ? } ? ?@Override ? ?public ServletConfig getServletConfig() { ? ? ? ?return null; ? } ? ?@Override ? ?public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { ? ? ? ?//專門向客服端提供響應的方法 ? ? ? ?System.out.println("Servlet正在提供服務"); ? } ? ?@Override ? ?public String getServletInfo() { ? ? ? ?return null; ? } ? ?@Override ? ?public void destroy() { ? ? ? ?System.out.println("Servlet正在銷毀"); ? }} ? ? ?然后在xml中配置正確的映射關系,在瀏覽器中訪問Servlet,第一次訪問時,控制臺輸出了如下信息:
然后,我們在瀏覽器中刷新3遍:
控制臺輸出的信息變成了下面這樣:
接下來,我們關閉Servlet容器:
控制臺輸出了Servlet的銷毀信息,這就是一個Servlet的完整生命周期。
Servlet 的其它兩個方法
?getServletInfo( ),這個方法會返回Servlet的一段描述,可以返回一段字符串。
?getServletConfig( ),這個方法會返回由Servlet容器傳給init( )方法的ServletConfig對象。
相關其他接口:
GenericServlet抽象類
前面我們編寫Servlet一直是通過實現(xiàn)Servlet接口來編寫的,但是,使用這種方法,則必須要實現(xiàn)Servlet接口中定義的所有的方法,即使有一些方法中沒有任何東西也要去實現(xiàn),并且還需要自己手動的維護ServletConfig這個對象的引用。因此,這樣去實現(xiàn)Servlet是比較麻煩的。幸好,GenericServlet抽象類的出現(xiàn)很好的解決了這個問題。本著盡可能使代碼簡潔的原則,GenericServlet實現(xiàn)了Servlet和ServletConfig接口。
其中,GenericServlet抽象類相比于直接實現(xiàn)Servlet接口,有以下幾個好處:
1.為Servlet接口中的所有方法提供了默認的實現(xiàn),則程序員需要什么就直接改什么,不再需要把所有的方法都自己實現(xiàn)了。2.提供方法,包圍ServletConfig對象中的方法。HttpServlet抽象類
HttpServlet抽象類是繼承于GenericServlet抽象類而來的。使用HttpServlet抽象類時,還需要借助分別代表Servlet請求和Servlet響應的HttpServletRequest和HttpServletResponse對象。
HttpServletRequest接口擴展于javax.servlet.ServletRequest接口,HttpServletResponse接口擴展于javax.servlet.servletResponse接口。
HttpServlet抽象類覆蓋了GenericServlet抽象類中的Service( )方法,并且添加了一個自己獨有的Service(HttpServletRequest request,HttpServletResponse方法
讓我們來具體的看一看HttpServlet抽象類是如何實現(xiàn)自己的service方法吧:
我們看到是一個抽象方法,也就是HttpServlet要自己去實現(xiàn)這個service方法,我們在看看HttpServlet是怎么覆蓋這個service方法的:
protected void service(HttpServletRequest req, HttpServletResponse resp) ? ? ? ?throws ServletException, IOException { ? ? ? ?String method = req.getMethod(); ? ? ? ?if (method.equals(METHOD_GET)) { ? ? ? ? ? ?long lastModified = getLastModified(req); ? ? ? ? ? ?if (lastModified == -1) { ? ? ? ? ? ? ? ?// servlet doesn't support if-modified-since, no reason ? ? ? ? ? ? ? ?// to go through further expensive logic ? ? ? ? ? ? ? ?doGet(req, resp); ? ? ? ? ? } else { ? ? ? ? ? ? ? ?long ifModifiedSince; ? ? ? ? ? ? ? ?try { ? ? ? ? ? ? ? ? ? ?ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE); ? ? ? ? ? ? ? } catch (IllegalArgumentException iae) { ? ? ? ? ? ? ? ? ? ?// Invalid date header - proceed as if none was set ? ? ? ? ? ? ? ? ? ?ifModifiedSince = -1; ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ?if (ifModifiedSince < (lastModified / 1000 * 1000)) { ? ? ? ? ? ? ? ? ? ?// If the servlet mod time is later, call doGet() ? ? ? ? ? ? ? ? ? ?// Round down to the nearest second for a proper compare ? ? ? ? ? ? ? ? ? ?// A ifModifiedSince of -1 will always be less ? ? ? ? ? ? ? ? ? ?maybeSetLastModified(resp, lastModified); ? ? ? ? ? ? ? ? ? ?doGet(req, resp); ? ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? ? ?resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED); ? ? ? ? ? ? ? } ? ? ? ? ? } ? ? ? } else if (method.equals(METHOD_HEAD)) { ? ? ? ? ? ?long lastModified = getLastModified(req); ? ? ? ? ? ?maybeSetLastModified(resp, lastModified); ? ? ? ? ? ?doHead(req, resp); ? ? ? } else if (method.equals(METHOD_POST)) { ? ? ? ? ? ?doPost(req, resp); ? ? ? } else if (method.equals(METHOD_PUT)) { ? ? ? ? ? ?doPut(req, resp); ? ? ? } else if (method.equals(METHOD_DELETE)) { ? ? ? ? ? ?doDelete(req, resp); ? ? ? } else if (method.equals(METHOD_OPTIONS)) { ? ? ? ? ? ?doOptions(req,resp); ? ? ? } else if (method.equals(METHOD_TRACE)) { ? ? ? ? ? ?doTrace(req,resp); ? ? ? } else { ? ? ? ? ? ?String errMsg = lStrings.getString("http.method_not_implemented"); ? ? ? ? ? ?Object[] errArgs = new Object[1]; ? ? ? ? ? ?errArgs[0] = method; ? ? ? ? ? ?errMsg = MessageFormat.format(errMsg, errArgs); ? ? ? ? ? ?resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg); ? ? ? } ? }我們會發(fā)現(xiàn)在service方法中還是沒有任何的服務邏輯,但是卻在解析HttpServletRequest中的方法參數(shù),并調用以下方法之一:doGet,doPost,doHead,doPut,doTrace,doOptions和doDelete。這7種方法中,每一種方法都表示一個Http方法。doGet和doPost是最常用的。所以,如果我們需要實現(xiàn)具體的服務邏輯,不再需要覆蓋service方法了,只需要覆蓋doGet或者doPost就好了
總之,HttpServlet有兩個特性是GenericServlet所不具備的:
1.不用覆蓋service方法,而是覆蓋doGet或者doPost方法。在少數(shù)情況,還會覆蓋其他的5個方法。
2.使用的是HttpServletRequest和HttpServletResponse對象。
HttpServletRequest接口
?HttpServletRequest表示Http環(huán)境中的Servlet請求。它擴展于javax.servlet.ServletRequest接口,并添加了幾個方法。如圖:
常用方法:
String getContextPath();//返回請求上下文的請求URI部分Cookie[] getCookies();//返回一個cookie對象數(shù)組String getHeader(String var1);//返回指定HTTP標題的值String getMethod();//返回生成這個請求HTTP的方法名稱String getQueryString();//返回請求URL中的查詢字符串HttpSession getSession();//返回與這個請求相關的會話對象HttpServletResponse接口
它繼承自ServletResponse接口,專門用來封裝HTTP響應消息。?由于HTTP請求消息分為狀態(tài)行,響應消息頭,響應消息體三部分,因此,在HttpServletResponse接口中定義了向客戶端發(fā)送響應狀態(tài)碼,響應消息頭,響應消息體的方法。
常用方法:
void addCookie(Cookie var1);//給這個響應添加一個cookievoid addHeader(String var1, String var2);//給這個請求添加一個響應頭void sendRedirect(String var1) throws IOException;//發(fā)送一條響應碼,講瀏覽器跳轉到指定的位置void setStatus(int var1);//設置響應行的狀態(tài)碼Response的亂碼問題:
由于計算機中的數(shù)據(jù)都是以二進制形式存儲的,因此,當傳輸文本時,就會發(fā)生字符和字節(jié)之間的轉換。字符與字節(jié)之間的轉換是通過查碼表完成的,將字符轉換成字節(jié)過程稱為編碼,將字節(jié)轉換成字符的過程為解碼,如果編碼和解碼使用的碼表不一致,就會導致亂碼問題。
解決方式1:
response緩存區(qū)的默認編碼是ISO-8859-1,此碼表沒有中文。所以需要更改response的編碼方式:
response.setCharacterEncoding("UTF-8");通過更改response的編碼方式為UTF-8,任然無法解決亂碼問題,因為發(fā)送端服務端雖然改變了編碼方式為UTF-8,但是接收端瀏覽器端仍然使用GB2312編碼方式解碼,還是無法還原正常的中文,因此還需要告知瀏覽器端使用UTF-8編碼去解碼。所以還需加上:
response.setHeader("Content-Type","text/html;charset=utf-8");上面通過調用兩個方式分別改變服務端對于Response的編碼方式以及瀏覽器的解碼方式為同樣的UTF-8編碼來解決編碼方式不一樣發(fā)生亂碼的問題。
解決方式2:
response.setContentType("text/html;charset=UTF-8")這個方法包含了上面的兩個方法的調用,因此在實際的開發(fā)中,只需要調用一個response.setContentType("text/html;charset=UTF-8")方法即可.
response.setContentType("text/html;charset=UTF-8");ServletConfig接口
當Servlet容器初始化Servlet時,Servlet容器會給Servlet的init( )方式傳入一個ServletConfig對象.
方法如下:
ServletContext接口
獲取Web應用上下文,與Servlet容器進行通信
ServletContext對象表示Servlet應用程序。每個Web應用程序都只有一個ServletContext對象。在將一個應用程序同時部署到多個容器的分布式環(huán)境中,每臺Java虛擬機上的Web應用都會有一個ServletContext對象。
通過在ServletConfig中調用getServletContext方法,也可以獲得ServletContext對象。
那么為什么要存在一個ServletContext對象呢?存在肯定是有它的道理,因為有了ServletContext對象,就可以共享從應用程序中的所有資料處訪問到的信息,并且可以動態(tài)注冊Web對象。前者將對象保存在ServletContext中的一個內部Map中。保存在ServletContext中的對象被稱作屬性。
常用方法:
| String getInitParameter ( ? ? ? ? ? ? ?String name ) | 獲取名為name的系統(tǒng)范圍的初始化參數(shù)值,系統(tǒng)范圍的初始化參數(shù)可在部署描述符中使用param>元素定義** |
| void setAttribute ( ?String name, Object object ) | 設置名稱為name的屬性 |
| Object getAttribute ( ? ? ? ? ? ? ?String name ) | 獲取名稱為name的屬性 |
| String getRealPath ( ? ? ? ? ? ? ? String path ) | 返回參數(shù)所代表目錄的真實路徑 |
| void log ( String message ) | 記錄一般日志信息 |
上機案例:
案例1:
package com.servlet;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class MyServlet extends HttpServlet { private static final long serialVersionUID = 1L; ? ? ? @Override public void init() throws ServletException { super.init(); System.out.println("初始化Servlet");} protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response);} protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("正在執(zhí)行業(yè)務....");} @Override public void destroy() { System.out.println("銷毀Servlet..."); super.destroy();}}注意:這里的關閉服務器,一定要在tomcat/bin目錄下,shutDown.sh下關閉才能實現(xiàn)
還有就是Eclipse2020版默認是使用注解方式,如果需要編寫Servlet后自動配置web.xml文件你就需要把這個項目編寫的版本調到3.0一下就可以。
如圖:
案例2:
xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> ?<display-name>ServletDemo2display-name> ?<welcome-file-list> ? ?<welcome-file>index.jspwelcome-file> ?welcome-file-list> ?<servlet> ? ?<servlet-name>MyServletservlet-name> ? ?<servlet-class>com.servlet.MyServletservlet-class> ? ?<init-param> ? <param-name>initParamparam-name> ? <param-value>Hello Servletparam-value> ? ?init-param> ?servlet> ?<servlet-mapping> ? ?<servlet-name>MyServletservlet-name> ? ?<url-pattern>/myServleturl-pattern> ?servlet-mapping>web-app>package com.servlet;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class MyServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response);} protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("處理請求時,doGet()方法被調用。"); String initParam = getInitParameter("initParam"); System.out.println(initParam);}}案例3:
xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> ?<display-name>ServletDemo2display-name> ?<context-param> ? ?<param-name>contextParamparam-name> ? ?<param-value>ContextParamValueparam-value> ?context-param> ? ?<servlet> ? ?<servlet-name>MyServletservlet-name> ? ?<servlet-class>com.servlet.MyServletservlet-class> ? ?<init-param> ? <param-name>initParamparam-name> ? <param-value>Hello Servletparam-value> ? ?init-param> ?servlet> ?<servlet-mapping> ? ?<servlet-name>MyServletservlet-name> ? ?<url-pattern>/myServleturl-pattern> ?servlet-mapping> ? ? ?<welcome-file-list> ? ? ?<welcome-file>myServletwelcome-file> ? welcome-file-list>web-app>public void doGet(HttpServletRequest request, ? ? ? ? ? ? ? ? ? ? HttpServletResponse response) ? ? ? ? ? ? ? ? ? throws ServletException, IOException { ? ? ? System.out.println("處理請求時,doGet()方法被調用。"); ? ? ? String initParam = getInitParameter("initParam"); ? ? ? String contextParam = ? ? ? ? ? this.getServletContext().getInitParameter("contextParam"); ? ? ? System.out.println("Servlet初始化參數(shù)" + initParam); ? ? ? System.out.println("上下文參數(shù)" + contextParam); ? }Servlet注解:
Servlet3.0通過注解實現(xiàn)Servlet,簡化web.xml的配置,后期我們的框架技術都是可以通過注解來簡化配置,大大提高開發(fā)效率。
@WebServlet(name = "MyServlet",urlPatterns ="/myServlet" )public class MyServlet extends HttpServlet { private static final long serialVersionUID = 1L; ? ? ? @Override public void init() throws ServletException { super.init(); System.out.println("初始化Servlet");} protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response);} protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("正在執(zhí)行業(yè)務....");} @Override public void destroy() { System.out.println("銷毀Servlet..."); super.destroy();}}@WebServlet屬性列表:
| name | String | 指定Servlet 的 name 屬性,等價于 。如果沒有顯式指定,則該 Servlet 的取值即為類的全限定名。 |
| value | String[] | 該屬性等價于 urlPatterns 屬性。兩個屬性不能同時使用。 |
| urlPatterns | String[] | 指定一組 Servlet 的 URL 匹配模式。等價于標簽。 |
| loadOnStartup | int | 指定 Servlet 的加載順序,等價于 標簽。 |
| initParams | WebInitParam[] | 指定一組 Servlet 初始化參數(shù),等價于標簽。 |
| asyncSupported | boolean | 聲明 Servlet 是否支持異步操作模式,等價于 標簽。 |
| description | String | 該 Servlet 的描述信息,等價于 標簽。 |
| displayName | String | 該 Servlet 的顯示名,通常配合工具使用,等價于 標簽。 |
總結
以上是生活随笔為你收集整理的jsp调用servlet_宇宙最全Servlet详解!!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 拳打奔驰C脚踢宝马3?蔚来ET5在多个城
- 下一篇: Excel表格怎么打印在a4纸上(exc