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/login
2)当前站点的跟路径: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)