Session cookie
基础知识:
- session通过SessionID来区分不同的客户,session是以cookie或URL重写为基础的,默认使用cookie来实现,系统会创造一个名为JSESSIONID的输出cookie ,这称之为session cookie,以区别persistent cookies(也就是我们通常所说的cookie),session cookie是存储于浏览器内存中的,并不是写到硬盘上的,通常看不到JSESSIONID,但是当把浏览器的cookie禁止后,web服务器会采用URL重写的方式传递Sessionid,这时地址栏看到
- session cookie针对某-次会话而言,会话结束session cookie也就随着消失了,而persistent cookie只是存在于客户端硬盘上的一段文本。
- 关闭浏览器,只会是浏览器端内存里的session cookie消失,但不会使保存在服务器端的session对象消失,同样也不会使已经保存到硬盘上的持久化cookie消失。
HttpSession 的生命周期
1. 什么时候创建HttpSession 对象
①对于JSP:是否浏览器访问服务端的任何一个JSP, 服务器不一定创建一 个HttpSession对象
若当前的JSP是客户端访问的当前WEB应用的第一 个资源,且JSP的page指定的session 属性值为false,则服务器就不会为JSP创建-个HttpSession对象;
若当前JSP不是客户端访问的当前WEB应用的第一个资源,且其他页面已经创建一个HttpSession对象,则服务器就不会为JSP创建-个HttpSession对象
②对于Serlvet:若Serlvet是客户端访问的第一-个WEB应用的资源,则只有调用了request . getSession()或request . getSession(true)才会创建HttpSession对象
2. page指令的session="false"
指当前JSP页面禁用session 隐含变量!但可以使用其他的显式的HttpSession 对象
3. 在servlet 中获取HttpSession 对象
request . getSession(boolean create):
create为false,若没有和当前JSP页面关联的HttpSession对象,则返回null;若有,则返回true
create为true, -定返回一个HttpSession对象。若没有和当前JSP页面关联的HttpSession对象,则服务器创建一个新的HttpSession对象返回,若有,直接返回关联的。
request . getSession(): 等同于request . getSession(true)
4.什么时候销毁HttpSession对象:
①直接调用HttpSession 的invalidate() 方法:该方法使HttpSession 失效
②服务器卸载了当前WEB应用。
③超出HttpSession的过期时间。
>设置HttpSession的过期时间: session. setMaxInactiveInterval(5);单位秒
>在web. xml文件中设置HttpSession的过期时间:单位为分钟.
<session- config>
<session-t imeout >30</sess ion- timeout>
</session- config>
④.并不是关闭了浏览器就销毁了HttpSession.
HttpSession 接口中的方法
- getId
得到session的 id - getCreateTime
得到创建时间 - getLastAccessdTIme
得到上次访问时间 - setMaxInactiveIntever
设置生命周期 - getMaxInactiveIntever
得到生命周期 - isNew
判断当前session 是不是新建的 - invalidate
使session 失效 - getServletContext
得到上下文 - setAttribute
设置 属性 attribute - getAttribute
得到属性 attribute - removeAttribute
移除属性attribute - getAttriuteNames
得到属性列
案例 登陆界面
login.jsp 中
<body>
IsNew:<%= session.isNew() %>
<br><br>
SessionID:<%= session.getId() %>
<br><br>
SessionCreatTime<%= new Date(session.getCreationTime()) %>
<br><br>
SessionLastAccessTime:<%= new Date(session.getLastAccessedTime()) %>
<br><br>
SessionMaxINactiveInterval:<%= session.getMaxInactiveInterval() %>
<br><br>
<%
Object name = session.getAttribute("userName");
if(name == null){
name = "";
}
%>
<form action="hello.jsp" method="post">
UserName:<input type="text" name="userName" value=<%= name %>>
<input type="submit" name = "submit" value = "Submit">
</form>
</body>
</html>
hello.jsp中
<body>
IsNew:<%= session.isNew() %>
<br><br>
SessionID:<%= session.getId() %>
<br><br>
SessionCreatTime<%= new Date(session.getCreationTime()) %>
<br><br>
SessionLastAccessTime:<%= new Date(session.getLastAccessedTime()) %>
<br><br>
SessionMaxINactiveInterval:<%= session.getMaxInactiveInterval() %>
<br><br>
Hello: <%= request.getParameter("userName") %>
<br><br>
<%
session.setAttribute("userName", request.getParameter("userName"));
%>
<a href="logIn.jsp">重新登陆</a>
<a href="logout.jsp">注销</a>
</body>
logout.jsp 中
<body>
已推出登陆
<br><br>
<%
session.invalidate();
%>
<a href="sigIn.jsp">返回登陆</a>
</body>
效果图
利用URL 重写实现session 跟踪
Servlet规范中引入了一种补充的会话管理机制,它允许不支持Cookie的浏览器也可以与WEB服务器保持连续的会话。这种补充机制要求在响应消息的实体内容中必须包含下-次请求的超链接,并将会话标识号作为超链接的URL地址的一个特殊参数。
将会话标识号以参数形式附加在超链接的URL地址后面的技术称为URI重写。
<form action="<%= response.encodeURL("hello.jsp")%>" method="post" >
userName:
<input type="text" name="username">
<input type="submit" name="submit" value="Submit">
</fomr>
1.关于 / :代表当前WEB应用的根目录,也可以代表WEB站点的根目录的情况
- / 如果交给浏览器解析,则代表WEB站点的根目录,如果交给WEB服务器解析则代表当前WEB应用的根目录
(1)代表当前WEB应用的根目录:在web.xml文件中,映射路径;请求的转发
(2)代表WEB站点的根目录:超链接的href 属性,请求重定向中的 /
2.关于绝对路径:
1).写绝对路径肯定不会发生问题。而写相对路径则可能会发生问题
2 ).所谓绝对路径:相对于当前WEB应用的路径.在/代表WEB站点的根目录,需要在前面加上contextPath
response.sendRedirect(request.getContextPath0 + "/check/index.jsp");
<form action=" <%= request.getContextPath0 %> /checkCodeServlet" method="post">
request.getRequestDispatcher("/di/m.jsp".forward(request, response);
3.处理重复提交的基本思想:
- 重复提交的情况:
①在表单提交到一个Servlet, 而Servlet又通过请求转发的方式响应一个JSP(HTML) 页面,此时地址栏还保留着Serlvet的那个路径,在响应页面点击"刷新"
②在响应页面没有到达时重复点击"提交按钮" .
③点击"返回",再点击"提交" - 不是重复提交的情况:点击"返回",“刷新” 原表单页面,再"提交”.
- 如何避免表单的重复提交:
在表单中做-个标记, 提交到Servlet时,检查标记是否存在且是否和预定义的标记致,若一致,则受理请求,并销毁标记,若不一致或没有标记,则直接响应提示信息: “重复 提交”
1仅提供一-个隐藏域: <input type= "hidden" name="token" value="atguigu"/>.
行不通:没有方法清除固定的请求参数.
2把标记放在request 中。
行不通,因为表单页面刷新后,request 已经被销毁,再提交表单是一个新的request .
3把标记放在session 中.可以!
解决方案
在原表单页面,生成一个随机值token
在原表单页面,把token值放入session 属性中
在原表单页面,把token值放入到隐藏域中.
在目标的Servlet中:获取session和隐藏域中的token值
比较两个值是否一-致:若-致,受理请求,且把session域中的token 属性清除
若不-致,则直接响应提示页面: “重复提交”
案例 表单重复提交
form.jsp 中
<body>
<%
//得到一个时间
String token = new Date().getTime()+"";
//将 token 放在session 的属性中
request.getSession().setAttribute("token", token);
%>
<form action="<%= request.getContextPath() %>/formServlet" method="post">
UserName:
<input type="text" name="name"/>
<input type="submit" name="submit" value="Submit"/>
<input type="hidden" name="tokenValue" value="<%= token %>"/>
</form>
formServlet 中
@WebServlet("/formServlet")
public class FormServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//得到一个 session
HttpSession session = request.getSession();
//得到session 中的 token 和 提交表单中的 tokenValue
String token = (String) session.getAttribute("token");
String tokenValue = request.getParameter("tokenValue");
//打印token 和 tokenvalue
System.out.println(token);
System.out.println(tokenValue);
//若token 为空或者 两个不相等 则返回错误界面
//相等则删除 session 中的tooken
if(token!=null && token.equals(tokenValue)) {
session.removeAttribute("token");
}else {
response.sendRedirect(request.getContextPath()+"/preventRepeatSubmit/error.jsp");
return ;
}
//提交成功
request.getRequestDispatcher("/preventRepeatSubmit/success.jsp").forward(request, response);
}
}
successful 和 error 省略
练习 简单购物车
process1.jsp 中
<body>
<h4>Step1:选择要购买的书籍</h4>
<%= request.getContextPath() %>
<form action="<%= request.getContextPath() %>/controlServlet1" method="post">
<table border="1px" cellpadding="10px" cellspacing="0px">
<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>JavaWeb</td>
<td><input type="checkbox" name="book" value="JavaWeb"></td>
</tr>
<tr>
<td>struts</td>
<td><input type="checkbox" name="book" value="struts"></td>
</tr>
<tr>
<td colspan="2"><input type="submit" name = "submit" value="submit"></td>
</tr>
</table>
</form>
</body>
controlServlet1.java中
@WebServlet("/controlServlet1")
public class ControlServlet1 extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//得到书名
String[] books = request.getParameterValues("book");
//将books 放在session 的 attribute 中
request.getSession().setAttribute("books", books);
//请求重定向到 process2.jsp 中
response.sendRedirect(request.getContextPath() + "/shoppingCart/process2.jsp");
}
}
process2.jsp 中
<body>
<h4>Step2:输入寄货地址和信用卡信息</h4>
<form action="<%= request.getContextPath() %>/controlServlet2" method="post">
<table border="1" cellpadding="10" cellspacing="0">
<tr>
<td colspan="2">基本信息</td>
</tr>
<tr>
<td>姓名信息</td>
<td><input type="text" name="name" value=""/></td>
</tr>
<tr>
<td>寄送地址</td>
<td><input type="text" name="address" value=""/></td>
</tr>
<tr>
<td colspan="2">信用卡信息</td>
</tr>
<tr>
<td>种类</td>
<td>
<input type="radio" name="cardType" value="Visa"/>Visa
<input type="radio" name="cardType" value="Master"/>Master
</td>
</tr>
<tr>
<td>卡号</td>
<td><input type="text" name="card"/></td>
</tr>
<tr>
<td colspan="2"><input type="submit" name="submit" value="Submit"/></td>
</tr>
</table>
</form>
</body>
contorlServlet2.java 中
@WebServlet("/controlServlet2")
public class ControlServlet2 extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 得到 name address cartType card
String name = request.getParameter("name");
String address = request.getParameter("address");
String cardType = request.getParameter("cardType");
String card = request.getParameter("card");
Customer customer = new Customer(name, address, cardType, card);
//将customer 添加到session 中
request.getSession().setAttribute("customer", customer);
//重定向到 process3.jsp
response.sendRedirect(request.getContextPath() + "/shoppingCart/process3.jsp");
}
}
process3.jsp 中
<body>
<h4>Step3:订单确定</h4>
<%
Customer customer = (Customer)session.getAttribute("customer");
%>
<table border="1" cellpadding="10" cellspacing="0">
<tr>
<td>顾客姓名</td>
<td><%= customer.getName() %></td>
</tr>
<tr>
<td>寄送地址</td>
<td><%= customer.getAddress() %></td>
</tr>
<tr>
<td colspan="2">付款信息</td>
</tr>
<tr>
<td>信用卡类型</td>
<td><%= customer.getCardType() %></td>
</tr>
<tr>
<td>卡号</td>
<td><%= customer.getCard()%></td>
</tr>
<tr>
<td>订货项目</td>
<td>
<%
System.out.println("dd");
String[] books = (String[])session.getAttribute("books");
for(String book : books){
%>
<%= book %><br>
<%
}
%>
</td>
</tr>
</table>
</body>
封装的 Customer类
public class Customer {
private String name;
private String address;
private String cardType;
private String card;
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 getCard() {
return card;
}
public void setCard(String card) {
this.card = card;
}
public Customer(String name, String address, String cardType, String card) {
super();
this.name = name;
this.address = address;
this.cardType = cardType;
this.card = card;
}
public Customer() {
}
}