1 session的概念
3 session的实现
5 session对象的创建和销毁机制
5.1 session对象的创建时机
5.2 session对象的销毁时机
6 利用session防止表单重复提交
在计算机中,尤其是在网络应用中,称为“会话控制”。Session对象存储特定用户会话所需的属性及配置信息。这样,当用户在应用程序的Web页之间跳转时,存储在Session对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当用户请求来自应用程序的 Web页时,如果该用户还没有会话,则Web服务器将自动创建一个 Session对象。当会话过期或被放弃后,服务器将终止该会话。Session 对象最常见的一个用法就是存储用户的首选项。例如,如果用户指明不喜欢查看图形,就可以将该信息存储在Session对象中。
在WEB开发中,服务器可以为每个用户浏览器创建一个会话对象(session对象),注意:一个浏览器独占一个session对象(默认情况下)。因此,在需要保存用户数据时,服务器程序可以把用户数据写到用户浏览器独占的session中,当用户使用浏览器访问其它程序时,其它程序可以从用户的session中取出该用户的数据,为用户服务。
服务端在创建了session之后,会将sessionid以cookie的形式存于浏览器,只要不关闭浏览器,再访问服务端时sessionid都会存在,就会使用服务端内存中与之对应的session为之服务。
package cn.session.study;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* Servlet implementation class SessionDemo01
*/
@WebServlet("/SessionDemo01")
public class SessionDemo01 extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public SessionDemo01() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
//使用request对象的getSession()获取session,如果session不存在创建一个
HttpSession session = request.getSession();
//将数据存储到session中
session.setAttribute("data", "娃哈哈");
//获取session的ID
String sessionId = session.getId();
//判断session是不是新建的
if (session.isNew()) {
response.getWriter().print("session创建成功,session的id是:"+sessionId);
} else {
response.getWriter().print("服务器已经存在了该session,sessionid是:"+sessionId);
}
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
response.encodeRedirectURL(java.lang.String url) 用于对sendRedirect方法后的url地址进行重写。
response.encodeURL(java.lang.String url) 用于对表单action和超链接的url地址进行重写。
IndexServlet.java
package cn.session.study;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;
import java.util.Set;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import cn.session.study.domain.Book;
/**
* Servlet implementation class IndexServlet
*/
@WebServlet("/IndexServlet")
public class IndexServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public IndexServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
//创建session
HttpSession session = request.getSession();
//获取sessionid
String sessionID = session.getId();
//判断session是不是新建的
if(session.isNew()) {
response.getWriter().print("session创建成功,sessionid是:"+sessionID);
}else {
response.getWriter().print("服务器已经纯在session,sessionid是:"+sessionID);
}
out.write("本网站有如下图书:
");
Set> set = DB.getAll().entrySet();
for (Map.Entry entry : set) {
Book book = entry.getValue();
String url = request.getContextPath()+"/BuyServlet?id="+book.getId();
response.encodeURL(url);//用于对表单action和超链接的url地址进行重写
url = response.encodeURL(url);//将超链接的url地址进行重写
out.println(book.getName()+"购买
");
}
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
Book.java
package cn.session.study.domain;
public class Book {
private String id;
private String name;
public Book(String id, String name) {
super();
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
DB.java
package cn.session.study;
/**
*
* @author Administrator
*
*/
import java.util.LinkedHashMap;
import java.util.Map;
import cn.session.study.domain.Book;
public class DB {
private static Map map = new LinkedHashMap();
static {
map.put("1", new Book("1","javaweb开发"));
map.put("2", new Book("2","spring开发"));
map.put("3", new Book("3","hibernate开发"));
map.put("4", new Book("4","struts开发"));
map.put("5", new Book("5","ajax开发"));
}
public static Map getAll() {
return map;
}
}
BuyServlet.java
package cn.session.study;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import cn.session.study.domain.Book;
/**
* Servlet implementation class BuyServlet
*/
@WebServlet("/BuyServlet")
public class BuyServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public BuyServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String id = request.getParameter("id");
Book book = DB.getAll().get(id);//得到用户想要买的书
HttpSession session = request.getSession();
List list = (List) session.getAttribute("list");//得到用户用于保存所有书的容器
if(list==null) {
list = new ArrayList();
session.setAttribute("list", list);
}
list.add(book);
// response.encodeRedirectURL(java.lang.String url);//用户对sendRedirect方法后的url进行重写。
String url = response.encodeRedirectURL(request.getContextPath()+"/ListCartServlet");
System.out.println(url);
response.sendRedirect(url);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
ListCarServlet.java
package cn.session.study;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import cn.session.study.domain.Book;
/**
* Servlet implementation class ListCartServlet
*/
@WebServlet("/ListCartServlet")
public class ListCartServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public ListCartServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
HttpSession session = request.getSession();
List list = (List) session.getAttribute("list");
if (list==null||list.size()==0) {
writer.write("对不起您没有购买任何商品!!");
}
writer.write("您买过如下商品:
");
for (Book book : list) {
writer.write(book.getName()+"
");
}
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
在程序第一次调用request.getSession()方法时就会创建一个新的session,可以用isNew()方法来判断session是不是新创建的。
//使用request对象的getSession()获取session,如果session不存在创建一个
HttpSession session = request.getSession();
//将数据存储到session中
session.setAttribute("data", "娃哈哈");
//获取session的ID
String sessionId = session.getId();
//判断session是不是新建的
if (session.isNew()) {
response.getWriter().print("session创建成功,session的id是:"+sessionId);
} else {
response.getWriter().print("服务器已经存在了该session,sessionid是:"+sessionId);
}
session对象默认30分钟没哟使用个,则服务器就会自动销毁session,web.xml文件中可以手工配置session的失效时间。
JavaWeb_Study
index.html
index.htm
index.jsp
default.html
default.htm
default.jsp
15
具体实现:在服务端生成一个唯一的随机标识号,专业术语称为token(令牌),同时在当前用户的session域中保存这个token,然后将token发送到form表单中,在form表单中使用隐藏域来存储这个token,表单提交的时候连同这个token一起提交到服务端,,然后在服务端判断客户端提交上来的token与服务端生成的token是否一致,如果不一致,那就是重复提交了。此时服务端就可以处理重复提交的表单。如果相同则处理表单提交,处理完后清除当前用户的session域中的标识号。
以下情况,服务器程序将拒绝处理用户的表单请求:
1. 存储session域中的token(令牌)与表单提交的token(令牌)不同、
2. 当前用户的session中不存在token(令牌)。
3. 用户提交的表单数据中没有token。
具体的范例:
1. 创建FormServlet,用于生成token(令牌)和跳转到fom.jsp
package cn.session.study;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class FormServlet
*/
@WebServlet("/FormServlet")
public class FormServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public FormServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String token = TokenProcessor.getInstance().makeToken();//创建token
System.out.println("在FormServlet中生成token:"+token);
request.getSession().setAttribute("token", token);
request.getRequestDispatcher("/form.jsp").forward(request, response);//跳转到form.jsp页面
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
2. 在form.jsp中使用隐藏域来存储token(令牌)
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
Form表单重复提交
3. DoFormServlet处理表单提交
package cn.session.study;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class DoFormServlet
*/
@WebServlet("/DoFormServlet")
public class DoFormServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public DoFormServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
//客户端是以UTF-8编码传输数据到服务端的,所以设置服务端以UTF-8的编码进行接收,否则对于中文数据就会乱码
request.setCharacterEncoding("utf-8");
String userName = request.getParameter("username");
try {
//让当前的线程睡眠3秒钟,模拟网络延迟而导致表单重复提交的现象
Thread.sleep(3*1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("向数据库中插入数据:"+userName);
*/
boolean b = isRepeatSubmit(request);//判断用户是否重复提交
if(b==true) {
System.out.println("请不要重复提交");
return;
}
request.getSession().removeAttribute("token");//移除session中的token
System.out.println("处理用户提交请求!");
}
/**
* 判断客户端提交上来的令牌和服务器端生成的令牌是否一致
* @param request
* @return true 用户重复提交了表单
* false 用户没有重复提交表单
*/
private boolean isRepeatSubmit(HttpServletRequest request) {
String client_token = request.getParameter("token");
//1.如果用户提交的表单数据中没有token,,则用户是重复提交
if(client_token==null) {
return true;
}
//取出存储在session中token
String server_token = (String) request.getSession().getAttribute("token");
//2.如果当前用户的session中不存在token,则用户重复提交
if (server_token==null) {
return true;
}
//3.存储在session中的token与表单提交的token不同,则用户重复提交了表单
if (!client_token.equals(server_token)) {
return true;
}
return false;
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
生成token的工具类TokenProccessor
package cn.session.study;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
public class TokenProcessor {
/*
* 单例设计模式(保证累的对象在内存中只有一个)
* 1.把类的构造函数私有
* 2.自己创建一个类的对象
* 3.对外提供一个公共的方法,返回类的对象
*/
private TokenProcessor() {}
private static final TokenProcessor instance = new TokenProcessor();
/**
* 返回类的对象
* @return
*/
public static TokenProcessor getInstance() {
return instance;
}
/**
* 生成token
* @return
*/
public String makeToken() {
String token = (System.currentTimeMillis()+new Random().nextInt(999999999))+"";
try {
MessageDigest md = MessageDigest.getInstance("md5");
byte[] md5 = md.digest(token.getBytes());
//base64编码--任意二进制编码明文字符
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(md5);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
}