1.問題的提出
HTTP協議是一種無狀態的協議,WEB服務器(這說明會話是從WEB服務器的角度進行定義的)本身不能識別出哪些請求是同一個瀏覽器發出的 ,瀏覽器的每一次請求都是完全孤立的。作爲 web 服務器,必須能夠採用一種機制來唯一地標識一個用戶,同時記錄該用戶的狀態。
2.會話和會話狀態
WEB應用中的會話是指一個客戶端瀏覽器與WEB服務器之間連續發生的一系列請求和響應過程。
WEB應用的會話狀態是指WEB服務器與瀏覽器在會話過程中產生的狀態信息,藉助會話狀態,WEB服務器能夠把屬於同一會話中的一系列的請求和響應過程關聯起來。
3.如何實現有狀態的會話?
WEB服務器端程序要能從大量的請求消息中區分出哪些請求消息屬於同一個會話,即能識別出來自同一個瀏覽器的訪問請求,這需要瀏覽器對其發出的每個請求消息都進行標識:屬於同一個會話中的請求消息都附帶同樣的標識號,而屬於不同會話的請求消息總是附帶不同的標識號,這個標識號就稱之爲會話ID(SessionID)。
4.會話的機制
在 Servlet 規範中,常用以下兩種機制完成會話跟蹤:①Cookie ②Session
5.Cookie
1)Cookie機制
(1)cookie機制採用的是在客戶端保持 HTTP 狀態信息的方案
(2)Cookie是在瀏覽器訪問WEB服務器的某個資源時,由WEB服務器在HTTP響應消息頭中附帶傳送給瀏覽器的一個小文本文件。
(3)一旦WEB瀏覽器保存了某個Cookie,那麼它在以後每次訪問該WEB服務器時,都會在HTTP請求頭中將這個Cookie回傳給WEB服務器。
(4)底層的實現原理: WEB服務器通過在HTTP響應消息中增加Set-Cookie響應頭字段將Cookie信息發送給瀏覽器,瀏覽器則通過在HTTP請求消息中增加Cookie請求頭字段將Cookie回傳給WEB服務器。
(5)一個Cookie只能標識一種信息,它至少含有一個標識該信息的名稱(NAME)和設置值(VALUE)。
(6)一個WEB站點可以給一個WEB瀏覽器發送多個Cookie,一個WEB瀏覽器也可以存儲多個WEB站點提供的Cookie。
(7)瀏覽器一般只允許存放300個Cookie,每個站點最多存放20個Cookie,每個Cookie的大小限制爲4KB。
2)Cookie的相關方法
(1)Cookie類的方法:
①構造方法: public Cookie(String name,String value)
②getName方法
③setValue與getValue方法
④setMaxAge與getMaxAge方法 :若設置爲0表示立即刪除該Cookie,負數表示不存儲該Cookie,正數表示存儲時間。
⑤setPath與getPath方法
(2)HttpServletResponse接口中定義了一個addCookie方法,它用於在發送給瀏覽器的HTTP響應消息中增加一個Set-Cookie響應頭字段。
(3)HttpServletRequest接口中定義了一個getCookies方法,它用於從HTTP請求消息的Cookie請求頭字段中讀取所有的Cookie項。
<%
//在Javaweb規範中Cookie類代表cookie
//1.創建Cookie對象
Cookie cookie = new Cookie("name","xiaojun");
//2.調用response的addCookie(Cookie cookie)方法把cookie傳給瀏覽器
response.addCookie(cookie);
//3.通過request的getCookies()方法獲取Cookie
Cookie[] cookies = request.getCookies();
if(cookies != null && cookies.length > 0){
for(Cookie c : cookies){
//4.獲取cookie的name和value
out.print(c.getName() + " : " + c.getValue());
}
}else{
out.print("沒有Cookie,正創建返回一個Cookie!");
Cookie cookie2 = new Cookie("name","xiaoming");
response.addCookie(cookie2);
}
//4.設置Cookie的最大有效期,以秒爲單位。
cookie.setMaxAge(30);
%>
3)案例
(1)自動登錄
登錄界面login.jsp<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" session="false"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<form action="hello.jsp">
name : <input type="text" name="name"/>
<input type="submit" value="submit"/>
</form>
</body>
</html>
處理界面hello.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" session="false"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<%
//若可以獲取到請求參數 loginName, 則打印出歡迎信息。把登錄信息存儲到 Cookie 中,並設置 Cookie 的最大時效爲 30S
String name = request.getParameter("name");
if(name != null && !name.trim().equals("")){
Cookie cookie = new Cookie("cookieName",name);
cookie.setMaxAge(5);
response.addCookie(cookie);
}else{
//從 Cookie 中讀取用戶信息,若存在則打印歡迎信息
Cookie[] cookies = request.getCookies();
if(cookies != null && cookies.length > 0){
for(Cookie c : cookies){
String cookieName = c.getName();
if("cookieName".equals(cookieName)){
String cookieValue = c.getValue();
name = cookieValue;
}
}
}
}
if(name != null && !name.trim().equals("")){
out.print("hello : " + name);
}else{
//若既沒有請求參數,也沒有 Cookie,則重定向到 login.jsp
response.sendRedirect("login.jsp");
}
%>
</body>
</html>
6.HttpSession
1)HttpSession是什麼
(1)session機制採用的是在服務器端保持 HTTP 狀態信息的方案
(2)當程序需要爲某個客戶端的請求創建一個session時,服務器首先檢查這個客戶端的請求裏是否包含了一個 session 標識(即 sessionId ),如果已經包含一個 sessionId 則說明以前已經爲此客戶創建過 session,服務器就按照 session id 把這個session 檢索出來使用(如果檢索不到,可能會新建一個,這種情況可能出現在服務端已經刪除了該用戶對應的session對象,但用戶人爲地在請求的URL後面附加上一個 JSESSION 的參數)。如果客戶請求不包含 sessionId,則爲此客戶創建一個session 並且生成一個與此 session 相關聯的 sessionId,這個 session id 將在本次響應中返回給客戶端保存。
(3)使用Cookie來跟蹤Session:session 通過 SessionID 來區分不同的客戶,,session 是以 cookie 或 URL 重寫爲基礎的,默認使用 cookie 來實現,系統會創造一個名爲 JSESSIONID 的輸出 cookie,這稱之爲 session cookie;session cookie 是存儲於瀏覽器內存中的,並不是寫到硬盤上的,通常看不到 JSESSIONID。
2)Session的生命週期
(1)創建HttpSession:一個常見的錯誤是以爲 session 在有客戶端訪問時就被創建,然而當第一次訪問某 WEB 應用的一個 JSP 頁面,且該 JSP 頁面的 page 指令的session爲 false 時,就不會創建一個 Session 對象
①某server端程序(如Servlet)調用HttpServletRequest.getSession(true) 或者 HttpServletRequest.getSession()這樣的語句時纔會被創建
②當第一次訪問某 WEB 應用的一個 JSP 頁面,且該 JSP 頁面的 page 指令的session爲 true時,服務器會自動爲該頁面分配一個Session對象
(2)銷燬HttpSession
①程序調用HttpSession.invalidate()
②距離上一次收到客戶端發送的session id時間間隔超過了session的最大有效時間
③服務器進程被停止(或當前 WEB 應用被卸載)
注意:關閉瀏覽器只會使存儲在客戶端瀏覽器內存中的session cookie失效,不會使服務器端的session對象失效
3)HttpSession相關的API
(1)獲取Session對象:request.getSession() request.getSession(boolean create)
(2)Session屬性相關的方法:setAtrribute getAttribute removeAttribute
(3)使HttpSession失效的方法:invalidate()
(4)設置Session最大時效的方法:setMaxInactiveInteval()
4)URL重寫
(1)Servlet規範中引入了一種補充的會話管理機制,它允許不支持Cookie的瀏覽器也可以與WEB服務器保持連續的會話
(2)將會話標識號以參數形式附加在超鏈接的URL地址後面的技術稱爲URL重寫
(3)代碼:
<a href=" <%= response.encodeURL("login.jsp") %>">重新登錄</a>
5)購物車:
login.jsp
<%@page import="javax.management.modelmbean.RequiredModelMBean"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<h4>step1:選擇要購買的書籍</h4>
<form action="<%=request.getContextPath()%>/processStep1" method="post">
<table border="1" cellspacing="0" cellpadding="10">
<tr>
<td>書名</td>
<td>購買</td>
</tr>
<tr>
<td>Java</td>
<td><input type="checkbox" name="book" value="Java"/></td>
</tr>
<tr>
<td>Oracle</td>
<td><input type="checkbox" name="book" value="Oracle"/></td>
</tr>
<tr>
<td>Structs</td>
<td><input type="checkbox" name="book" value="Structs"/></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="submit"/></td>
</tr>
</table>
</form>
</body>
</html>
person.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<h4>step2:請輸入寄送地址和信用卡信息</h4>
<form action="<%= request.getContextPath() %>/processStep2" method="post">
<table border="1" cellspacing="0" cellpadding="10">
<tr>
<td colspan="2">基本信息</td>
<td>姓名:<input type="text" name="name"/></td>
<td>寄送地址:<input type="text" name="adress"/></td>
</tr>
<tr>
<td colspan="2">信用卡信息</td>
<td>種類:<input type="radio" name="cardType" value="Visa"/>Visa
<input type="radio" name="cardType" value="Master"/>Master
</td>
<td>卡號:<input type="text" name="cardID"/></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="submit"/></td>
</tr>
</table>
</form>
</body>
</html>
comfirm.jsp
<%@page import="com.zhaoliang.servlet.Custmer"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<h4>step3:訂單確認</h4>
<%
Custmer custmer = (Custmer)session.getAttribute("custmer");
String[] books = (String[])session.getAttribute("books");
%>
<table border="1" cellspacing="0" cellpadding="10">
<tr>
<td colspan="2">基本信息</td>
</tr>
<tr>
<td>姓名:</td>
<td><%=custmer.getName() %></td>
</tr>
<tr>
<td>寄送地址:</td>
<td><%=custmer.getAddress() %></td>
</tr>
<tr>
<td colspan="2">信用卡信息</td>
</tr>
<tr>
<td>種類:</td>
<td><%=custmer.getCardType() %></td>
</tr>
<tr>
<td>卡號:</td>
<td><%=custmer.getCardID() %></td>
</tr>
<tr>
<td colspan="2">圖書信息</td>
<td>
<%
for(String book : books){
out.print(book);
out.print("<br>");
}
%>
</td>
</tr>
</table>
</body>
</html>
shoppingServlet
package com.zhaoliang.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ProcessStep1 extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.獲取圖書信息
String[] books = request.getParameterValues("book");
//2.將圖書信息添加到Session中
request.getSession().setAttribute("books", books);
//3.重定向到ShoppingCart/step-2.jsp頁面下
response.sendRedirect(request.getContextPath() + "/ShoppingCart/step-2.jsp");
}
}
inputInfoServlet
package com.zhaoliang.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ProcessStep2 extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.獲取請求參數name address cardType cardID
String name = request.getParameter("name");
String address = request.getParameter("address");
String cardType = request.getParameter("cardType");
String cardID = request.getParameter("cardID");
//2.將上述參數存入到HttpSession中
Custmer custmer = new Custmer(name, address, cardType, cardID);
request.getSession().setAttribute("custmer", custmer);
//3.重定向到comfirm.jsp
response.sendRedirect(request.getContextPath() + "/ShoppingCart/confirm.jsp");
}
}
customer類
package com.zhaoliang.servlet;
public class Custmer {
private String name;
private String address;
private String cardType;
private String cardID;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getCardType() {
return cardType;
}
public void setCardType(String cardType) {
this.cardType = cardType;
}
public String getCardID() {
return cardID;
}
public void setCardID(String cardID) {
this.cardID = cardID;
}
public Custmer(String name, String address, String cardType, String cardID) {
this.name = name;
this.address = address;
this.cardType = cardType;
this.cardID = cardID;
}
public Custmer() {
}
}
注意:
1.在開發中,路徑建議編寫成絕對路徑:在由Servlet轉發到JSP頁面時,此時在地址欄上顯示的是Servlet的路徑,而若JSP頁面的超鏈接還是相對於該JSP頁面的地址,則可能會出現路徑混亂的問題
2.在JavaWEB中,絕對路徑有當前WEB應用和站點路徑之分
3.在JavaWEB中, / 代表什麼
1)當前WEB應用的根路徑:http://localhost:8080/contextPath/ (若 / 由Servlet來處理)
(1)請求轉發:request.getRequestDispatcher("/path/a.jsp").forward(request,response) ----> http://localhost:8080/day_01/path/a.jsp
(2)web.xml文件用映射Servlet訪問路徑
<servlet-mapping>
<servlet-name>loginServlet</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
---->http://localhost:8080/day_01/login2)當前站點的跟路徑:http://localhost:8080/ (若 / 由瀏覽器來處理)
(1)超鏈接:<a href="/a.jsp>AAA</a> ----> http://localhost:8080/a.jsp
(2)form中的action:<from action="/a.jsp"></form>
(3)請求重定向:response.sendRedirect("/a.jsp")
7.避免表單重複提交
1)如何避免表單重複提交:在表單中做一個標記,在表單提交到Servlet時,檢查標記是否存在且是否和預定的標記一致。若一致,這受理請求,並銷燬標記;若不一致或沒有標記,則直接響應提示信息:“重複提交”
2)實現:
<%@page import="java.util.Date"%>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<%
String tokenValue = new Date().getTime() + "";
session.setAttribute("token", tokenValue);
%>
<form action="<%=request.getContextPath() %>/tokenServlet" method="post">
<input type="hidden" name="token" value="<%= tokenValue%>"/>
name:<input type="text" name="name"/>
<input type="submit" value="submit"/>
</form>
</body>
</html>
package com.zhaoliang.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class TokenServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try{
Thread.sleep(2000);
}catch(Exception e){
e.printStackTrace();
}
HttpSession session = request.getSession();
Object token = session.getAttribute("token");
String tokenValue = request.getParameter("token");
System.out.println("session token : " + token);
System.out.println("hidden token : " + tokenValue);
if(token != null && token.equals(tokenValue)){
session.removeAttribute("token");
}else{
response.sendRedirect(request.getContextPath() + "/token/erro.jsp");
return;
}
String name = request.getParameter("name");
System.out.println(name);
request.getRequestDispatcher("/token/sucess.jsp").forward(request, response);;
}
}
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<h4>Success Page</h4>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<h4>sorry</h4>
</body>
</html>
8.驗證碼(Session)
1)