会话技术之Session

会话技术之Session

​ 对Session做总结之前,我们先来运行一个小小的demo。假设这样一个情景,在网站的登录界面中输入自己用户名和密码,然后点击登录,登录之后跳转的主界面应该包含刚刚的登录信息(如用户名),也就是在登录界面和主界面之间应该把用户信息共享,或者说传递给主界面。那么如何实现这个过程呢?可能一开始会有这样的疑问,我们可以将JSP获取到的字段值存放到request域中,然后负责处理主界面的Servlet直接在request中读取就可以啦,那么到底这样做能不能解决这个问题呢,我们来试一下。

​ 为了直观的感受,我们把这个过程简化下,只需要一个简单的JSP登陆界面,两个Servlet。

【代码】SessionTest.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Sessiondemo</title>
</head>
<body>
	<form action="SomeServlet" method="post">
	输入用户名:<input type="text" name="username" id="username"></input>
	<br>
	<input type="submit" value="提交">
	</form>
</body>
</html>

【代码】SomeServlet.java

import java.io.IOException;
import java.io.PrintWriter;

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 SomeServlet
 */
@WebServlet("/SomeServlet")
public class SomeServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public SomeServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @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.setCharacterEncoding("UTF-8");
		request.setCharacterEncoding("UTF-8");
		
		String username=request.getParameter("username");
		request.setAttribute("user",username);
		HttpSession session=request.getSession();
		session.setAttribute("username", username);
		PrintWriter out=response.getWriter();
		out.println("SomeServlet Session: "+ session);
		out.println("SomeServelt username: "+ username);
	}

}

【代码】OtherServlet.java

import java.io.IOException;
import java.io.PrintWriter;

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 OtherServlet
 */
@WebServlet("/OtherServlet")
public class OtherServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public OtherServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		response.setCharacterEncoding("UTF-8");
		request.setCharacterEncoding("UTF-8");
		
		//从Request域中读取user属性
		String user=request.getParameter("user");
		
		//获取Session
		HttpSession session =request.getSession(false);
		
		//从Session中读取username属性
		String username=null;
		if(session!=null) {
			username=(String) session.getAttribute("username");
		}
		
		PrintWriter out=response.getWriter();
		out.println("OtherServlet user = "+user);
		out.println("OtherServlet username = "+username);
		out.println("OtherServlet session : "+session);
		
	}

	/**
	 * @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);
	}

}

​ 这个demo中引入了Session会话机制、读取request域获取登陆用户名的方法,通过浏览器的打印结果我们可以发现从request域中获取的user为null,而使用Session之后SomeServlet和OtherServlet的Session和username打印结果均相同。这说明Session的会话机制可以解决我们一开始说的问题,而获取request域的方法则行不通。下面通过解释user值在OtherServlet中为空的原因仔细的总结下Session是怎么来的。

​ 我们知道,用浏览器打开一个网页,用到的是HTTP协议,HTTP协议是无状态的,就是说这一次请求和上一次请求是没有任何关系的,互不认识的,没有关联的,但是这种无状态的的好处是快速。所以带来的问题就是,我希望几个请求的页面要有关联,比如:我在www.itbegin.com/login.jsp里面登陆了,我在www.itbegin.com/index.jsp也希望是登陆状态,但是,这是2个不同的页面,也就是2个不同的HTTP请求,这2个HTTP请求是无状态的,也就是无关联的,所以无法单纯的在index.jsp中读取到它在login.jsp中已经登陆了,所以这也是为什么获取request域信息在页面中显示null的原因。那怎么去解决这个问题呢,在index.jsp界面中再登录一遍?这个时候出现了一种客户端存储数据的方式Cookie,Cookie是把信息储存在用户本地,它在一个域名下是全局的。不安全又很容易的被修改。由此session就出现了,它储存在服务器上,通过它关联同一个用户的信息,这样用户在访问不同的页面的时候我们就知道对方是同一个人,而不需要每次无状态的访问都需要用户登录/关联了。

​ Session,是web开发中的一种会话状态跟踪技术,Cookie也是,不同的是Cookie是将会话状态保存在了客户端,而Session是保存在了服务器端。Session不是Javaweb开发中所特有的,而是整个Web开发中所使用的技术,在Javaweb中,Session是以HttpSession的接口对象出现的。

​ 对于客户端来说,浏览器发送第一次请求到关闭浏览器是一次会话,但是对于服务器端来说,浏览器发送第一次请求一直到session失效才是一次会话。

1.Session 的访问
1.1 Session对象的创建

​ Session对象的创建主要有两个方法,有参和无参。无参数的构造方法如果当前这个request有相关联的session那么就返回,否则就创建一个新的再返回,显然使用这种方法的时候数据来源根本不是同一个session,所以这种情况下不应使用该创建方法,有参的构造方法呢则是 若当前存在Session则返回该会话,参数为true就新建一个Session参数为false返回NULLH。

HttpServletRequest.getSession(ture) 等同于 HttpServletRequest.getSession(),若当前存在Session则返回该会话,否则新建一个Session;

HttpServletRequest.getSession(false) 等同于: 若当前存在Session则返回该会话,否则返回NULL,因此,一般情况下,尽量要明确使用参数为false的写法。

​ 需要注意的地方是request.getSession() 等同于 request.getSession(true),除非我们确认session一定存在或者sesson不存在时明确有创建session的需要,否则尽量使用request.getSession(false)。在使用request.getSession()函数,通常在action中检查是否有某个变量/标记存放在session中。这个场景中可能没有session存在,那么创建之后需要判断下session是否为null。之前示例demo中OtherServlet就做了这样的判断处理。

1.getSession();
//Returns the current session associated with this request, or if the request does not have a session, creates one.
2.getSession((boolean create);
//Returns the current HttpSession associated with this request or, if there is no current session and create is true, returns a new session.
1.2 对Session域属性空间的操作

​ Session是一个专门用于存放数据的集合,一般称这个存放数据的内存空间叫做域属性空间。其中里面有三个方法。

getAttribute(java.lang.String name)
//Returns the object bound with the specified name in this session, or null if no object is bound under the name.
setAttribute(java.lang.String name, java.lang.Object value)
//Binds an object to this session, using the name specified.
removeAttribute(java.lang.String name)
//Removes the object bound with the specified name from this session.
1.3 例子

以setAttribute方法为例。

//构造一个User的curruser对象
User curruser = new User(“zhangsan”, 20, “男”); 
//两个参数分别是 属性名,属性对应的值
request.setAttribute(“curruser”, curruser)
2.Session的工作原理

​ 在服务器中系统会为每个会话维护一个session,HTTP请求一个页面后(第一次访问时,服务器会创建一个新的sesion,并且把session的Id以cookie的形式发送给客户端浏览器),如果用到开启session,会去读cookie中的JSESSIONID是否有,如果没有,则会新生成一个session_id,先存入cookie中的JSESSIONID中,再生成一个sess前缀文件。当有写入$SESSION的时候,就会往sess文件里序列化写入数据。当读取的session变量的时候,先会读取cookie中的JSESSIONID,获得session_id,然后再去找这个sess_sessionid文件,来获取对应的数据。由于默认的JSESSIONID是临时的会话,在浏览器关闭后,会消失,所以,我们重新访问的时候,会新生成session_id和sess这个文件,所以我们用同一浏览器多次关闭打开获取到的Session打印信息不一样的原因。

2.1 写入Session列表

​ 服务器对当前应用中的Session是以Map的形式进行管理的,这个Map成为Session列表。该Map的key是一个32位长度的随机串JSessionID,value则为Session对象的引用。

​ 当用户第一次提交请求时,服务端的Servlet中执行到getSession()方法后,会自动创建生成一个Map.Entry对象,key为一个根据某种算法新生成JSessionID,value则为新创建的HttpSession对象。

2.2 服务器生成并发送Cookie

​ 在将Session信息写入Session列表后,系统还会自动将JSESSIONID作为name,这个32位长度的随机串作为value,以Cookie的形式存放到响应报头中,并随着响应,将该Cookie发送到客户端。
输入helloagain然后提交。
在这里插入图片描述

2.3 客户端接受并发送Cookie

​ 客户端接收到这个Cookie后将其存放到浏览器的缓存中。即,只要客户端浏览器不关闭,浏览器缓存中的Cookie就不会消失。当用户提交第二次请求时,会将缓存中的Cookie伴随着请求的头部信息一块发送到服务端。
在这里插入图片描述在这里插入图片描述

2.4 从Session列表中查找

​ 服务器端从请求中读取到客户端发送来的Cookie,并根据Cookie的JSESSIONID值,从Map中查找响应的key对应的value,即session对象,然后对该session对象的域属性进行读写操作。

2.5 一个小实验

​ 我在Chrome浏览器中新建了一个页面,再次访问http://localhost:8080/WebTest/SessionTest.jsp,这一次没有在input中输入用户名,之间点击登录,那么SomeServlet中的username会显示什么呢?答案是什么也没用,但是我们发现JSessionID和以前是一样的,说明即使新建了一个网页但是在同一个浏览器中,Session是共享的,那么我们来验证一下,切换到第一个打开的界面F5刷新,如果共享数据的话username应该由helloagain变为空白,我们来实验下。
在这里插入图片描述在这里插入图片描述 还想补充的就是,我一直以为只有执行了getSession()才会创建JSessionID,当我注释相关代码之后在访问JSP界面我发现依然后生成JSessionID,与是否有getSession()方法无关,当然了访问servlet也会生成。
以及在不改变代码的情况下,禁用Cookie,会发现在OtherServlet中打印的三行全部为null,这样说明了Session是依赖于Cookie完成实现的。

3.Session的失效

​ 其实可以理解为Session的超时,如果某个Session在指定的时间范围内一直没有被访问,那么Session就会失效。一般默认Session的超时时间为30min。Session即使失效了,也不是null!

4.Cookie禁用后使用Sesssion进行重定向
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值