Servlet就是一段運(yùn)行在Web容器里的Java程序盼樟。(自己不能獨(dú)立運(yùn)行)?
Sun公司是如何實(shí)現(xiàn)這件事情的呢渤昌??
1) 首先Sun公司編寫了一系列Class愁铺,比如javax.servlet.http.HttpServlet余素,你編寫的Servlet需要利用或繼承它 們奔穿。這一系列Class都放在servlet-api.jar這個文件當(dāng)中镜沽。這樣底層和復(fù)雜機(jī)器環(huán)境比如網(wǎng)絡(luò)或Tomcat(Apache公司依據(jù)sun公司J2EE(Enterprise<企業(yè)> Edition)規(guī)范開發(fā))打交道的工作,Servlet 編寫者就不用考慮了贱田!servlet只需要考慮一段時(shí)期(Session)的相關(guān)的請求(Request)響應(yīng)(Response)系列就可以了缅茉。客戶端 把它想要發(fā)給服務(wù)器的數(shù)據(jù)男摧,存放在Request當(dāng)中蔬墩。而服務(wù)器把它想給客戶端的數(shù)據(jù),存在Response當(dāng)中耗拓。如果跨越幾個Request- Response的交互拇颅。數(shù)據(jù)就可以放在Session當(dāng)中。
Tomcat的部署war包里主要是class文件和Web.xml乔询,以及頁面樟插。
1.瀏覽器和Servlet的互傳參數(shù):
doGet(HttpServletRequest request, HttpServletResponse response)。
request當(dāng)中包含客戶端送到服務(wù)器的數(shù)據(jù)竿刁。response包含服務(wù)器送回給客戶端的數(shù)據(jù)黄锤。
當(dāng)用戶在瀏覽器輸入Servlet地址,按回車以后食拜,通過網(wǎng)絡(luò)鸵熟,Tomcat就 會運(yùn)行用戶這個Servlet的doGet方法,而且傳入兩個參數(shù)负甸。一個就是代表從客戶端來的request流强。另外一個就是代表從服務(wù)器去客戶端的 resonse痹届。
response有個buffer,flushBuffer()會強(qiáng)行把Buffer的 內(nèi)容寫到客戶端瀏覽器.
public class ServletHello1 extends HttpServlet {
??? protected void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
??????? response.setContentType("text/html; charset=GBK");
??????? PrintWriter out = response.getWriter();
??????? out.println("<html>");
??????? out.println("<head><title>Servlet1</title></head>");
??????? out.println("<body bgcolor=\"#ff0000\">");
??????? out.println("<p><H1>我們The servlet </H1></p>");
??????? out.println("</body></html>");??? }
}
2打月,HttpServlet的Service方法短纵。它的功能就是調(diào)用與HTTP請求的方法相對應(yīng)的do功能。例如僵控,如果HTTP請求方法為GET香到,則調(diào)用doGet() 。這樣作為Servlet編寫者的你报破,只需覆蓋doGet方法悠就。這也是我們迄今為止的做法。
3,Servlet的生命周期
servlet的生命周期有三個:
1)初始化時(shí)期
在啟動Tomcat后充易,客戶機(jī)首次訪問Servlet時(shí)梗脾,tomcat裝入和實(shí)例化Servlet,僅執(zhí)行一次init()方法盹靴。
無論有多少客戶機(jī)訪問 Servlet炸茧,都不會重復(fù)執(zhí)行init()。這里通常進(jìn)行一些初始化的操作稿静,如數(shù)據(jù)庫的連接梭冠。init()方法不能反復(fù)調(diào)用,一旦調(diào)用就是重裝載 servlet改备。直到服務(wù)器調(diào)用destroy方法卸載servlet后才能再調(diào)用控漠。
2)Servlet的執(zhí)行時(shí)期
在服務(wù)器裝載初始化servlet后,servlet就能夠無限循環(huán)往復(fù)的處理客戶端的請求悬钳。
在前面的例子中盐捷,我們用doXXX方法來處理每個客戶的請求,且發(fā)回相應(yīng)的響應(yīng)默勾。
3)Servlet結(jié)束時(shí)期
Servlets一直運(yùn)行到他們被服務(wù)器卸載碉渡。
比如,在eclipse的情況下母剥,當(dāng)我們點(diǎn)擊服務(wù)器窗口的紅色按鈕時(shí)滞诺,就關(guān)停Tomcat,這時(shí) Servlet的destroy方法就會被tomcat調(diào)用媳搪。通常铭段,大家在destroy方法里收回在init()方法中初始化的資源骤宣,如關(guān)閉數(shù)據(jù)庫的連 接等秦爆。
4,session的用法
如何跨越幾次請求響應(yīng)之間傳遞參數(shù)呢?
Sun公司為我 們提供了HttpSession這個接口憔披。
HttpSession session = request.getSession();
通過這句話等限,你可以得到一個與你的瀏覽器綁定的session對象爸吮,存在Tomcat里。這 個session對象只認(rèn)你這個瀏覽器望门,之后只要是你這個瀏覽器發(fā)出的請求形娇,無論跨越多少次請求響應(yīng),這個session對象就對它開放筹误,其它瀏覽器不能 訪問桐早。通過session.setAttribute()可以往session里面存值,session.getAttribute可以取值厨剪。
問題是 session是如何識別你的瀏覽器呢哄酝?靠Cookie或者URL改寫:如果瀏覽器支持Cookie,則使用Cookie祷膳;如果瀏覽器不支持Cookie或者Cookie功能被關(guān)閉陶衅,則自動使用URL改寫方法。拿cookie來說(通持背浚客戶很少見關(guān)閉cookie搀军,即使你關(guān)了,我也可以發(fā)現(xiàn)勇皇,之后提醒你打開或編程序重寫URL)罩句,服務(wù)器往客戶端寫東西時(shí),cookie會帶上sessionid敛摘。當(dāng)客戶端再次訪問服務(wù)器時(shí)的止,同一path下,會自動在html請求頭中帶上cookie信息,服務(wù)器可以在_COOKIE域中得取到想要的sessionid着撩。????
注意:跨應(yīng)用的Session:Session取不出來诅福。可以考慮用文件拖叙、數(shù)據(jù)庫氓润,URL傳值、隱藏表單傳遞session id等實(shí)現(xiàn)薯鳍。
5?咖气,從web.xml中獲取參數(shù)
1)用init-param獲取
在web.xml中加入:
??? <servlet>
??? ??? <servlet-name>ServletHello1</servlet-name>
??? ??? <servlet-class>com.ServletHello1</servlet-class>
??? ??? ???? <init-param>
???????????????? <param-name>zhangsan</param-name>
???????????????? <param-value>1000</param-value>
???????????? </init-param>
??? </servlet>
??? <servlet-mapping>
??? ??? <servlet-name>ServletHello1</servlet-name>
??? ??? <url-pattern>/MarkToWinServletHello1</url-pattern>
??? </servlet-mapping>
public class ServletHello1 extends HttpServlet {
??? protected void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
??? ??? String salary = getInitParameter("zhangsan");
??? ??? System.out.println("salary is "+salary);
??? }
2)用ServletConfig從init-param獲取
獲取init-param同getInitParameter
public class ServletHello1 extends HttpServlet {
??? protected void doGet(HttpServletRequest request, HttpServletResponse response)
??? ??? ??? throws ServletException, IOException {
??? ??? ServletConfig c = getServletConfig();
??? ??? System.out.println(c.getServletName()+c.getInitParameter("zhangsan"));
??? }
}
3)從context-param獲取
用context-param存放的參數(shù),整個web應(yīng)用中的任何servlet挖滤,jsp都可以獲得崩溪。
(因?yàn)閏ontext參數(shù)不屬于任何特定的servlet,屬于整個web應(yīng)用):
????<context-param>
??????? <param-name>zhangsan</param-name>
??????? <param-value>1000</param-value>
??? </context-param>
??? protected void doGet(HttpServletRequest request, HttpServletResponse response)
??? ??? ??? throws ServletException, IOException {
??????? ServletContext servletContext = getServletContext();
??????? String jd =? servletContext.getInitParameter("zhangsan");
??? ??? System.out.println(jd);
??? }
4)從env-entry獲取
用env-entry存放的參數(shù)斩松,整個web應(yīng)用中的任何servlet伶唯,jsp都可以獲得。和context-param相比惧盹,env-entry存放的參數(shù)不止為String類型乳幸。下面的comp是component的意思瞪讼。
public void doGet(HttpServletRequest request, HttpServletResponse response)
??? ??? ??? throws ServletException, IOException {
??? ??? Context ctx;
??? ??? boolean isReady = false;
??? ??? try {
??? ??? ??? ctx = new InitialContext();
??? ??? ??? Boolean b = (Boolean) ctx.lookup("java:comp/env/isReady");
??? ??? ??? isReady = b.booleanValue();
??? ??? } catch (NamingException e) {
??? ??? ??? e.printStackTrace();
??? ??? }
??? ??? System.out.println("" + isReady);
??? }
<env-entry>
???? <env-entry-name>isReady</env-entry-name>
???? <env-entry-type>java.lang.Boolean</env-entry-type>
???? <env-entry-value>true</env-entry-value>
</env-entry>
6,?Servlet中的跳轉(zhuǎn)問題
1)用RequestDispatcher跳轉(zhuǎn)
?javax.servlet.RequestDispatcher是Sun公司編寫的一個Interface粹断,
顧名思義符欠,它可以把用戶請求"a資源"的request派遣(dispatch)到"b資源"上,從而實(shí)現(xiàn)跳轉(zhuǎn)瓶埋。(本來人家要訪問'a資源"希柿,你的程序卻讓人家自動的跳轉(zhuǎn)到"b資源"上。)
注意:RequestDispatcher有兩種形式:這兩種形式都能達(dá)到跳轉(zhuǎn)的目的养筒。
一種是ServletRequest.getRequestDispatcher(String url)狡汉。
一種是ServletContext.getRequestDispatcher(String url)。
但正常來講闽颇,二者都只能訪問同一web應(yīng)用的資源盾戴。見下面理論論述和實(shí)驗(yàn)。
注意以下兩者的而區(qū)別:
ServletContext.getRequestDispatcher(String
url)中的url只能使用絕對路徑兵多;
而ServletRequest.getRequestDispatcher(String
url)中的url可以使用相對路徑(兩個資源在同一個目錄下尖啡,所以省去路徑),也可以絕對路徑剩膘。假如你寫成相對路徑時(shí)衅斩,比如
request.getRequestDispatcher("add").forward(request, response);
系統(tǒng)會在同一目錄下找add,見后面的例子怠褐。
但是假如你寫成request.getRequestDispatcher(/WebModule1/jsp1.jsp).forward
(request, response); 系統(tǒng)也會傻傻的變成:request.getRequestDispatcher(http://localhost:
8080/WebModule1/WebModule1/jsp1.jsp).forward(request, response);
當(dāng)然你更不要寫成:request.getRequestDispatcher(http://localhost:
8083/WebModule1/jsp1.jsp).forward(request, response).道理是一樣的畏梆。
public class DeleteCookie extends HttpServlet {
??? protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
??????? request.setAttribute("requestkey","requstvalue1");
??????? getServletContext().setAttribute("ServletContextKey","ServletContextValue");
/*下面任意一種方法都能正確執(zhí)行。*/????????
??????? request.getRequestDispatcher("/Cookie/AddCookie").forward(request, response);
?//?????? request.getRequestDispatcher("AddCookie").forward(request, response);
?//?????? request.getRequestDispatcher("/WEB-INF/1.html").forward(request, response);
?//?????? request.getRequestDispatcher("/Hello/MarkToWinServletHello1").forward(request, response);
?//?????? getServletContext().getRequestDispatcher("/Hello/MarkToWinServletHello1").forward(request, response);
?// ????? getServletContext().getRequestDispatcher("/WEB-INF/1.html").forward(request, response);
/*下面的寫法錯誤奈懒,找不到AddCookie*/
//????? request.getRequestDispatcher("/AddCookie").forward(request, response);
// getServletContext().getRequestDispatcher("http://localhost:8080/ServletHello/Hello/MarkToWinServletHello1").forward(request, response);
??? }
}
2)用setHeader("refresh"...跳轉(zhuǎn)
使用response對象的setHeader()方法可以實(shí)現(xiàn)在某個時(shí)間點(diǎn)跳轉(zhuǎn)到某個頁面的作用奠涌。比如response.setHeader("refresh",60);可以實(shí)現(xiàn)六十秒以后,又一次訪問當(dāng)前頁面磷杏。而response.setHeader("refresh","3;URL=http://localhost:8080/ServletHello/cookie.html");?實(shí)現(xiàn)3秒后訪問新頁面:http://localhost:8080/ServletHello/cookie.html溜畅。
3)用sendRedirect跳轉(zhuǎn)
response的方法:void sendRedirect(String url),將頁面重定向到指定的URL地址上极祸。
?protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
??????? response.sendRedirect("http://localhost:8080/ServletHello/cookie.html");
??? }
4)sendRedirect和RequestDispatcher的區(qū)別
response.sendRedirect()與request.getRequestDispatcher().forward()區(qū)別:response.sendRedirect(url)是先回到客戶端慈格,再重新請求url,和過去的請求沒關(guān)系遥金≡±Γ可以訪問任何地方。瀏覽器的地址欄也變成了新的url稿械。request.getRequestDispatcher().forward()就干脆沒回到客戶端选泻,就一直在服務(wù)器里,從本個web應(yīng)用的一個資源(servlet溜哮,jsp滔金,或html)跳到另一個資源色解。(所以不能隨便訪問什么地方)茂嗓。而且瀏覽器地址欄沒有變餐茵。同時(shí)可以用request.setAttribute("requestkey","requstvalue1");來傳遞參數(shù)。?
RequestDispatcher會block述吸,因?yàn)橥诜?wù)器端忿族。當(dāng)程序需要從資源1跳到資源2時(shí),資源1會等資源2運(yùn)行完蝌矛,回來以后道批,再繼續(xù)執(zhí)行下面沒執(zhí)行的部分。所謂的block入撒。
7隆豹,Servlet的其他相關(guān)問題
servlet與JDBC、servlet與Cookie茅逮、Servlet與Image
html的Header當(dāng)中有一個叫做Referer的鍵,用于追溯