Servlet接口
什么是Servlet?
Servlet是一種基于Java技術(shù)的Web組件,用于生成動(dòng)態(tài)內(nèi)容,由容器管理,是平臺(tái)無關(guān)的Java類組成,并且由Java Web服務(wù)器加載執(zhí)行,是Web容器的最基本組成單元
什么是Servlet容器?
Servlet容器作為Web服務(wù)器或應(yīng)用服務(wù)器的一部分,通過請(qǐng)求和響應(yīng)提供Web客戶端與Servlets交互的能力,容器管理Servlet實(shí)例以及它們的生命周期(創(chuàng)建、初始化、提供服務(wù)、銷毀等)
在java web中不管是使用J2EE原生的servlet/jsp還是使用springmvc/springboot,在web服務(wù)器看來只是對(duì)外暴露出來的Servlet,而這個(gè)Servlet是javax.servlet.Servlet接口,該接口定義了Servlet引擎與Servlet程序之間通信的協(xié)議約定。
//?Servlet的加載和實(shí)例化可以發(fā)生在容器啟動(dòng)時(shí),也可以延遲初始化直到有請(qǐng)求需要處理時(shí)
public?interface?Servlet?{
???//?負(fù)責(zé)初始化Servlet對(duì)象,容器創(chuàng)建好Servlet對(duì)象后由容器調(diào)用調(diào)用,只執(zhí)行一次
???//?當(dāng)load-on-startup設(shè)置為負(fù)數(shù)或者不設(shè)置時(shí)會(huì)在Servlet第一次用到時(shí)才被調(diào)用
????void?init(ServletConfig?config)?throws?ServletException;
??//?獲取該Servlet的初始化參數(shù)信息
????ServletConfig?getServletConfig();
??//?負(fù)責(zé)響應(yīng)客戶端的請(qǐng)求,當(dāng)容器接收到客戶端要求訪問特定Servlet對(duì)象的請(qǐng)求時(shí),會(huì)調(diào)用該Servlet對(duì)象的service()方法,每次請(qǐng)求都會(huì)執(zhí)行
????void?service(ServletRequest?req,?ServletResponse?res)
?throws?ServletException,?IOException;
??//?返回Servlet信息,包含創(chuàng)建者、版本、版權(quán)等信息
????String?getServletInfo();
??//?Servlet結(jié)束生命周期時(shí)調(diào)用,釋放Servlet對(duì)象占用的資源
????void?destroy();
}
而為了簡(jiǎn)化開發(fā),jdk中提供了一個(gè)實(shí)現(xiàn)Servlet接口的簡(jiǎn)單的Servlet類,javax.servlet.GenericServlet,該類實(shí)現(xiàn)了Servlet的基本功能,對(duì)init(ServletConfig config)、service(ServletRequest req, ServletResponse res)和destroy()方法提供了默認(rèn)實(shí)現(xiàn)
jdk針對(duì)HTTP協(xié)議專門提供了一個(gè)Servlet類,javax.servlet.http.HttpServlet,該類繼承于GenericServlet類,在其基礎(chǔ)上針對(duì)HTTP的特點(diǎn)進(jìn)行擴(kuò)充,一般編寫程序時(shí)繼承HttpServlet即可,這樣只需要重寫doGet()和doPost()方法即可

Servlet中涉及的主要對(duì)象
-
請(qǐng)求對(duì)象 ServletRequest、HttpServletRequest -
響應(yīng)對(duì)象 ServletResponse、HttpServletResponse -
Servlet配置對(duì)象 ServletConfig -
Servlet上下文對(duì)象 ServletConfig
Servlet注冊(cè)與運(yùn)行
Servlet編寫好之后需要在web.xml中進(jìn)行注冊(cè)和映射才能被Servlet容器加載從而被外界訪問
<!--?注意servlet和servlet-mapping都是成對(duì)出現(xiàn)的?-->?
<!--?注冊(cè)Servlet?-->????
?<servlet>
????????<servlet-name>HW</servlet-name>
????????<servlet-class>com.zhanghe.study.servlet.HelloWorldServlet</servlet-class>
?????<!--?配置servlet初始化init時(shí)中ServletConfig參數(shù)-->
????????<init-param>
??????????<param-name>name</param-name>
??????????<param-value>john</param-value>
????????</init-param>
????????<!--?servlet加載時(shí)機(jī),若為負(fù)數(shù),則在第一次請(qǐng)求時(shí)被創(chuàng)建,若為0或者正數(shù),在web應(yīng)用被Servlet容器加載時(shí)創(chuàng)建實(shí)例,值越小越早被啟動(dòng)??-->
????????<load-on-startup>1</load-on-startup>
????</servlet>
??<!--?映射Servlet?-->
????<servlet-mapping>
??????<!--?對(duì)應(yīng)servlet標(biāo)簽中的servlet-name值?-->
????????<servlet-name>HW</servlet-name>
???????<!--?開頭的/表示web用用程序的根目錄?-->
????????<url-pattern>/HelloWorld</url-pattern>
????</servlet-mapping>
tomcat中的web.xml包含有一個(gè)缺省的Servlet
????<servlet>
????????<servlet-name>default</servlet-name>
????????<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
????????<init-param>
????????????<param-name>debug</param-name>
????????????<param-value>0</param-value>
????????</init-param>
????????<init-param>
????????????<param-name>listings</param-name>
????????????<param-value>false</param-value>
????????</init-param>
????????<load-on-startup>1</load-on-startup>
????</servlet>
????<servlet-mapping>
????????<servlet-name>default</servlet-name>
????????<url-pattern>/</url-pattern>
????</servlet-mapping>
ServletConfig
對(duì)于每個(gè)Servlet可能在啟動(dòng)時(shí)都需要一些初始化參數(shù),而所有的Servlet是交由Servlet引擎去實(shí)例化的,那么也就是需要將每個(gè)Servlet的初始化參數(shù)也都配置到web.xml中,Servlet引擎將Servlet容器對(duì)象和Servlet的配置信息封裝到ServletConfig中,并在Servlet初始化時(shí)將ServletConfig傳遞給該Servlet。javax.servlet.ServletConfig接口的作用就是用來定義ServletConfig對(duì)象所需要對(duì)外提供的方法
public?interface?ServletConfig?{
??//?獲取web.xml中定義的servlet-name
????String?getServletName();
?//?ServletContext表示的是應(yīng)用本身
????ServletContext?getServletContext();
??//?獲取init-param配置的參數(shù)
????String?getInitParameter(String?name);
??//?獲取init-param配置的所有參數(shù)
????Enumeration<String>?getInitParameterNames();
}
Servlet引擎裝載并創(chuàng)建一個(gè)Servlet對(duì)象后,會(huì)調(diào)用該對(duì)象的init(ServletConfig config)方法,Servlet中的ServletConfig getServletConfig()方法會(huì)返回init傳入的ServletConfig對(duì)象
????<servlet>
????????<servlet-name>HW</servlet-name>
????????<servlet-class>com.zhanghe.study.servlet.HelloWorldServlet</servlet-class>
????????<init-param>
????????????<param-name>name</param-name>
????????????<param-value>zhanghe</param-value>
????????</init-param>
????</servlet>
//?獲取指定的屬性
config.getInitParameter("name")
//?獲取所有的屬性
config.getInitParameters()
ServletContext
每個(gè)Web應(yīng)用程序在啟動(dòng)時(shí)都會(huì)創(chuàng)建一個(gè)ServletContext對(duì)象,每個(gè)Web應(yīng)用程序都有一個(gè)唯一的ServletContext對(duì)象,javax.servlet.ServletContext接口定義了ServletContext需要對(duì)外提供的方法,Servlet通過這些方法來和ServletContext容器進(jìn)行通信
-
該對(duì)象代表當(dāng)前WEB應(yīng)用,可以獲取到web應(yīng)用的信息,一個(gè)Web應(yīng)用只有一個(gè)ServletContext對(duì)象 -
可以使用ServletConfig的getServletContext()獲取到ServletContext -
可以獲取web應(yīng)用的初始化參數(shù),這是全局的方法,在web.xml中配置 -
獲取web應(yīng)用某個(gè)文件的絕對(duì)路徑(在服務(wù)器上的路徑,不是部署前的方法) getRealPath -
獲取當(dāng)前應(yīng)用的名稱 getContextPath -
獲取當(dāng)前web應(yīng)用的某一個(gè)文件對(duì)應(yīng)的輸入流 getResourceAsStream() path是相對(duì)于當(dāng)前web應(yīng)用的根目錄
????<context-param>
????????<param-name>email</param-name>
????????<param-value>master@163.com</param-value>
????</context-param>
servlet生命周期
生命周期相關(guān)方法,servlet生命周期中的方法全是由servlet容器來調(diào)用的
-
構(gòu)造器 web容器調(diào)用Servlet的無參構(gòu)造器,默認(rèn)是在第一次請(qǐng)求時(shí)被加載,可以通過load-on-startup標(biāo)簽來進(jìn)行設(shè)置什么時(shí)候加載 -
init方法 -
service方法 -
destory方法
init方法--初始化
init方法在第一次創(chuàng)建servlet時(shí)被調(diào)用,在后續(xù)每次請(qǐng)求時(shí)都不會(huì)被調(diào)用。
當(dāng)用戶調(diào)用servlet的時(shí)候,該servlet的一個(gè)實(shí)例就會(huì)被創(chuàng)建,并且為每一個(gè)用戶產(chǎn)生一個(gè)新的線程,init()用于進(jìn)行一些初始化數(shù)據(jù)的加載和處理,這些數(shù)據(jù)會(huì)被用于servlet的整個(gè)生命周期
void?init(ServletConfig?config)?throws?ServletException;
為了防止重寫該方法時(shí)開發(fā)者忘記將入?yún)onfig賦值給成員變量config,故而提供了GenericServlet類進(jìn)行了一次封裝
public?void?init(ServletConfig?config)?throws?ServletException?{
????this.config?=?config;
????this.init();
}
在進(jìn)行Servlet重寫時(shí)只需要重寫不帶參數(shù)的init方法即可
public?void?init()?throws?ServletException
該方法是由servlet容器調(diào)用的
什么時(shí)候觸發(fā)初始化
有兩種情況會(huì)進(jìn)行Servlet的初始化
-
Servlet被客戶端首次請(qǐng)求訪問時(shí)觸發(fā)初始化方法
-
如果配置了load-on-startup元素,則在Servlet容器啟動(dòng)該Servlet所屬Web應(yīng)用時(shí)就會(huì)初始化該Servlet
?????<servlet>
?????????<servlet-name>dispatcherServlet</servlet-name>
?????????<servlet-class>
?????????????org.springframework.web.servlet.DispatcherServlet
?????????</servlet-class>
?????????<load-on-startup>1</load-on-startup>
?????</servlet>
重寫init方法
GenericServlet實(shí)現(xiàn)了Servlet和ServletConfig,是一個(gè)抽象類,并對(duì)init(ServletConfig var1)方法進(jìn)行了一層封裝,有一個(gè)ServletConfig成員變量,在init()方法中進(jìn)行了初始化,使得可以直接在GenericServlet中直接使用ServletConfig方法
而我們平時(shí)寫Servlet大多是繼承于HttpServlet類的,在對(duì)init方法進(jìn)行重寫時(shí),重寫不帶參的init()方法即可
//GenericServlet類
public?void?init(ServletConfig?config)?throws?ServletException?{
????this.config?=?config;
????this.init();
}
public?void?init()?throws?ServletException?{
}
該方法由GenericServlet的調(diào)用,如果需要使用到ServletConfig則調(diào)用getServletConfig()方法來獲取
service方法
service方法是實(shí)際處理請(qǐng)求的方法,servlet容器調(diào)用service方法來處理請(qǐng)求,并將響應(yīng)寫回到客戶端,每次服務(wù)器接收到一個(gè)新的servlet請(qǐng)求時(shí),服務(wù)器會(huì)產(chǎn)生一個(gè)新的線程來調(diào)用服務(wù)
void?service(ServletRequest?req,?ServletResponse?res)?throws?ServletException,?IOException;
處理請(qǐng)求邏輯
HttpServlet繼承了GenericServlet,重寫了service方法,將ServletRequest和ServletResponse轉(zhuǎn)換為HttpServletRequest和HttpServletResponse,并根據(jù)不同的請(qǐng)求方式進(jìn)行分發(fā),doGet/doPost/doHead等
@Override
public?void?service(ServletRequest?req,?ServletResponse?res)
????throws?ServletException,?IOException
{
????HttpServletRequest??request;
????HttpServletResponse?response;
????//?如果請(qǐng)求類型不相符,則拋出異常
????if?(!(req?instanceof?HttpServletRequest?&&
????????????res?instanceof?HttpServletResponse))?{
????????throw?new?ServletException("non-HTTP?request?or?response");
????}
??//?轉(zhuǎn)換成Http的request和response
????request?=?(HttpServletRequest)?req;
????response?=?(HttpServletResponse)?res;
??//?進(jìn)行http的處理方法
????service(request,?response);
}
protected?void?service(HttpServletRequest?req,?HttpServletResponse?resp)
????????throws?ServletException,?IOException
????{
????//?獲取請(qǐng)求類型
????????String?method?=?req.getMethod();
???//?根據(jù)不同的請(qǐng)求類型調(diào)用不同的方法
????????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?=?req.getDateHeader(HEADER_IFMODSINCE);
????????????????if?(ifModifiedSince?<?lastModified)?{
????????????????????//?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?{
????????????//
????????????//?Note?that?this?means?NO?servlet?supports?whatever
????????????//?method?was?requested,?anywhere?on?this?server.
????????????//
????????????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);
????????}
????}
servlet可以在任何協(xié)議下訪問 ,寫的Servlet必須實(shí)現(xiàn)Servlet接口,在http協(xié)議下可以使用HttpServlet ,用來給Web訪問的
在HttpServlet類中對(duì)于service()方法進(jìn)行了處理,根據(jù)請(qǐng)求方式的不同,將請(qǐng)求分發(fā)到了不同的方法,而我們一般情況下寫Servlet也是繼承自HttpServlet的,所以在寫請(qǐng)求處理邏輯時(shí),只需要重寫doGet()和doPost()方法即可
//?HttpServlet類
protected?void?doGet(HttpServletRequest?req,?HttpServletResponse?resp)?throws?ServletException,?IOException?{
????String?msg?=?lStrings.getString("http.method_get_not_supported");
????this.sendMethodNotAllowed(req,?resp,?msg);
}
protected?void?doPost(HttpServletRequest?req,?HttpServletResponse?resp)?throws?ServletException,?IOException?{
????????String?msg?=?lStrings.getString("http.method_post_not_supported");
????????this.sendMethodNotAllowed(req,?resp,?msg);
}
GET方法
GET方法時(shí)瀏覽器向web服務(wù)器傳遞信息的默認(rèn)方法,會(huì)在地址欄上產(chǎn)生很長(zhǎng)的字符串,且GET方法有大小限制,請(qǐng)求字符串中最多只能有1024個(gè)字符
POST方法
POST方法不將請(qǐng)求信息放到地址中
destroy方法
destory()方法只在servlet生命周期結(jié)束時(shí)被調(diào)用一次。可以在destory()方法中進(jìn)行一些資源的清理,如關(guān)閉數(shù)據(jù)庫連接、停止后臺(tái)線程等
https://zhhll.icu/2021/javaweb/基礎(chǔ)/1.Servlet接口/文章來源:http://www.zghlxwxcb.cn/news/detail-829994.html
本文由 mdnice 多平臺(tái)發(fā)布文章來源地址http://www.zghlxwxcb.cn/news/detail-829994.html
到了這里,關(guān)于JavaWeb之Servlet接口的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!