JSP的前身就是Servlet。Servlet就是在服務器端運行的一段小程序。一個Servlet就是一個Java類,而且能夠經過「請求-響應」編程模型來訪問的這個駐留在服務器內存的Servlet程序。php
Tomcat的容器分爲4個等級,Servlet的容器管理Context容器,一個Context對應一個Web工程。html
編寫一個Servlet程序大致上須要3個步驟:繼承HttpServlet-->重寫doGet()或者doPost()方法-->在web.xml中註冊Servlet。java
HttpServlet的繼承關係如圖:git
重寫doGet仍是doPost方法須要根據請求方式而定。web
1、編寫一個類繼承自HttpRequest並重寫doGet(或者doPost方法)在項目的src目錄下新建一個servlet.MyServlet.java編程
1 package servlet; 2 3 import java.io.IOException; 4 import java.io.PrintWriter; 5 6 import javax.servlet.ServletException; 7 import javax.servlet.http.HttpServlet; 8 import javax.servlet.http.HttpServletRequest; 9 import javax.servlet.http.HttpServletResponse; 10 11 /** 繼承自HttpServlet */ 12 public class HelloServlet extends HttpServlet { 13 14 /** 重寫doGet方法 */ 15 @Override 16 protected void doGet(HttpServletRequest request, HttpServletResponse response) 17 throws ServletException, IOException { 18 System.out.println("處理get請求。。。"); 19 PrintWriter out = response.getWriter(); 20 out.println("<b>HelloServlet</b>"); 21 } 22 23 /** 重寫doPost方法 */ 24 @Override 25 protected void doPost(HttpServletRequest request, HttpServletResponse response) 26 throws ServletException, IOException { 27 System.out.println("處理post請求。。。"); 28 PrintWriter out = response.getWriter(); 29 out.println("<b>HelloServlet</b>"); 30 } 31 32 }
2、在WEB-INF/web.xml中註冊剛剛新建的Servlet:小程序
1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app version="2.5" 3 xmlns="http://java.sun.com/xml/ns/javaee" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 6 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> 7 <display-name></display-name> 8 <welcome-file-list> 9 <welcome-file>index.jsp</welcome-file> 10 </welcome-file-list> 11 12 <!-- 註冊Servlet開始 --> 13 <servlet> 14 <servlet-name>HelloServlet</servlet-name> 15 <servlet-class>servlet.HelloServlet</servlet-class> 16 </servlet> 17 <servlet-mapping> 18 <servlet-name>HelloServlet</servlet-name> 19 <url-pattern>/servlet/HelloServlet</url-pattern> 20 </servlet-mapping> 21 <!-- 註冊Servlet結束 --> 22 23 </web-app>
其中servlet-name表示Servlet的名字,servlet-class要寫完成的類的定義(包名.類名),url-pattern表示Servlet的路徑。瀏覽器
在index.jsp中使用自定義的Servlet處理get和post請求。服務器
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 3 <html> 4 <head> 5 <title>手工編寫的第一個Servlet</title> 6 </head> 7 8 <body> 9 <h1>第一個Servlet小例子</h1><hr> 10 <a href="servlet/HelloServlet">get方式請求HelloServlet</a><br /><br /> 11 <form action="servlet/HelloServlet" method="post"> 12 <input type="submit" value="post方式請求HelloServlet" /> 13 </form> 14 </body> 15 </html>
發佈項目,運行結果:session
一個Servlet能夠在web.xml中配置多個映射,這樣就能夠在URL中使用不一樣的名字訪問相同的Servlet。以下所示:就可使用給人以假象——好像使用的是asp或者php或者更多的語言。
1 <!-- 註冊Servlet開始 --> 2 <servlet> 3 <servlet-name>HelloServlet</servlet-name> 4 <servlet-class>servlet.HelloServlet</servlet-class> 5 </servlet> 6 <!-- 一個Servlet能夠配置多個映射,向下面這樣配置就能夠有多種方式訪問Servlet了 --> 7 <servlet-mapping> 8 <servlet-name>HelloServlet</servlet-name> 9 <url-pattern>/servlet/HelloServlet</url-pattern> 10 </servlet-mapping> 11 <servlet-mapping> 12 <servlet-name>HelloServlet</servlet-name> 13 <url-pattern>/servlet/HelloServlet.asp</url-pattern> 14 </servlet-mapping> 15 <servlet-mapping> 16 <servlet-name>HelloServlet</servlet-name> 17 <url-pattern>/servlet/HelloServlet.php</url-pattern> 18 </servlet-mapping> 19 <servlet-mapping> 20 <servlet-name>HelloServlet</servlet-name> 21 <!-- *表示任意名稱都可 --> 22 <url-pattern>/servlet/hello/*</url-pattern> 23 </servlet-mapping> 24 <!-- 註冊Servlet結束 -->
1.src-->new Servlet。
2.重寫doGet()或者doPost()方法。
3.部署運行。
經過MyEclipse建立Servlet的時候它默認繼承自HttpServlet。默認勾選覆寫init()、destory()、doGet()和doPost()方法,而且自動向web.xml中註冊該Servlet。
能夠發現使用MyEclipse建立的Servlet它已經自動爲咱們生成了輸出的html模板,咱們只須要作不多的改動便可。
用戶點擊超連接向Servlet發送請求-->服務器在web.xml中的servlet-mapping尋找與該Servlet相對應的URL地址-->找到對應的Servlet名字-->根據Servlet的名字找到和該Servlet相關的處理類-->根據請求的方式不一樣肯定是調用doGet仍是doPost方法。
一個Servlet的生命週期大體分爲3個階段:
1.客戶端發送請求給服務器。
2.服務器開始接受,先判斷該請求的servlet實例是否存在,若是不存在先裝載一個servlet類並建立實例。
若是存在則直接調用該servlet的service方法,以後進行判斷是調用 doGet方法仍是doPost方法。
3.servlet建立實例後,調用init方法進行初始化。以後調用servce方法,判斷是調用doGet方法仍是doPost方法。
4.最後判斷服務器是否關閉,若是關閉則調用destroy方法。
下面這個例子展現了Servlet的生命週期:
首先是一個Servlet:TestServlet1
1 package servlet; 2 3 import java.io.IOException; 4 import java.io.PrintWriter; 5 6 import javax.servlet.ServletException; 7 import javax.servlet.http.HttpServlet; 8 import javax.servlet.http.HttpServletRequest; 9 import javax.servlet.http.HttpServletResponse; 10 11 public class TestServlet1 extends HttpServlet { 12 13 public TestServlet1() { 14 System.out.println("TestServlet1構造方法被執行!"); 15 } 16 17 public void destroy() { 18 System.out.println("TestServlet1銷燬方法被執行!"); 19 } 20 21 public void doGet(HttpServletRequest request, HttpServletResponse response) 22 throws ServletException, IOException { 23 24 System.out.println("TestServlet1的doGet方法被執行!"); 25 response.setContentType("text/html;charset=utf-8"); 26 PrintWriter out = response.getWriter(); 27 out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">"); 28 out.println("<HTML>"); 29 out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>"); 30 out.println(" <BODY>"); 31 out.println("<h1>你好我是TestServlet1</h1>"); 32 out.println(" </BODY>"); 33 out.println("</HTML>"); 34 out.flush(); 35 out.close(); 36 } 37 38 public void doPost(HttpServletRequest request, HttpServletResponse response) 39 throws ServletException, IOException { 40 System.out.println("TestServlet1的doPost方法被執行!"); 41 doGet(request, response);// 讓doPost與doGet執行相同的操做 42 } 43 44 public void init() throws ServletException { 45 System.out.println("TestServlet1的初始化方法被執行!"); 46 } 47 48 }
主頁index.jsp
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <% 3 String path = request.getContextPath(); 4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; 5 %> 6 7 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 8 <html> 9 <head> 10 <base href="<%=basePath%>"> 11 <title>Servlet的生命週期</title> 12 </head> 13 14 <body> 15 <h1>Servlet的生命週期</h1><hr /> 16 <a href = "servlet/TestServlet1">以get方式請求TestServlet1</a> 17 </body> 18 </html>
當服務器啓動以後咱們第一次訪問index.jsp的時候,構造方法,初始化方法和doGet()方法執行
當咱們再次請求該頁面的時候,只有doGet()方法被執行:
服務器關閉的時候銷燬方法執行。
在下列時刻Servlet容器會加載Servlet:
1.Servlet容器啓動時自動裝載某些Servlet,實現它只須要在web.xml文件中的<servlet></servlet>之間添加如下代碼:
<load-on-startup>1</load-on-startup>
其中,數字越小表示優先級越高。
例如:咱們在web.xml中設置TestServlet2的優先級爲1,而TestServlet1的優先級爲2,啓動和關閉Tomcat:
優先級高的先啓動也先關閉。
2.客戶端首次向某個Servlet發送請求。【例子詳見Servlet生命週期的那個例子】?//JSP自動會生成Servlet是爲了生成動態的HTML頁面流,以便瀏覽器引擎轉化成網頁,同時也是爲了與Servlet類進行交換數據。
//JSP—>servlet發送request時候須要寫入相應servlet的地址,{一種經過JSP文件裏使用跳轉標籤指明處理該JSP處理的servlet,或者在servlet中經過@WEBSERVLET進行注射}
web.xml文件只備註servlet,filter等等類的信息。可是這些不是給備註JSP與Servlet對應關係的信息。因此,jsp與servlet對應關係的地址須要在程序裏寫入,容器引擎我會根據地址自動處理。 //servlet—>jsp發送消息也須要寫入{或者經過request從新跳轉到一個JSP}
3.Servlet類被修改後,Tomcat容器會從新裝載Servlet。
Servlet被裝載後,Servlet容器會建立一個Servlet實例,而且調用Servlet的init()方法進行初始化,在Servlet的真個生命週期內init()方法只被調用一次。
用戶在reg.jsp中填寫註冊表單,使用post方式將數據發送到一個名稱爲servlet.RegServlet的Servlet處理【Servlet的doPost()方法】,Servlet將用戶信息封裝成一個Users對象存儲在session中,講請求轉發到userinfo.jsp。在userinfo.jsp中經過<jsp:useBean>指令從session中取出保存的用戶對象,經過<jsp:getPerproty>指令顯示用戶對象的各個字段。
相對路徑就是相對於當前頁面的路徑,絕對路徑就是相對於項目根目錄的路徑(絕對路徑須要使用到path變量)。
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <% 3 String path = request.getContextPath(); 4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; 5 %> 6 7 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 8 <html> 9 <head> 10 <base href="<%=basePath%>"> 11 <title>Servlet路徑跳轉</title> 12 </head> 13 14 <body> 15 <h1>Servlet路徑跳轉</h1> 16 <!-- 使用相對路徑訪問HelloServlet --> 17 <a href="servlet/HelloServlet">使用相對路徑訪問servlet</a><br /> 18 19 <!-- 使用絕對路徑訪問HelloServlet,使用path變量 --> 20 項目的根目錄:<%=path %><br /> 21 <a href="<%=path %>/servlet/HelloServlet">使用相對路徑訪問servlet</a><br /> 22 </body> 23 </html>
在web.xml中註冊的Servlet的路徑寫法是絕對路徑:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app version="2.5" 3 xmlns="http://java.sun.com/xml/ns/javaee" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 6 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> 7 <display-name></display-name> 8 9 <!-- Servlet註冊開始 --> 10 <servlet> 11 <description>This is the description of my J2EE component</description> 12 <display-name>This is the display name of my J2EE component</display-name> 13 <servlet-name>HelloServlet</servlet-name> 14 <servlet-class>servlet.HelloServlet</servlet-class> 15 </servlet> 16 <servlet-mapping> 17 <servlet-name>HelloServlet</servlet-name> 18 <url-pattern>/servlet/HelloServlet</url-pattern><!-- Servlet的路徑是絕對路徑 --> 19 </servlet-mapping> 20 <!-- Servlet註冊結束 --> 21 22 <welcome-file-list> 23 <welcome-file>index.jsp</welcome-file> 24 </welcome-file-list> 25 </web-app>
index.jsp中有一個連接指向servlet.TestServlet
<a href="servlet/TestServlet">訪問TestServlet,跳轉到Test.jsp</a>
servlet.TestServlet的doPost()和doGet()方法以下:
1 public void doGet(HttpServletRequest request, HttpServletResponse response) 2 throws ServletException, IOException { 3 4 doPost(request, response); 5 } 6 7 public void doPost(HttpServletRequest request, HttpServletResponse response) 8 throws ServletException, IOException { 9 // 1.使用請求重定向的方式跳轉到test.jsp 10 // response.sendRedirect("../test.jsp"); 11 // 也可使用絕對路徑的方式request.getContextPath 12 // response.sendRedirect(request.getContextPath()+"/test.jsp"); 13 14 // 2.使用服務器內部跳轉的方式 15 // request.getRequestDispatcher("../test.jsp").forward(request, response); 16 request.getRequestDispatcher("/test.jsp").forward(request, response); 17 }
在TestServlet中完成到網站根目錄下的跳轉有兩種方式重定向和服務器內部轉發,其中URL的寫法也有2種方式:絕對路徑和相對路徑。相對路徑使用..便可,而絕對路徑重定向須要依賴request.getContextPath()方法取得上下文環境,而服務器內部轉發中的斜線就表示項目的根目錄。
開發中通常在web.xml中配置Servlet的路徑爲表單所在路徑,這樣在表單中只須要書寫Servlet名字便可。在開發中應該儘可能避免../的寫法。
用戶名和密碼都是admin,登錄成功則使用服務器內部轉發到login_success.jsp,顯示登陸成功的用戶名。登陸失敗則重定向到login_failure.jsp。
把login.jsp中表單的action屬性改成須要處理登陸的Servlet
1 <form action="servlet/LoginServlet" method="post" name="loginForm"> 2 <!-- 代碼省略 --> 3 </form>
在web.xml中配置Servlet時,能夠配置一些初始化參數。而在Servlet中能夠經過ServletConfig接口提供的方法來取得這些參數。
1.首先在index.jsp中創建一條超連接指向servlet.GetInitParameterServlet。
<a href = "servlet/GetInitParameterServlet">獲取Servlet的初始化參數</a>
2.在web.xml中配置該Servlet的初始化參數:
3.在GetInitParameterServlet的init方法中使用this.getgetInitParameter(String name)方法得到初始化參數:
運行結果:
MVC旨在分離模型、視圖、控制。是分層思想的一種體現。
結構圖以下:
1.瀏覽器發送請求被控制器接收(Servlet)。
2.由控制器實例化一個模型層對象(JavaBean),模型層訪問EIS(企業信息系統,就是DB)。EIS將結果返回給JavaBean,JavaBean將結果返回給控制層Servlet。
3.控制層根據模型層返回的結果選擇合適的視圖給用戶呈現。
Model2實際上就是JSP(V)+Servlet(C)+JavaBean(M),是MVC設計思想。
JSP(View)+Servlet(Control)+ dao(Model)。
已有的商品實體類:
實現階段:建立購物車類-->編寫Servlet-->建立頁面層。
1.購物車類Cart的設計:
購物車有2個屬性,分別是購買商品的集合和商品的總價格。
購物車的方法有3個:添加商品、刪除商品、計算商品的總價格。
那麼問題來了,咱們應該使用何種集合來存儲用戶購買的商品?咱們可使用Map類型,鍵是商品對象,值是該種商品的數量。
實現以下:
接下來測試上面的購物車類:
直接在給Cart類中編寫main方法測試購物車類;
1 public static void main(String[] args) { 2 //建立2個商品對象 3 Items i1 = new Items(1, "沃特籃球鞋", "溫州", 200, 500, "001.jpg"); 4 Items i2 = new Items(2, "李寧運動鞋", "廣州", 300, 500, "002.jpg"); 5 Items i3 = new Items(1, "沃特籃球鞋", "溫州", 200, 500, "001.jpg"); 6 7 //建立購物車對象 8 Cart cart = new Cart(); 9 cart.addGoodsInCart(i1, 1); 10 cart.addGoodsInCart(i2, 2); 11 cart.addGoodsInCart(i3, 3);//再買3雙沃特籃球鞋 12 13 14 //購物車中商品的集合 15 Set<Map.Entry<Items, Integer>>items = cart.getGoods().entrySet(); 16 for (Map.Entry<Items, Integer> entry : items) { 17 System.out.println(entry); 18 } 19 System.out.println("買4雙沃特籃球鞋和2雙李寧運動鞋以後,購物車總價格:"+cart.getTotalPrice());; 20 }
運行結果:
雖然總金額的計算沒有問題,可是用戶體驗不太好,購物車中中出現了相同的商品記錄(應該是須要合併的)。
一種方式是重寫Items類的hashCode和equals方法。重寫以後再次運行程序:
雖然商品的記錄在購物車中不會重複,可是購買的數量卻不對了,沃特籃球鞋的後面的一條記錄替換掉了前面的記錄。
解決方案:此時只要修改購物車的addGoodsInCart()方法就好了:在加入新的商品以前先判斷若是已經添加了相同的商品,只須要修改商品的數量便可:
1 public boolean addGoodsInCart(Items item, int number) { 2 //若是商品已經在購物車中只須要修改商品數量便可【原有數量+新加入的數量】 3 if (goods.containsKey(item)) { 4 goods.put(item, goods.get(item)+number); 5 }else { 6 goods.put(item, number); 7 } 8 calcTotalPrice();// 從新計算購物車的總金額 9 return true; 10 }
運行結果:
2.Servlet類的設計
由Servlet類調用購物車類的代碼實現購物功能。
3.界面層在details.jsp頁面中顯示購物車。
項目的完整地址:https://git.oschina.net/gaopengfei/JavaWebShoppingDemoByMVC.git