JavaWeb开发中的会话技术[Cookie/Session]

时间:2021-03-22 13:20:07

会话

会话:用户打开一个浏览器,点击多个超链接,访问服务器多个web资源,然后关闭浏览器,整个过程称之为一个会话。

会话过程中要解决的一些问题:

  • 每个用户在使用浏览器与服务器进行会话的过程中,不可避免各自回产生一些数据,程序要想办法为每个用户保存这些资源。电商中的保存用户的购买的商品。

保存会话数据的两种技术

  • Cookie:Cookie是客户端技术,程序把每个用户的数据以cookie的形式写给用户各自的浏览器。当用户使用浏览器再去访问服务器中的web资源时,就会带着各自的数据去,这样web资源处理的就是用户自己的数据。
  • Session:Session是服务器技术,利用这个技术,服务器在运行时可以为每一个用户的浏览器创建一个其独享的session对象,由于session为用户浏览器独享,所以用户在访问服务器的web资源时,可以把各自的数据放在各自的session中,当用户再去访问服务器中的其他web资源时,其他的web资源再从用户各自德尔session中取出数据为用户服务。
  • Cookie的访问过程:
    JavaWeb开发中的会话技术[Cookie/Session]

  • javax.servlet.http.Cookie类用于创建一个Cookie,response接口也定义了一个addCookie方法,它用于在其响应头中增加一个相应的Set-Cookie头字段。同样在request接口中也定义了一个getCookies方法,它用于获取客户端提交的Cookie。

  • Cookie类的方法有(最好查看其API):

    • public Cookie(String name, String value)
    • setValue 与 getValue
    • setMaxAge 与 getMaxAge() [秒]
    • setPath 与 getPath
    • setDomain 与 getDomain
    • getName
  • 一个Cookie是一个键值对。

  • 通过Cookie可以保存用户的信息,示例:保存用户的上次的访问的时间并显示出来(通过request获取请求头中带有的Cookie,再通过response的响应头将Cookie值返回给浏览器):

package com.hsx.cookie;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;

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 com.hsx.constant.MyConstant;

/**
* 保存用户的上次的访问的时间并显示出来
* @author hsx
*
*/

public class CookieDemo1 extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("您上次获取的时间是:");
// 从客户端的请求获取指定的cookie
Cookie[] cookies = request.getCookies();
System.out.println(cookies); // 第一次访问时cookie的值可能为null
for (int i = 0; cookies != null && i < cookies.length; i++) {
Cookie cookie = cookies[i];
System.out.println(cookie.getName());
if (MyConstant.LAST_ACCESS_TIME.equals(cookie.getName())) {
long value = Long.parseLong(cookie.getValue());
out.println(new Date(value).toLocaleString());
}
}
// 把当前的时间写给客户端
Cookie cookie1 = new Cookie(MyConstant.LAST_ACCESS_TIME, System.currentTimeMillis() + "");
cookie1.setPath(request.getContextPath());
cookie1.setMaxAge(10 * 24 * 60 * 60); //存活的时间,默认浏览器的进程
response.addCookie(cookie1);
}

public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

this.doGet(request, response);
}

}

--------------------------------------------------------

/**
* 常量接口设计模式(这里只是设置了Cookie的name值)
* @author hsx
*
*/

public interface MyConstant {

String LAST_ACCESS_TIME = "lastAccessTime";
}
  • Cookie细节:
    • 获取Cookie采用:request.getCookies();
    • 设置Cookie采用:response.addCookie(cookie);
    • 一个Cookie只能标识一种信息,它至少含有一个标识该信息的名称(name)和设置值(value)。
    • 一个Web站点可以给一个Web浏览器发送多个Cookie,一个Web浏览器也可以存储多个Web站点提供的Cookie。
    • 浏览器一般存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB。
    • 如果创建了一个Cookie,并将它发送到浏览器,默认情况下它是一个会话级别的cookie(即存储在浏览器的内存中),用户退出浏览器之后即被删除。若希望浏览器将该Cookie存储在磁盘上,则需要使用maxAge(默认是浏览器的进程),并给出一个以秒为单位的时间。将最大时效设为0则是命令浏览器删除该Cookie。
    • path:默认是产生cookie的应用的访问路径,删除Cookie时,path必须一致,否则不会删除。在应用程序中设置Cookie时[cookie.setPath(“xxx”)]注意:
    • 如果设置了路径,只能被包含的此路径的资源访问。
    • 如果设置的路径是”/servletCS”,该Cookie只能被servletCS这个应用访问。
    • 如果设置的路径是”/servletCS2”,虽然是servletCS应用产生的Cookie,但是该Cookie只能被servletCS2这个应用访问,servletCS是访问不到的。
    • cookie.setPath(request.getContextPath())这条语句设置的Cookie是本身这个应用的。由此可得:request.getContextPath()是获取该应用[项目]的路径。
    • 如果设置的路径是cookie.setPath("http://localhost:8080/")或者cookie.setPath("/")这条语句设置的Cookie能被”http://localhost:8080/“下的所有的应用访问。
    • 如果设置的路径是cookie.setPath("http://localhost:8080/ServletCS/servlet/")这条语句设置的Cookie能只能被该Servlet访问;即某个Servlet的url-pattern配置是servlet2,则该servlet2都不能访问其Cookie。
    • 总结:Cookie是否能被访问到是根据其设置的路径而言的。
//--- 删除指定的cookie  cookie.setMaxAge(0);---//
// 先获取指定的Cookie
Cookie[] cookies = request.getCookies();
for (int i = 0; cookies != null && i < cookies.length; i++) {
Cookie cookie = cookies[i];
if (MyConstant.LAST_ACCESS_TIME.equals(cookie.getName())) {
//设置其maxAge(0):必须有path一致
cookie.setMaxAge(0);
cookie.setPath(request.getContextPath());
//写个客户端
response.addCookie(cookie);
}
}
  • Cookie应用
    • 模拟用户名登陆,始终保存用户的用户名[CookieDemo2中输入用户名,提交到CookieDemo3中,CookieDemo3对其用户名的Cookie做永久保存,在以后访问CookieDemo2时,用户名能显示出来]
/*---------------CookieDemo2---------------------*/
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

String name = "";
String rem = "";

// 从Cookie中获取用户名
Cookie[] cookies = request.getCookies();
for (int i = 0; cookies != null && i < cookies.length; i++) {
Cookie cookie = cookies[i];
if (MyConstant.USER_NAEM.equals(cookie.getName())) {
name = cookie.getValue();
rem = "checked='checked'";
}
}

// 显示出登陆页面
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head><title>用户登陆</title></head>");
out.println("<body>");
out.println("<form action='/servletCS/CookieDemo3' method='post'>");
out.println("<table width='400' border='1'>");
out.println("<tr>");
out.println("<td>用户名</td>");
out.println("<td><input type='text' name='username' value='" + name + "'/></td>");
out.println("</tr>");
out.println("<tr>");
out.println("<td>密码</td>");
out.println("<td><input type='password' name='password'/></td>");
out.println("</tr>");
out.println("<tr>");
out.println("<td colspan='2'><input type='checkbox' name='remember' " + rem + " />记住用户名</td>");
out.println("</tr>");
out.println("<tr>");
out.println("<td colspan='2'><input type='submit' value='go'/></td>");
out.println("</tr>");
out.println("</table>");
out.println("</form>");
out.println("</body>");
out.println("</html>");
}


/*------------------CookieDemo3--------------------------*/
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
Cookie cookie = null;
String remember = request.getParameter("remember");
System.out.println(remember);
if (remember != null) {
cookie = new Cookie(MyConstant.USER_NAEM, request.getParameter("username"));
cookie.setPath(request.getContextPath());
cookie.setMaxAge(Integer.MAX_VALUE); //永久保存
response.addCookie(cookie);
}
out.println(cookie.getName() + "<br/>");
out.println(cookie.getValue());
}


/*--------------------常量接口设计模式------------------------*/
public interface MyConstant {

String USER_NAEM = "username";
}

Seesion

  • session的访问过程
    JavaWeb开发中的会话技术[Cookie/Session]

  • 在Web开发中,服务器可以为每一个用户浏览器创建一个会话对象(Session对象),注意:一个浏览器独占一个Session对象(默认情况下)。因此,在需要保存用户数据时,服务器程序可以把用户数据写到用户浏览器独占的Session中,当用户使用浏览器访问其他程序时,其他程序可以从用户的Session中取出该用户的数据,为用户服务。

  • Session和Cookie的主要区别在于:
    • Cookie是把用户的数据写给用户的浏览器。
    • Seesion技术把用户的对象写到用户独占的session中。
  • Session对象是由服务器创建的,开发人员可以调用request对象的getSession方法得到session对象。
  • Session技术实际上用的Cookie技术。图解说明:
  • 注意:
    • IE7及以下版本,新开的窗口都会开启一次新会话。
    • 每一个客户端都有各自的Session对象,以SeesionID标识。
    • Seesion技术实际上是借助Cookie技术实现的,在创建Session对象时,会将该Session对象的ID以Cookie的JSESSIONID=SessionID的形式写给客户端。
    • session的原理图:
      JavaWeb开发中的会话技术[Cookie/Session]
    • Session默认何时时效?时间到了,就会失效,默认是30分钟。更改Session的默认时间:
      在web.xml文件的根元素中增加,单位为分钟。
<session-config>
<session-timeout>1s</session-timeout>
</session-config>

注意:

request.getSession(); // 要是没有Session对象,就立马创建Session对象
request.getSession(false); // 设置了false,要是没有Session对象,不会创建session对象。
  • IE禁用Cookie后的session处理
    • 解决方案:URL重写(以下方法先检查浏览器是否禁用Cookie,若禁用Cookie那么会在地址栏上加上jsesssionid=xxx,若没有禁用Cookie那么不加jsessionid–>很智能。注意:当禁用Cookie后,要对所有的URL进行重写)
    • response.encodeRedirectURL(java.lang.String url); //用于对sendRedirect方法后的url地址进行重写。
    • response.encodeURL(java.lang.String url); //用于对表单action和超链接的url地址进行重写。
String url1 = request.getContextPath() + "/PayServlet";
url1 = response.encodeURL(url1);
out.println("<br/><a href='" + url1 + "'>结账</a>");
  • 案例:
/*-----IndesServlet-----显示所有的商品,提供购买链接 -- 放入购物车*/ 

response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head><title>商品</title></head>");
out.println("<body>");
// 显示所有的商品
List<String> productList = Product.getAllProduct();
out.println("本站有以下好商品:<br/>");
for (String product : productList) {
out.println(product);
String url = request.getContextPath() + "/BuyServlet?name=" + product;
url = response.encodeURL(url); //禁用浏览器的Cookie时使用的
out.println("<a href='" + url + "'>购买</a><br/>");
}
// 转向结账
String url1 = request.getContextPath() + "/PayServlet";
url1 = response.encodeURL(url1);
out.println("<br/><a href='" + url1 + "'>结账</a>");
out.println("</body>");
out.println("</html>");
out.close();


/*-----BuyServlet-----购买的Servlet,将商品加入购物车*/

String productName = request.getParameter("name");
productName = new String(productName.getBytes("ISO-8859-1"), "UTF-8");

// 查看Session中是否有购物车
HttpSession session = request.getSession();
Object object = session.getAttribute(MyConstant.MY_CART);
if (null != object) {// 有:取出来,放商品
List<String> cartList = (List<String>) object;
cartList.add(productName);
}
else {// 没有,先构件购物车
List<String> cartList = new ArrayList<String>();
cartList.add(productName);
session.setAttribute(MyConstant.MY_CART, cartList);
}

response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("您已经购买了:" + productName);
String url = request.getContextPath() +"/IndesServlet";
url = response.encodeURL(url);
out.println("<br/><br/><a href='"+ url +"'>继续购买</a>");


/*-----PayServlet-----显示购物车中的商品*/

response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
HttpSession session = request.getSession(false); //只是取
if (session == null) {
out.println("您还未购物");
}
else {
List<String> myCartList = (List<String>) session.getAttribute(MyConstant.MY_CART);
out.println("您购买了以下商品:<br/>");
for (Object object : myCartList) {
out.println(object + "<br/>");
}
}
out.close();
  • Session开发中遇到的问题?
    1. 内存中的Session非常多,怎么办?
    2. 用户在购物中,服务器停了该web应用(或者重启了),那么用户购物车中的东西怎么办?
      • 解决办法:将内存中的Session持久化。
      • 何时session会被持久化?[具体是根据服务器的实现定的,对用户来说完全是透明的]
    3. 当服务器停止当前应用
    4. 内存中的session对象太多
    5. session长时间没有活动(并没有被销毁)
      • 何时会被激活?
    6. 当前web应用又启动了
    7. 用户又开始使用了(鼠标、键盘又开始使用了)
      • session中的序列与反序列基本图:
        JavaWeb开发中的会话技术[Cookie/Session]