session的应用

来源:互联网 发布:餐饮软件破解版 编辑:程序博客网 时间:2024/06/05 11:32

session在不同环境下的不同含义

    session,中文经常翻译为会话,其本来的含义是指有始有终的一系列动作/消息,比如打电话是从拿起电话拨号到挂断电话这中间的一系列过程可以称之为一个session。session在Web开发环境下的语义又有了新的扩展,它的含义是指一类用来在客户端与服务器端之间保持状态的解决方案。有时候Session也用来指这种解决方案的存储结构。

Session机制

    session机制采用的是在服务器端保持 HTTP 状态信息的方案。服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。当程序需要为某个客户端的请求创建一个session时,服务器首先检查这个客户端的请求里是否包含了一个session标识(即sessionId),如果已经包含一个sessionId则说明以前已经为此客户创建过session,服务器就按照session id把这个session检索出来使用(如果检索不到,可能会新建一个,这种情况可能出现在服务端已经删除了该用户对应的session对象,但用户人为地在请求的URL后面附加上一个JSESSION的参数)。如果客户请求不包含sessionId,则为此客户创建一个session并且生成一个与此session相关联的sessionId,这个session id将在本次响应中返回给客户端保存。

保存session id的几种方式 :

    保存session id的方式可以采用cookie,这样在交互过程中浏览器可以自动的按照规则把这个标识发送给服务器。由于cookie可以被人为的禁用,必须有其它的机制以便在cookie被禁用时仍然能够把session id传递回服务器,经常采用的一种技术叫做URL重写,就是把session id附加在URL路径的后面,附加的方式也有两种,一种是作为URL路径的附加信息,另一种是作为查询字符串附加在URL后面。网络在整个交互过程中始终保持状态,就必须在每个客户端可能请求的路径后面都包含这个session id。

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消失。

Session的创建与删除
     一个常见的错误是以为session在有客户端访问时就被创建,然而事实是直到某server端程序(如Servlet)调用HttpServletRequest.getSession(true)这样的语句时才会被创建。
session在下列情况下被删除:
A.程序调用HttpSession.invalidate()
B.距离上一次收到客户端发送的session id时间间隔超过了session的最大有效时间
C.服务器进程被停止
注意:关闭浏览器只会使存储在客户端浏览器内存中的session cookie失效,不会使服务器端的session对象失效

两个浏览器窗口访问应用程序会使用同一个session

    通常session cookie是不能跨窗口使用的,当你新开了一个浏览器窗口进入相同页面时,系统会赋予你一个新的session id,这样信息共享的目的就达不到了。此时可以先把session id保存在persistent cookie中(通过设置cookie的最大有效时间),然后在新窗口中读出来,就可以得到上一个窗口的session id了,这样通过session cookie和persistent cookie的结合就可以实现了跨窗口的会话跟踪。

Session的超时管理

    WEB服务器无法判断当前的客户端浏览器是否还会继续访问,也无法检测客户端浏览器是否关闭,所以,即使客户已经离开或关闭了浏览器,WEB服务器还要保留与之对应的HttpSession对象。随着时间的推移而不断增加新的访问客户端,WEB服务器内存中将会因此积累起大量的不再被使用的HttpSession对象,并将最终导致服务器内存耗尽。 WEB服务器采用“超时限制”的办法来判断客户端是否还在继续访问,如果某个客户端在一定的时间之内没有发出后续请求,WEB服务器则认为客户端已经停止了活动,结束与该客户端的会话并将与之对应的HttpSession对象变成垃圾。如果客户端浏览器超时后再次发出访问请求,WEB服务器则认为这是一个新的会话的开始,将为之创建新的HttpSession对象和分配新的会话标识号。会话的超时间隔可以在web.xml文件中设置,其默认值由Servlet容器定义。
 <session-config>
  <session-timeout>30</session-timeout>
 </session-config>

HttpSession接口中的方法
   getId方法,getCreationTime方法,getLastAccessedTime方法,setMaxInactiveInterval法,
getMaxInactiveInterval方法,isNew方法,invalidate方法,getServletContext方法,setAttribute方法,
getAttribute方法,removeAttribute方法, getAttributeNames方法

HttpServletRequest接口中的Session方法
    getSession方法 ,public HttpSession getSession(boolean create),public HttpSession getSession(),isRequestedSessionIdValid方法, isRequestedSessionIdFromCookie方法, isRequestedSessionIdFromURL方法

利用URL重写实现Session跟踪
     Servlet规范中引入了一种补充的会话管理机制,它允许不支持Cookie的浏览器也可以与WEB服务器保持连续的会话。这种补充机制要求在响应消息的实体内容中必须包含下一次请求的超链接,并将会话标识号作为超链接的URL地址的一个特殊参数。将会话标识号以参数形式附加在超链接的URL地址后面的技术称为URL重写。如果在浏览器不支持Cookie或者关闭了Cookie功能的情况下,WEB服务器还要能够与浏览器实现有状态的会话,就必须对所有可能被客户端访问的请求路径(包括超链接、form表单的action属性设置和重定向的URL)进行URL重写。
HttpServletResponse接口中定义了两个用于完成URL重写方法:
    encodeURL方法 ,encodeRedirectURL方法

避免表单的重复提交
     调用 RequestDispatcher.forward() 方法,浏览器所保留的URL 是先前的表单提交的 URL,此时点击”刷新”, 浏览器将再次提交用户先前输入的数据,引起重复提交.如果采用 HttpServletResponse.sendRedirct() 方法将客户端重定向到成功页面,将不会出现重复一条问题

利用Session防止表单重复提交
     包含有FORM表单的页面必须通过一个服务器程序动态产生,服务器程序为每次产生的页面中的FORM表单都分配一个唯一的随机标识号,并在FORM表单的一个隐藏字段中设置这个标识号,同时在当前用户的Session域中保存这个标识号。当用户提交FORM表单时,负责接收这一请求的服务器程序比较FORM表单隐藏字段中的标识号与存储在当前用户的Session域中的标识号是否相同,如果相同则处理表单数据,处理完后清除当前用户的Session域中存储的标识号。在下列情况下,服务器程序将忽略提交的表单请求:
当前用户的Session中不存在表单标识号,用户提交的表单数据中没有标识号字段,存储在当前用户的Session域中的表单标识号与表单数据中的标识号不同,浏览器只有重新向WEB服务器请求包含FORM表单的页面时,服务器程序才又产生另外一个随机标识号,并将这个标识号保存在Session域中和作为新返回的FORM表单中的隐藏字段值。
TokenProcessor.java:用于管理表单标识号的工具类,它主要用于产生、比较和清除存储在当前用户Session中的表单标识号。为了保证表单标识号的唯一性,每次将当前SessionID和系统时间的组合值按MD5算法计算的结果作为表单标识号,并且将TokenProcessor类设计为单件类

利用Session实现一次性验证码
    一次性验证码的主要目的就是为了限制人们利用工具软件来暴力猜测密码,其原理与利用Session防止表单重复提交的原理基本一样,只是将表单标识号变成了验证码的形式,并且要求用户将提示的验证码手工填写进一个表单字段中,而不是通过表单的隐藏字段自动回传给服务器。服务器程序接收到表单数据后,首先判断用户是否填写了正确的验证码,只有该验证码与服务器端保存的验证码匹配时,服务器程序才开始正常的表单处理流程。密码猜测工具要逐一尝试每个密码的前题条件是先输入正确的验证码,而验证码是一次性有效的,这样基本上就阻断了密码猜测工具的自动地处理过程。


下面是佟刚老师的session简易版购物车:
'step1.jsp'
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>My JSP 'step1.jsp' starting page</title>
  </head>
 
  <body>
           请选择您要购买的书: <br>
    <c:url value="processStep1" var="url"></c:url>
    <form action="${pageScope.url }" method="post">
     <input type="checkbox" name="book" value="Java">Java
     <input type="checkbox" name="book" value="Oracle">Oracle
     <input type="checkbox" name="book" value="Ruby">Ruby
     <input type="checkbox" name="book" value="C#">C#
     <input type="submit" value="Submit" />
    </form>
  </body>
</html>

'step2.jsp'
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>My JSP 'step2.jsp' starting page</title>
  </head>
 
  <body>
   请填入个人信息: <br>
   <c:url value="processStep2" var="url"></c:url>
    <form action="${pageScope.url }" method="post">
     个人信息: <br>
     姓名: <input type="text" name="name" />
     地址: <input type="text" name="address" /><br><br>
     信用卡信息: <br>
     信用卡类型:<input type="radio" name="cardType" value="visa" />Visa
                <input type="radio" name="cardType" value="master" />Master<br>
     卡号: <input type="text" name="cardId" /><br><br>
     <input type="submit" value="Submit" />
    </form>
  </body>
</html>

 'step3.jsp'
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>My JSP 'step3.jsp' starting page</title>
  </head>
 
  <body>
           订单确认: <br>
           用户名: ${sessionScope.name }<br>
           地址: ${sessionScope.address }<br>
           信用卡类型: ${sessionScope.cardType }<br>
           卡号: ${sessionScope.cardId }<br>
           选购的图书:
    <c:forEach items="${sessionScope.books}" var="book">
     ${book } &nbsp;&nbsp;&nbsp;
    </c:forEach>
  </body>
</html>

ProcessStep1
package cn.itcast.session.shoppingcart;

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 ProcessStep1 extends HttpServlet {

 public void doPost(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException {
  //1. 解析表单信息
  String [] books = request.getParameterValues("book");
  
  //2. 把获取到的图书信息放入 Session 中
  HttpSession session = request.getSession();
  session.setAttribute("books", books);
  
  //3. 页面重定向到 step2.jsp
  response.sendRedirect(response.encodeURL("step2.jsp"));
 }

}

 ProcessStep2
package cn.itcast.session.shoppingcart;

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 ProcessStep2 extends HttpServlet {

 public void doPost(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException {
  String name = request.getParameter("name");
  String address = request.getParameter("address");
  String cardType = request.getParameter("cardType");
  String cardId = request.getParameter("cardId");
  
  HttpSession session = request.getSession();
  session.setAttribute("name", name);
  session.setAttribute("address", address);
  session.setAttribute("cardType", cardType);
  session.setAttribute("cardId", cardId);
  
  response.sendRedirect(response.encodeURL("step3.jsp"));
 }

}
上面的程序,个人觉得很经典!这个里面融和了EL,JSTL,Sevlet这些最新的技术!当然记得最后的时候要配置下WEB.XML文件!
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
 xmlns="http://java.sun.com/xml/ns/javaee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <servlet>
    <description>This is the description of my J2EE component</description>
    <display-name>This is the display name of my J2EE component</display-name>
    <servlet-name>RegServlet</servlet-name>
    <servlet-class>cn.itcast.session.RegServlet</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>RegServlet</servlet-name>
    <url-pattern>/regServlet</url-pattern>
  </servlet-mapping>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

这样这个简易的session购物车就完成了!

原创粉丝点击