Session概述
在WEB开发中,服务器可以为每个用户浏览器创建一个会话对象(session对象),注意:一个浏览器独占一个session对象(默认情况下)。因此,在需要保存用户数据时,服务器程序可以把用户数据写到用户浏览器独占的session中,当用户使用浏览器访问其它程序时,其它程序可以从用户的session中取出该用户的数据,为用户服务。
session是一个域对象,作用范围为整个会话。
Session和Cookie的主要区别在于:
Cookie是把用户的数据写给用户的浏览器。
Session技术把用户的数据写到用户独占的session中。
Session 是一个域
作用范围:当前会话范围
生命周期:
当程序第一次调用到request.getSession()方法时说明客户端明确的需要用到session此时创建出对应客户端的Session对象.
当session超过30分钟(这个时间是可以在web.xml文件中进行修改的)没有人使用则认为session超时销毁这个session.
修改时间:在web.xml文件中<web-app>
标签里添加:
<session-config>
<session-timeout>30</session-timeout> 以分钟为单位的值
</session-config>
程序中明确的调用session.invalidate()方法可以立即杀死session.
当服务器被非正常关闭时,随着虚拟机的死亡而死亡.
如果服务器是正常关闭,还未超时的session会被以文件的形式保存在服务器的work目录下,这个过程叫做session的钝化(Sessions.ser).下次再正常启动服务器时,钝化着的session会被恢复到内存中,这个过程叫做session的活化.
作用:在会话范围内共享数据。
Session原理
request.getSession()方法会检查请求中有没有JSESSIONID cookie,如果有拿出他的值找到对应的session为他服务。
如果没有则检查请求的URL后有没有以参数的形式带着JSESSIONID过来,如果有则找到对应的Session为浏览器服务。
如果还找不到则认为这个浏览器没有对应的Session,创建一个Session然后再在响应中添加JSESSIONID cookie,值就是这个Session 的id。
默认情况下,JSESSIONID 的path为当前web应用的名称,并且没有设置过MaxAge,是一个会话级别的cookie。
这意味着一旦关闭浏览器再新开浏览器时,由于JSESSIONID丢失,会找不到之前的Session。
我们可以手动的发送JSESSIONID cookie,名字和path设置的和自动发送时一样,但是设置一下MaxAge,使浏览器除了在内存中保存JSESSIONID信息以外还在临时文件夹中以文件的形式保存,这样即使重开浏览器仍然可以使用之前的session。
URL重写
如果浏览器禁用了Cookie,浏览器就没有办法JSESSIONID cookie,这样就用不了Session了.
我们可以使用URL重写的机制,在所有的超链接后都以参数的形式拼接JSESSIONID信息,从而在点击超链接时可以使用URL参数的方式带回JSESSIONID,从而使用Session
将URL进行重写拼接上JSESSIONID的过程就叫做URL重写
request.getSession() –在URL重写之前一定要先创建出Session,才能进行重写
response.encodeURL()— 一般的地址都用这个方法重写
response.encodeRedirectURL() — 如果地址是用来进行重定向的则使用这个方法
url重写的方法一旦发现浏览器带回了任意cookie信息,则认为客户端没有禁用cookie,就不会再进行重写操作
Session实例
利用session模拟简单的网站购物功能
新建prodList.jsp文件,用来显示商品。代码如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" session="false"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
</head>
<body>
<%
request.getSession();
String url1 = request.getContextPath() + "/servlet/BuyServlet?prod=电视机";
String url2 = request.getContextPath() + "/servlet/BuyServlet?prod=冰箱";
String url3 = request.getContextPath() + "/servlet/PayServlet";
url1 = response.encodeURL(url1);
url2 = response.encodeURL(url2);
url3 = response.encodeURL(url3);
%>
<a href="<%=url1 %>">电视机</a>
<a href="<%=url2 %>">冰箱</a>
<a href="<%=url3 %>">结账</a>
</body>
</html>
BuyServlet,处理购买商品的逻辑:
package me.zipstream.session;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class BuyServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String prod = request.getParameter("prod");
prod = new String(prod.getBytes("iso8859-1"), "utf-8");
HttpSession session = request.getSession();
Cookie jc = new Cookie("JSESSIONID", session.getId());
jc.setPath(request.getContextPath());
jc.setMaxAge(1800);//30minutes
response.addCookie(jc);
session.setAttribute("prod", prod);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
PayServlet,显示购买后的逻辑:
package me.zipstream.session;
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 PayServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
HttpSession session = request.getSession();
String prod = (String) session.getAttribute("prod");
response.getWriter().write("您购买的商品是:" + prod + ",售价5999元。");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
利用Session实现网站登录的案例
新建index.jsp,模拟网站的首页:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
</head>
<body>
<h1>我的网站</h1><hr>
<%
//获取Session中的登录状态
String user = (String) session.getAttribute("user");
%>
<%
if (user==null || "".equals(user)){
%>
欢迎光临!游客!
<a href="${pageContext.request.contextPath }/loginout/login.jsp">登录</a>
<a href="#">注册</a>
<%
} else{
%>
欢迎回来!<%=user %>
<a href="${pageContext.request.contextPath }/servlet/LogoutServlet">注销</a>
<%
}
%>
</body>
</html>
新建login.jsp,模拟登录页面:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
</head>
<body>
<h1>我的网站</h1><hr>
<form action="${pageContext.request.contextPath }/servlet/LoginServlet" method="POST">
用户名:<input type="text" name="username" />
密码:<input type="password" name="password" />
<input type="submit" value="登录" />
</form>
</body>
</html>
新建UserDao类,模拟用户数据库:
package me.zipstream.session.loginout;
import java.util.HashMap;
import java.util.Map;
public class UserDao {
private UserDao(){}
private static Map<String, String> map = new HashMap<String, String>();
static{
map.put("张三丰", "111");
map.put("张翠山", "222");
map.put("张无忌", "333");
}
public static boolean valiNamePsw(String username, String password){
return map.containsKey(username) && map.get(username).equals(password);
}
}
新建LoginServlet,处理用户登录逻辑:
package me.zipstream.session.loginout;
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 LoginServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
//获取用户名和密码
String username = request.getParameter("username");
String password = request.getParameter("password");
//查询数据库检查用户名和密码
if (UserDao.valiNamePsw(username, password)){
//如果正确登录,则重定向到主页
request.getSession().setAttribute("user", username);
response.sendRedirect(request.getContextPath() + "/loginout/index.jsp");
return;
} else{
//如果错误,则提示
response.getWriter().write("用户名或密码不正确!");
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
新建LogoutServlet,实现用户注销的逻辑:
package me.zipstream.session.loginout;
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 LogoutServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//杀掉session
if (request.getSession(false)!=null
&& request.getSession().getAttribute("user")!=null){
request.getSession().invalidate();
}
//重定向到主页
response.sendRedirect(request.getContextPath() + "/loginout/index.jsp");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}