一? servlet概述
狹義的Servlet指javax.servlet包中的一個(gè)接口壁顶,而廣義的Servlet則是指實(shí)現(xiàn)了這個(gè)接口的類若专。一個(gè)Servlet應(yīng)用有一個(gè)或多個(gè)Servlet程序调衰。
Jsp是在傳統(tǒng)的HTML代碼中插入java程序段(Scriplet)與jsp標(biāo)記(tag).
servlet應(yīng)用需要在servlet容器中運(yùn)行自阱,典型容器如Jetty沛豌、Tomcat 運(yùn)行servlet應(yīng)用。在一個(gè)容器中可以同時(shí)運(yùn)行Servlet與靜態(tài)內(nèi)容叫确。
servlet API 主要由以下幾個(gè)工具包:
1.javax.Servlet? 其中包含Servlet和Servlet容器之間契約的類和接口
2.javax.Servlet.http 其中包含定義HTTP Servlet(采用了HTTP協(xié)議的Servlet)和Servlet容器之間契約的類和接口竹勉。
3.avax.servlet.annotation次乓,其中包含標(biāo)注Servlet、Filter照瘾、Listener的標(biāo)注析命。它還為被標(biāo)注元件定義元數(shù)據(jù)逃默。
javax.servlet.descriptor完域,其中包含提供程序化登錄web應(yīng)用程序的配置信息的類型吟税。
二? Servlet接口
其中的方法包括:
? ? ? ? 1.init(ServletConfig config)? 當(dāng)該Servlet被一次請(qǐng)求時(shí),調(diào)用該方法肖抱,此后不再調(diào)用意述。參數(shù)傳入的是Servlet的配置信息
? ? ? ? 2.service(ServletRequest req,ServletResponse res) 每當(dāng)請(qǐng)求Servlet時(shí)吮蛹,Servlet容器就會(huì)調(diào)用這個(gè)方法潮针。編寫代碼時(shí)每篷,假設(shè)Servlet要在這里? 被請(qǐng)求。第一次請(qǐng)求Servlet時(shí)带兜,Servlet容器調(diào)用init方法和Service方法。后續(xù)的請(qǐng)求將只調(diào)用Service方法刑巧。
? ? ? ? 3.destroy() 當(dāng)要銷毀Servlet時(shí),Servlet容器就會(huì)調(diào)用這個(gè)方法浑彰。當(dāng)要卸載應(yīng)用程序郭变,或者當(dāng)要關(guān)閉Servlet容器時(shí)涯保,就會(huì)發(fā)生這種情況夕春。一般會(huì)在這個(gè)方法中編寫清除代碼。
? ? ? 4. ServletConfig getServletConfig() 這個(gè)方法會(huì)返回由Servlet容器傳給init方法的ServletConfig
? ? ?5. String getServletInfo() 這個(gè)方法會(huì)返回Servlet的描述片排。
ServletRequest接口 封裝請(qǐng)求數(shù)據(jù)
1. Object getAttribute(String name)? 返回以name為名字的屬性的值率寡,如果不存在倚搬,返回null
2. Enumeration getAttributeNames(); 返回請(qǐng)求中所有可用的屬性的名字潭枣。返回一個(gè)枚舉集合
3. void removeAttribute(String name); 移除請(qǐng)求中名字為name的屬性
4. void setAttribute(String key,Object val); 在請(qǐng)求中保存一個(gè)鍵值對(duì)盆犁。
5. getCharacterEncoding() 返回請(qǐng)求正文使用的字符編碼的名字
6. int getContentLength() 以字節(jié)為單位,返回請(qǐng)求正文的長(zhǎng)度醋奠。
7. String getContentType() 返回正文的MIME類型
8. ServletInputStream getInputStream()
9. BufferedReader getReader()
10.String getLocalAddr() 返回接收到請(qǐng)求的網(wǎng)絡(luò)接口的IP地址窜司。
11.String getRemoteAddr() 返回發(fā)送請(qǐng)求的客戶端或最后一個(gè)代理服務(wù)器的IP地址
12. String getRemoteHost() 返回發(fā)送請(qǐng)求的客戶端或者最后一個(gè)代理服務(wù)器的完整限定名
13. String getLocalName() 返回接收到請(qǐng)求的IP接口的主機(jī)名
14. int getLocalPort() 返回接收到請(qǐng)求的網(wǎng)絡(luò)接口的IP端口號(hào)
?15. int getRemotePort() 返回發(fā)送請(qǐng)求的客戶端或最后一個(gè)代理服務(wù)器的IP源端口塞祈。
16? String getParameter(String name) 返回請(qǐng)求中name參數(shù)的值议薪,如果name參數(shù)有多個(gè)值,該方法返回值列表中的第一個(gè)值产捞。如果請(qǐng)求中沒有找到該參數(shù)坯临,返回null
17 Enumeration getParameterNames() 返回請(qǐng)求中包含的所有的參數(shù)的名字恋昼。
18 String[] getParameterValues(String name); 返回請(qǐng)求中name參數(shù)所有的值
19 String getProtocal() 返回請(qǐng)求使用的協(xié)議的名字和版本 例如: HTTP/1.1
20. RequestDispatcher getRequestDispatcher(String path) 返回RequestDispather對(duì)象焰雕,作為path所定位的資源的封裝矩屁。
21. String getServerName()? 返回請(qǐng)求發(fā)送到服務(wù)器的主機(jī)名
?22 int getServerPort() 返回請(qǐng)求發(fā)送到服務(wù)器的端口號(hào)
23. setCharacterEncoding(String env) 覆蓋在請(qǐng)求正文中所使用的字符編碼的名字吝秕。(鏈接:http://www.reibang.com/p/d718a5f4a850)
ServletResponse接口,用來封裝響應(yīng)數(shù)據(jù)
flushBuffer()? ? ? ? ? ? ?強(qiáng)制把任何在緩存中的內(nèi)容發(fā)送到客戶端
int getBufferSize()? ? ? ? ? 返回實(shí)際用于響應(yīng)的緩存的大小容客,如果沒有使用緩存缩挑,這個(gè)方法返回0
String getCharacterEncoding() 返回響應(yīng)中發(fā)送的正文所使用的字符編碼(MIME字符集)
String getContentType()返回響應(yīng)中發(fā)送的正文所使用的MIME類型
ServletOutputStream getOutputStream()
PrintWriter getWriter()
boolean isCommitted()? ? ? 返回一個(gè)布爾值供置,指示是否已經(jīng)提交了響應(yīng)绽快。
void reset()? ? ? ? ? ? ? ? 清除在緩存中的任何數(shù)據(jù)坊罢,包括狀態(tài)代碼和消息報(bào)頭活孩。
void resetBuffer()? ? ? ? ? 清除在緩存中的響應(yīng)內(nèi)容,保留狀態(tài)代碼和消息包頭挎挖。
void setBufferSize(int size) 設(shè)置響應(yīng)正文的緩存大小蕉朵。
void setCharacterEncoding(String charset) 設(shè)置發(fā)送到客戶端的響應(yīng)的字符編碼
void setContentLength(int len) 設(shè)置內(nèi)容正文的長(zhǎng)度
void setContentType(String type)? 設(shè)置要發(fā)送到客戶端的響應(yīng)的內(nèi)容類型始衅。例如:"text/html;charset=UTF-8"
ServletConfig
Servlet容器使用ServletConfig對(duì)象在Servlet初始化期間向它傳遞配置信息汛闸,一個(gè)ServletConfig對(duì)象艺骂。
String getInitParameter(String name); 返回名字為name的初始化參數(shù)的值钳恕,初始化參數(shù)在web.xml配置文件中進(jìn)行配置忧额。
Enumeration getInitParameterNames()? 返回Servlet所有初始化參數(shù)的名字的枚舉集合。
ServletContext getServletContext() 返回Servlet上下文對(duì)象的引用类茂。
String getServletName() 返回Servlet實(shí)例的名字巩检,這個(gè)名字是web應(yīng)用程序的部署描述符中指定兢哭。
編寫一個(gè)Servlet實(shí)際上就是編寫一個(gè)實(shí)現(xiàn)了javax.servlet.Servlet接口的類丑搔。
GenericServlet
如果要編寫一個(gè)通用的Servlet啤月,只需要從GenericServlet繼承谎仲,并且實(shí)現(xiàn)抽象方法service();
String getInitParameter(String name)
Enumeration getInitParameterNames();
ServletContext getServletContext()
init(ServletConfig config)
HttpServlet
在絕大多數(shù)的網(wǎng)絡(luò)應(yīng)用中,都是客戶端通過HTTP協(xié)議去訪問服務(wù)器端的資源我們編寫的Servlet也主要是應(yīng)用于HTTP協(xié)議的請(qǐng)求和響應(yīng)杉武,為了快速開發(fā)應(yīng)用于HTTP協(xié)議的Servlet類辙售,sun公司在javax.servlet.http包中給我們提供了一個(gè)抽象類HttpServlet旦部,它繼承自GenericServlet類士八,用于創(chuàng)建適合WEB站點(diǎn)的HTTP Servlet
public void service(ServletRequest req,ServletResponse res);
protected void service(HttpServletRequest req,HttpServletResponse resp)
針對(duì)HTTP1.1定義的7種請(qǐng)求方法GET,POST,HEAD,PUT,DELETE,TRACE,OPTION,
HttpServlet提供了7個(gè)處理方法
doGet(HttpServletRequest req,HttpServletResponse resp)
doPost(HttpServletRequest req,HttpServletResponse resp)
......
當(dāng)容器接受到一個(gè)針對(duì)HttpServlet對(duì)象的請(qǐng)求時(shí),調(diào)用該對(duì)象中的方法順序如下:
調(diào)用公共的service()方法
在公共的service()方法中蝗茁,首先將參數(shù)類型轉(zhuǎn)換為HttpServletRequest和HttpServletResponse评甜,然后調(diào)用保護(hù)的service()方法忍坷,將轉(zhuǎn)換后的對(duì)象作為參數(shù)傳遞進(jìn)去
在保護(hù)的service方法中,首先調(diào)用HttpServletRequest對(duì)象的getMethod方法佩研,獲取HTTP請(qǐng)求方法的名稱旬薯,然后根據(jù)請(qǐng)求方法的類型绊序,調(diào)用相應(yīng)的doXxx()方法
HttpServletRequest
繼承自javax.servlet.servletRequest,在該接口中新增的方法如下:
String getContextPath() 返回請(qǐng)求URI中表示請(qǐng)求上下文的部分骤公,上下文路徑是請(qǐng)求URI的開始部分
Cookie[] getCookies() 返回客戶端在此次請(qǐng)求中發(fā)送的所有的Cookie對(duì)象
String getHeader(String name) 返回名字為name的請(qǐng)求報(bào)頭的值
Enumeration getHeaderNames() 返回此次請(qǐng)求中包含的所有的報(bào)頭名字的枚舉集合
Enumeration getHeaders(String name) 返回名字為name的請(qǐng)求報(bào)頭的所有值的枚舉集合
String getMethod() 返回此次請(qǐng)求所使用的HTTP方法的名字
String getServletPath() 返回請(qǐng)求URI中調(diào)用Servlet的部分
HttpSession getSession() 返回和此次請(qǐng)求相關(guān)聯(lián)的Session
HttpSession getSession(boolean create)? 返回此次請(qǐng)求相關(guān)聯(lián)的Session,如果沒有給客戶端分配Session,并且create參數(shù)為true,則創(chuàng)建一個(gè)新的Session,如果為false阶捆,此次請(qǐng)求沒有一個(gè)有效的HttpSession,返回null
HttpServletResponse
該接口繼承ServletResponse,新增的方法入下
addCookie(Cookie cookie)
addHeader(String name,String value);
boolean containsHeader(String name)
encodeRedirectURL(String url)?
使用SessionID 對(duì)于重定向的url編碼,以便用于sendRedirect()方法中
encodeURL(String url)? ? ? ? ? ? 使用SessionID 指定的url編碼
sendRedirect(String location)? ? ? 發(fā)送一個(gè)臨時(shí)的重定向響應(yīng)到客戶端朴上,讓客戶端訪問新的url
(鏈接:http://www.reibang.com/p/d718a5f4a850)
ServletConfig接口
當(dāng)Servlet容器初始化Servlet時(shí)痪宰,Servlet容器會(huì)給Servlet的init方法傳入一個(gè)ServletConfig對(duì)象跷坝。ServletConfig封裝了通過@WebServlet注解或者部署描述符(關(guān)于@WebServlet注解和部署描述符的內(nèi)容會(huì)在后面的文章中講到)傳給Servlet的配置信息柴钻。這樣傳入的每一條信息就叫一個(gè)初始參數(shù)贴届。一個(gè)初始參數(shù)有key和value兩個(gè)元素毫蚓∥羯疲可以使用getServletConfig來獲取傳遞給Servlet的ServletConfig君仆。
為了從Servlet內(nèi)部獲取到初始參數(shù)的值返咱,要在Servlet容器傳給Servlet的init方法的ServletConfig中調(diào)用getInitParameter方法咖摹。ServletConfig還提供了另一個(gè)很有用的方法:getServletContext萤晴。利用這個(gè)方法可以從Servlet內(nèi)部獲取ServletContext。
(鏈接:http://www.reibang.com/p/136fb6bf9ed6)
4.ServletContext接口
ServletContext表示Servlet應(yīng)用程序的上下文嗦枢,且每一個(gè)應(yīng)用程序只有一個(gè)上下文。在將一個(gè)應(yīng)用程序同時(shí)部署到多個(gè)容器的分布式環(huán)境中择葡,每臺(tái)Java虛擬機(jī)上的Web應(yīng)用都會(huì)有一個(gè)ServletContext對(duì)象敏储。
通過在ServletConfig中調(diào)用getServletContext方法已添,可以獲得ServletContext。有了ServletContext畦幢,就可以共享從應(yīng)用程序中的所有資料處訪問到的信息宇葱,并且可以動(dòng)態(tài)注冊(cè)Web對(duì)象黍瞧。ServletContext將對(duì)象保存在一個(gè)內(nèi)部Map中印颤。保存在ServletContext中的對(duì)象被稱作屬性年局。
鏈接:http://www.reibang.com/p/136fb6bf9ed6
Cookie
Cookie是由Web服務(wù)器保存在用戶瀏覽器上的小文本文件被碗,它可以包含有關(guān)用戶的信息锐朴。無論何時(shí)用戶鏈接到服務(wù)器焚志,Web站點(diǎn)都可以訪問cookie信息。Cookie作為HTTP? header的一部分壶谒,其傳輸由HTTP協(xié)議控制汗菜。此外陨界,你還可以控制cookie的有效時(shí)間菌瘪。
可以通過傳遞name和value兩個(gè)參數(shù)給Cookie類的構(gòu)造函數(shù)來創(chuàng)建一個(gè)cookie:
Cookie cookie = new Cookie(name, value);
創(chuàng)建完一個(gè)Cookie對(duì)象后,你可以使用setMaxAge方法設(shè)置maxAge屬性俏扩,這個(gè)屬性決定cookie何時(shí)過期糜工。
要將cookie發(fā)送到瀏覽器,需要調(diào)用HttpServletResponse的add方法录淡。
服務(wù)端若要讀取瀏覽器提交的cookie捌木,可以通過HttpServletRequest接口的getCookies方法,該方法返回一個(gè)Cookie數(shù)組赁咙,若沒有cookies則返回null钮莲。你需要遍歷整個(gè)數(shù)組來查詢某個(gè)特定名稱的cookie。
目前彼水,還沒有通過名稱來獲取cookie的方法來幫助簡(jiǎn)化工作极舔。此外凤覆,也沒有一個(gè)直接的方法來刪除一個(gè)cookie,你只能創(chuàng)建一個(gè)同名的cookie拆魏,并將maxAge 屬性設(shè)置為0盯桦,并添加到HttpServletResponse接口中,就像下面這樣:
Cookie cookie = new Cookie("userName", "");
cookie.setMaxAge(0);
response.addCookie(cookie);
現(xiàn)在我們來編寫一個(gè)使用cookie來幫助統(tǒng)計(jì)用戶訪問某一頁面次數(shù)的Servlet:
package com.mc.hello;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class CookieDemoServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html");
PrintWriter out = response.getWriter();
int count = 0;
Cookie[] cookies = request.getCookies();
if(cookies != null) {
for (Cookie cookie : cookies) {
if(cookie.getName().equals("VisitCount")) {
count = Integer.parseInt(cookie.getValue());
break;
}
}
}
count++;
out.print("這是你第" + count + "次訪問這個(gè)頁面");
Cookie cookie = new Cookie("VisitCount", "" + count);
response.addCookie(cookie);
}
}
在web.xml中的配置:
cookiecom.mc.hello.CookieDemoServletcookie/cookie
在瀏覽器地址欄中輸入http://localhost:8080/HelloWorld/cookie即可看到如下頁面:
顯示訪問次數(shù)的頁面
每刷新一次這個(gè)頁面渤刃,訪問次數(shù)都會(huì)增加一次拥峦。但是當(dāng)我們關(guān)閉瀏覽器,然后再次打開瀏覽器卖子,并輸入這個(gè)頁面的URL時(shí)略号,頁面上顯示的訪問次數(shù)還是一次。這是因?yàn)槲覀儧]有設(shè)置cookie的過期時(shí)間洋闽,當(dāng)我們關(guān)閉瀏覽器的時(shí)候cookie就過期了玄柠。這里我們將這個(gè)cookie的過期時(shí)間設(shè)置為3分鐘:
Cookie cookie = new Cookie("VisitCount", "" + count);
cookie.setMaxAge(3 * 60);
response.addCookie(cookie);
這樣一來,3分鐘之內(nèi)诫舅,無論我們是否關(guān)閉瀏覽器羽利,cookie都不會(huì)過期。
Session 接口
Session是另一種記錄客戶狀態(tài)的機(jī)制刊懈,與Cookie將客戶狀態(tài)保存在客戶端瀏覽器中的形式不同这弧,Session將客戶狀態(tài)保存在服務(wù)器上娃闲。客戶端瀏覽器訪問服務(wù)器的時(shí)候匾浪,服務(wù)器把客戶端信息以某種形式記錄在服務(wù)器上畜吊。客戶端瀏覽器再次訪問時(shí)只需要從該Session中查找該客戶的狀態(tài)即可户矢。
HttpSession接口是Java對(duì)Session機(jī)制的實(shí)現(xiàn)規(guī)范玲献,它位于javax.servlet.http包中。
HttpSession對(duì)象在用戶第一次訪問網(wǎng)站的時(shí)候自動(dòng)被創(chuàng)建梯浪,你可以通過調(diào)用HttpServletRequest的getSession方法獲取該對(duì)象捌年。getSession有兩個(gè)重載方法:
HttpSession getSession()
HttpSession getSession(boolean create)
沒有參數(shù)的getSession方法會(huì)返回當(dāng)前的HttpSession,若當(dāng)前沒有挂洛,則創(chuàng)建一個(gè)返回礼预。getSession(false)返回當(dāng)前HttpSession,如當(dāng)前會(huì)話不存在虏劲,則返回null托酸。getSession(true)與沒有參數(shù)的getSession方法一致,也是返回當(dāng)前HttpSession柒巫,若當(dāng)前沒有励堡,則創(chuàng)建一個(gè)。
可以通過HttpSession的setAttribute方法將值放入HttpSession堡掏,該方法簽名如下:
void setAttribute(String name, Object value)
調(diào)用setAttribute方法時(shí)应结,若傳入的name參數(shù)此前已經(jīng)使用過,則會(huì)用新值覆蓋舊值泉唁。
通過調(diào)用HttpSession的getAttribute方法可以取回之前放入的對(duì)象鹅龄,該方法的簽名如下:
Object getAttribute(String name)
注意,所有保存在HttpSession的數(shù)據(jù)不會(huì)被發(fā)送到客戶端亭畜。
可以通過調(diào)用HttpSession的getId方法來讀取Session的ID扮休。Servlet容器為每個(gè)HttpSession生成唯一的標(biāo)識(shí),并為這個(gè)標(biāo)識(shí)創(chuàng)建一個(gè)名為JSESSIONID的cookie拴鸵。在后續(xù)的請(qǐng)求中玷坠,瀏覽器會(huì)將標(biāo)識(shí)提交給服務(wù)端,這樣服務(wù)器就可以識(shí)別該請(qǐng)求是由哪個(gè)用戶發(fā)起的宝踪。
下面是幾種使Session失效的方法:
在項(xiàng)目的部署描述文件中進(jìn)行設(shè)置:
1
該Session會(huì)在最后一次訪問一分鐘后失效
直接在應(yīng)用服務(wù)器中設(shè)置侨糟。如果是tomcat,可以在tomcat目錄下conf/web.xml中找到元素瘩燥,tomcat默認(rèn)設(shè)置是30分鐘秕重,只要修改這個(gè)值即可。
對(duì)HttpSession調(diào)用setMaxInactiveInterval方法來設(shè)定其超時(shí)時(shí)間:
void setMaxInactiveInterval(int seconds)
對(duì)HttpSession調(diào)用invalidate方法強(qiáng)制使會(huì)話過期厉膀。
下面我們編寫程序來創(chuàng)建一個(gè)Session:
package com.mc.hello;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@WebServlet(urlPatterns = { "/mysession" })
public class SessionDemoServlet extends HttpServlet {
private static final long serialVersionUID = 36L;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html");
PrintWriter out = response.getWriter();
HttpSession session = request.getSession();
session.setAttribute("name", "maconn");
Cookie[] cookies = request.getCookies();
if(cookies != null) {
for (Cookie cookie : cookies) {
out.print(cookie.getName() + " = " + session.getId());
}
}
else
out.print("no cookie");
}
}
第一次打開頁面溶耘,由于之前此時(shí)還不存在Session二拐,也就不存在JSESSIONID對(duì)應(yīng)的cookie,此時(shí)網(wǎng)頁上會(huì)顯示"no cookie"凳兵。再次刷新頁面百新,就會(huì)看到Session對(duì)應(yīng)的JSESSIONID。
鏈接:http://www.reibang.com/p/95849fa7be53