Servlet方法详解
Servlet:
Servlet是SUN公司提供的一套規(guī)范,名稱就叫Servlet規(guī)范,它也是JavaEE規(guī)范之一。使用JavaEE的API。目前在Oracle官網(wǎng)中的最新版本是JavaEE8,
- Servlet是一個(gè)運(yùn)行在web服務(wù)端的java小程序
- 它可以用于接收和響應(yīng)客戶端的請求
- 要想實(shí)現(xiàn)Servlet功能,可以實(shí)現(xiàn)Servlet接口,繼承GenericServlet或者HttpServlet
- 每次請求都會(huì)執(zhí)行service方法
- Servlet還支持配置
Servlet執(zhí)行過程:
Servlet關(guān)系視圖:
Servlet實(shí)現(xiàn)方式:
1、 實(shí)現(xiàn)Servlet接口,接口中的方法必須全部實(shí)現(xiàn)。
表示接口中的所有方法在需求方面都有重寫的必要。這種方式支持最大程度的自定義。
2、繼承GenericServlet,service方法必須重寫,其他方可根據(jù)需求,選擇性重寫。
表示只在接收和響應(yīng)客戶端請求這方面有重寫的需求,而其他方法可根據(jù)實(shí)際需求選擇性重寫,使開發(fā)Servlet變得簡單。但是,此種方式是和HTTP協(xié)議無關(guān)的。
3、繼承HttpServlet,它是javax.servlet.http包下的一個(gè)抽象類,是GenericServlet的子類。如果選擇繼承HttpServlet時(shí),只需要重寫doGet和doPost方法,不要覆蓋service方法。
表示我們的請求和響應(yīng)需要和HTTP協(xié)議相關(guān)。也就是說通過HTTP協(xié)議來訪問的。那么每次請求和響應(yīng)都符合HTTP協(xié)議的規(guī)范。請求的方式就是HTTP協(xié)議所支持的方式
實(shí)現(xiàn)Servlet:
public class ServletDemo03 implements Servlet {@Overridepublic void init(ServletConfig servletConfig) throws ServletException {}@Overridepublic ServletConfig getServletConfig() {return null;}@Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {System.out.println("實(shí)現(xiàn)Servlet方式");}@Overridepublic String getServletInfo() {return null;}@Overridepublic void destroy() {} }繼承GenericServlet:
public class ServletDemo01 extends GenericServlet {@Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {System.out.println("service方法執(zhí)行了...");} }繼承HttpServlet::
public class ServletDemo extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("Servlet執(zhí)行了");}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);} }配置文件:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><!--Servlet配置--><servlet><servlet-name>servletDemo</servlet-name><servlet-class>com.example.demo.ServletDemo</servlet-class></servlet><!--映射配置--><servlet-mapping><servlet-name>servletDemo</servlet-name><url-pattern>/servletDemo</url-pattern></servlet-mapping><!--生命周期配置--><servlet><servlet-name>servletDemo02</servlet-name><servlet-class>com.example.demo.ServletDemo02</servlet-class></servlet><servlet-mapping><servlet-name>servletDemo02</servlet-name><url-pattern>/servletDemo02</url-pattern></servlet-mapping></web-app>Servlet生命周期:
- 對象的生命周期,就是對象從生到死的過程,
- 出生:請求第一次到達(dá)Servlet時(shí),對象就創(chuàng)建出來,并且初始化成功。只出生一次,就放到內(nèi)存中。
- 活著:服務(wù)器提供服務(wù)的整個(gè)過程中,該對象一直存在,每次都是執(zhí)行service方法。
- 死亡:當(dāng)服務(wù)停止時(shí),或者服務(wù)器宕機(jī)時(shí),對象消亡。
- Servlet對象只會(huì)創(chuàng)建一次,銷毀一次。所以,Servlet對象只有一個(gè)實(shí)例。如果一個(gè)對象實(shí)例在應(yīng)用中是唯一的存在,用了單例模式。
演示:
public class ServletDemo02 extends HttpServlet {// 對象出生@Overridepublic void init() throws ServletException {System.out.println("出生了");}// 對象服務(wù)@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("收到客戶端請求");}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);}// 對象死亡@Overridepublic void destroy() {System.out.println("掛了");} }線程安全:
在Servlet中定義了類成員之后,多個(gè)瀏覽器都會(huì)共享類成員的數(shù)據(jù)。其實(shí)每一個(gè)瀏覽器端發(fā)送請求,就代表是一個(gè)線程,那么多個(gè)瀏覽器就是多個(gè)線程,多個(gè)線程會(huì)共享Servlet類成員中的數(shù)據(jù),其中任何一個(gè)線程修改了數(shù)據(jù),都會(huì)影響其他線程。因此,所以Servlet它不是線程安全的。分析產(chǎn)生這個(gè)問題的根本原因,其實(shí)就是因?yàn)镾ervlet是單例,單例對象的類成員只會(huì)隨類實(shí)例化時(shí)初始化一次,之后的操作都是改變,而不會(huì)重新初始化。
解決:
在Servlet中定義類成員要慎重。如果類成員是共用的,并且只會(huì)在初始化時(shí)賦值,其余時(shí)間都是獲取的話,那么是沒問題。如果類成員并非共用,或者每次使用都有可能對其賦值,那么就要考慮線程安全問題了,把它定義到doGet或者doPost方法里面去就可以了。或者是直接加synchronized
演示:
public class ServletDemo03 extends HttpServlet {private String username;@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {synchronized (this) {// 在這里聲明的話,就是把成員變量變成局部變量,谷歌進(jìn)來是一個(gè)username,火狐進(jìn)來又是另一個(gè)就不會(huì)出現(xiàn)出數(shù)據(jù)不安全了// String username = null;// String getParameter(String name):根據(jù)參數(shù)名稱獲取參數(shù)值username = req.getParameter("username");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}// resp.getWriter 傳數(shù)據(jù)給前端PrintWriter writer = resp.getWriter();writer.println("username:" + username);writer.close();}}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req,resp);} }Servlet映射三種方式:
說明:映射優(yōu)先級(jí):越具體優(yōu)先級(jí)越高,1>2>3
演示:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><!--<!–ServletHttp配置–><servlet><servlet-name>servletDemo</servlet-name><servlet-class>com.example.demo.ServletDemo</servlet-class></servlet><servlet-mapping><servlet-name>servletDemo</servlet-name><url-pattern>/servletDemo</url-pattern></servlet-mapping>--><!-- <!–/開頭+通配符的方式–><servlet><servlet-name>servletDemo</servlet-name><servlet-class>com.example.demo.ServletDemo</servlet-class></servlet><servlet-mapping><servlet-name>servletDemo</servlet-name><url-pattern>/servlet/*</url-pattern></servlet-mapping>--><!--通配符+固定格式結(jié)尾 結(jié)尾寫什么就寫什么,開心就好--><servlet><servlet-name>servletDemo</servlet-name><servlet-class>com.example.demo.ServletDemo</servlet-class></servlet><servlet-mapping><servlet-name>servletDemo</servlet-name><url-pattern>*.itzhuzhu</url-pattern></servlet-mapping> </web-app>實(shí)現(xiàn)類:
public class ServletDemo extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 定義一個(gè)商品金額int money = 1000;// 獲取訪問路徑String uri = req.getRequestURI();// public int lastIndexOf(int ch): 返回指定字符在此字符串中最后一次出現(xiàn)處的索引,如果此字符串中沒有這樣的字符,則返回 -1。uri = uri.substring(uri.lastIndexOf("/"));// 條件判斷if ("/vip".equals(uri)) {System.out.println("原價(jià):" + money + "尊敬的Vip您的折后價(jià)是:" + money * 0.8);} else if ("/svip".equals(uri)) {System.out.println("原價(jià):" + money + "尊敬的Sip您的折后價(jià)是:" + money * 0.1);} else {System.out.println("會(huì)員都不開還想打折?打骨折");}}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);} }Servlet創(chuàng)建時(shí)機(jī):
第一種:服務(wù)器加載時(shí)創(chuàng)建
優(yōu)勢:
在服務(wù)器啟動(dòng)時(shí),就把需要的對象都創(chuàng)建完成了,從而在使用的時(shí)候減少了創(chuàng)建對象的時(shí)間,提高了首次執(zhí)行的效率。
弊端:
因?yàn)樵趹?yīng)用加載時(shí)就創(chuàng)建了Servlet對象,因此,導(dǎo)致內(nèi)存中充斥著大量用不上的Servlet對象,造成了內(nèi)存的浪費(fèi)。
第二種:第一次訪問時(shí)創(chuàng)建
優(yōu)勢:
就是減少了對服務(wù)器內(nèi)存的浪費(fèi),因?yàn)槟切┮恢睕]有被訪問過的Servlet對象都沒有創(chuàng)建,因此也提高了服務(wù)器的啟動(dòng)時(shí)間。
弊端:
如果有一些要在應(yīng)用加載時(shí)就做的初始化操作,它都沒法完成,從而要考慮其他技術(shù)實(shí)現(xiàn)。
修改創(chuàng)建時(shí)機(jī):在標(biāo)簽中添加標(biāo)簽
標(biāo)簽里的數(shù)字越小優(yōu)先級(jí)越高,正整數(shù)代表服務(wù)器加載時(shí)創(chuàng)建,負(fù)數(shù)或不寫代表第一次訪問的時(shí)候創(chuàng)建
<servlet><servlet-name>servletDemo</servlet-name><servlet-class>com.example.demo.ServletDemo</servlet-class><!--數(shù)字越小越高,負(fù)數(shù)或者不寫就是第一次訪問的時(shí)候創(chuàng)建--><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>servletDemo</servlet-name><url-pattern>/servletDemo</url-pattern></servlet-mapping>默認(rèn)Servlet:
默認(rèn)Servlet是由服務(wù)器提供的一個(gè)Servlet,它配置在Tomcat的conf目錄下web.xml中。它的映射路徑是<url-pattern>/<url-pattern>,在發(fā)送請求時(shí),首先會(huì)在應(yīng)用中的web.xml中查找映射配置,找到就執(zhí)行。找不到對應(yīng)的Servlet路徑時(shí),就去找默認(rèn)的Servlet,由默認(rèn)Servlet處理。
ServletConfig:
ServletConfig是Servlet的配置參數(shù)對象,在Servlet規(guī)范中,允許為每個(gè)Servlet都提供一些初始化配置。所以,每個(gè)Servlet都一個(gè)自己的ServletConfig。它的作用是在Servlet初始化期間,把一些配置信息傳遞給Servlet。比如servlet是個(gè)孩子,ServletConfig就是保姆
生命周期:
由于它是在初始化階段讀取了web.xml中為Servlet準(zhǔn)備的初始化配置,并把配置信息傳遞給Servlet,所以生命周期與Servlet相同。需要注意的是,如果Servlet配置了1,那么ServletConfig也會(huì)在應(yīng)用加載時(shí)創(chuàng)建。
配置ServletConfig:
在<servlet>標(biāo)簽中,通過<init-param>標(biāo)簽配置,有兩個(gè)子標(biāo)簽
<param-name>:代表初始化參數(shù)的key
<param-value>:代表初始化參數(shù)的value
ServletConfig方法:
| String | getInitParameter(String name) | 根據(jù)參數(shù)名稱獲取參數(shù)的值 |
| Enumeration | getInitParameterNames() | 獲取所有參數(shù)名稱的枚舉 |
| String | getServletName | 獲取Servlet的名稱 |
| SerlvetContext | getServletContext | 獲取ServletContext對象 |
演示:
配置信息:
<servlet><servlet-name>servletDemo05</servlet-name><servlet-class>com.example.demo.ServletDemo05</servlet-class><!--配置ServletConfig,是以鍵值對的形式存在的--><init-param><param-name>itz</param-name><param-value>itzhuzhu</param-value></init-param></servlet><servlet-mapping><servlet-name>servletDemo05</servlet-name><url-pattern>/servletDemo05</url-pattern></servlet-mapping>實(shí)現(xiàn)類:
public class servletDemo04 extends HttpServlet {// 聲明ServletConfigprivate ServletConfig config;// 因?yàn)镾ervletConfig是在初始化期間傳遞信息,所以要在init方法里去獲取@Overridepublic void init(ServletConfig config) throws ServletException {// 通過init方法,對ServletConfig對象賦值this.config = config;}@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// getInitParameter(String name):根據(jù)key獲取valueString encodingValue = config.getInitParameter("encoding");System.out.println(encodingValue);// getInitParameterNames():獲取所有keyEnumeration<String> keys = config.getInitParameterNames();while (keys.hasMoreElements()) {// 獲取每一個(gè)keyString key = keys.nextElement();// 根據(jù)key獲取valueString value = config.getInitParameter(key);System.out.println(key + " : " + value);}// getServletName 獲取Servlet的名稱String servletName = config.getServletName();System.out.println(servletName);// getServletContext 獲取ServletContext對象ServletContext servletContext = config.getServletContext();System.out.println(servletContext);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);} }ServletContext:
ServletContext對象,它是應(yīng)用上下文對象。每一個(gè)應(yīng)用有且只有一個(gè)ServletContext對象。
作用:
它可以配置和獲取應(yīng)用的全局初始化參數(shù),實(shí)現(xiàn)所有Servlet之間的數(shù)據(jù)共享。
生命周期:
- 出生: 應(yīng)用一加載,該對象就被創(chuàng)建出來了。一個(gè)應(yīng)用只有一個(gè)實(shí)例對象。(Servlet和ServletContext都-是單例的)
- 活著:只要應(yīng)用一直提供服務(wù),對象就一直存在。
- 死亡:應(yīng)用被卸載(或者服務(wù)器掛了),對象死亡。
域?qū)ο蟾拍?#xff1a;
- 域?qū)ο?#xff1a;指的是對象有作用域(作用范圍)
- 域?qū)ο蟮淖饔?#xff1a;域?qū)ο罂梢詫?shí)現(xiàn)數(shù)據(jù)共享。
- 不同作用范圍的域?qū)ο?#xff0c;共享數(shù)據(jù)的能力不一樣。在Servlet規(guī)范中,一共有4個(gè)域?qū)ο蟆ervletContext就是其中一個(gè)。也是web應(yīng)用中最大的作用域,叫application域。每個(gè)應(yīng)用只有一個(gè)application域(應(yīng)用域),它可以實(shí)現(xiàn)整個(gè)應(yīng)用間的數(shù)據(jù)共享功能。
ServletContext配置:
ServletContext被稱之為應(yīng)用上下文對象,所以它的配置是針對整個(gè)應(yīng)用的配置,而非某個(gè)特定Servlet的配置。它的配置被稱為應(yīng)用的初始化參數(shù)配置。
配置的方式,需要在標(biāo)簽中使用來配置初始化參數(shù)
<param-name>:全局初始化參數(shù)的key
<param-value>:全局初始化參數(shù)的value
常用方法:
| String | getInitParameter(String name) | 根據(jù)名稱獲取全局配置的參數(shù) |
| String | getContextPath() | 獲取當(dāng)前應(yīng)用訪問的虛擬目錄 |
| String | getRealPath | 根據(jù)虛擬目錄獲取應(yīng)用部署的磁盤絕對路徑 |
應(yīng)用域常用方法:
| void | setAttribute(String name,Object value) | 向應(yīng)用域?qū)ο笾写鎯?chǔ)數(shù)據(jù) |
| Object | getAttribute(String name) | 通過名稱獲取應(yīng)用域?qū)ο笾械臄?shù)組 |
| void | removeAttribute(String name) | 通過名稱移除應(yīng)用域?qū)ο笾械臄?shù)據(jù) |
配置文件:
<!--因?yàn)閟ervletContext它不屬于某一個(gè)servlet,它是配置全局的,所以不能寫在servlet里--><context-param><param-name>desc</param-name><param-value>This is Ser vletContextDemo</param-value></context-param><servlet><servlet-name>servletContextDemo</servlet-name><servlet-class>com.example.demo.ServletContextDemo</servlet-class></servlet><servlet-mapping><servlet-name>servletContextDemo</servlet-name><url-pattern>/servletContextDemo</url-pattern></servlet-mapping>實(shí)現(xiàn)類:
public class ServletContextDemo extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 獲取ServletContext對象 , GenericServlet底層已經(jīng)實(shí)現(xiàn)了getInitParameter所以可以直接調(diào)用 ServletConfig sc = this.getServletConfig();ServletContext context = getServletContext();//獲取全局配置參數(shù)的descString value = context.getInitParameter("desc");System.out.println(value);//獲取應(yīng)用的訪問虛擬目錄String contextPath = context.getContextPath();System.out.println(contextPath);//根據(jù)虛擬目錄獲取應(yīng)用部署的磁盤絕對路徑String realPath = context.getRealPath("/");System.out.println(realPath);// 在src、wabapp、webinf創(chuàng)建三個(gè)文件獲取路徑//獲取a.txt文件的絕對路徑String a = context.getRealPath("/WEB-INF/classes/a.txt");System.out.println(a);//獲取b.txt文件的絕對路徑String b = context.getRealPath("/b.txt");System.out.println(b);String c = context.getRealPath("/WEB-INF/c.txt");System.out.println(c);//向域?qū)ο笾写鎯?chǔ)數(shù)據(jù)context.setAttribute("username", "itzhuzhu");//移除域?qū)ο笾衭sername的數(shù)據(jù),刪除了再訪問就變成null了context.removeAttribute("username");}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);} }獲取共享數(shù)據(jù):
public class ServletDemo05 extends HttpServlet {// 聲明ServletConfigprivate ServletConfig config;// 因?yàn)镾ervletConfig是在初始化期間傳遞信息,所以要在init方法里去獲取@Overridepublic void init(ServletConfig config) throws ServletException {// 通過init方法,對ServletConfig對象賦值this.config = config;}@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// getServletContext 獲取ServletContext對象ServletContext servletContext = config.getServletContext();System.out.println(servletContext);// getAttribute(String name) 通過名稱獲取應(yīng)用域?qū)ο笾械臄?shù)組Object username = servletContext.getAttribute("username");System.out.println(username);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);} }Request方法詳解:
總結(jié)
以上是生活随笔為你收集整理的Servlet方法详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring AOP切入点与通知XML类
- 下一篇: java去掉图片边框颜色_sharp 去