Head First Servlet&JSP 6.session management

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sinat_34524528/article/details/86885788

d# Conversation State

服务器没有短期记忆,消息已发出去就忘了你是谁。这个问题用 Servlet API 来解决。
注:本章覆盖了所有 session management 的内容,别着急。

要像真的“对话”一样

服务器要记得之前都说过什么,即在某处保存客户端的先前所有请求中的参数。
有哪些选择呢?

  • stateful session enterprise javabean:可达目的,但是杀鸡焉用牛刀,款且 Tomcat 不是支持EJB的完整 J2EE 容器
  • database:可达目的,开销更甚
  • HttpSession:对头

HTTP 协议提供的的是无状态(stateless)连接。
客户端连接服务器,发送请求,接收响应,最后关闭连接。
换句话说,连接连接仅存在于一次单个的 request/response。连接不持续,故容器并不能识别这个请求是由上一个请求相同的客户端发送的,对容器来说,每个请求都视为新的客户端发送的请求。

识别客户端:
不能用IP,因为服务器看到的是你的路由的IP。
不能用安全信息(HTTPS),因为这需要用户登录,而好的网站设计成只有必要的时候(如结账)才需要用户登录,而浏览时(如添加到购物车)则不必。

The client needs a unique session ID

客户端发出第一个请求,容器生成唯一的 session ID 并和响应一起发送回客户端。客户端在后续的请求中都带着这个 session ID。容器看到这个 ID ,就认得这个客户端是先前的客户端了。

How do the Client and Container exchange Session ID info?

用Cookies。响应头“Set-Cookie",请求头"Cookie"。

//Sending a session cookie in the RESPONSE
HttpSession session = request.getSession();// 具体的一系列操作由容器在幕后完成
// Getting the session ID from the REQUEST
HttpSession session = request.getSession();
// 两者是一样的

如何得知 session 是否是刚创建的。

public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
    response.setContentType("text/html");
    PrintWriter out = response.getWriter();
    out.println("test session attributes<br>");
    
    HttpSession session = request.getSession();

    if (session.isNew()) {
        out.println("This is a new session ");
    } else {
        out.println("Welcome back!");
    }
}

如何只要已经存在的 session。

public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
    response.setContentType("text/html");
    PrintWriter out = response.getWriter();
    out.println("test session attributes<br>");

    HttpSession session = request.getSession(false);
    // false 参数,返回已经存在的session,如果没有与当前客户端联系的session,返回null

    if (session == null) {
        out.println("no session was available");
        out.println("making one...");
        session = request.getSession();
    } else {
        out.println("there was a session!");
    }
}

getSession(false)getSession(true)

扫描二维码关注公众号,回复: 5318614 查看本文章

You can do sessions even if the client doesn’t accept cookies, but you have to do a little more work

the container can handle a cookie-refusing client but it takes a little more effort from you.
If cookies aren’t enabled, it means the client will never join the session. In other words, the session’s isNew() method will always return true.

p234: A client with cookies disabled will ignore “Set-Cookies” response headers

这需要用 URL rewriting 来解决。
既然不能通过cookies 交换 session ID info,这可以将 session ID 直接贴到 URL 的末尾。

public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
    response.setContentType("text/html");
    PrintWriter out = response.getWriter();
    HttpSession session = request.getSession(false);// get a session

    out.println("<html><body>");
    out.println("<a href=\"" + response.encodeURL("/BeerTest.do") + "\">click me<a/>"); // Add the extra session ID info to this URL
    out.println("<body/><html/>");
}

容器这样判断客户端是否支持Cookie:第一个response 同时用“Set-Cookies"和 URL rewriting。如果再次过来的请求头有 “Cookies”,容器知道客户端支持,并忽略response.encodeURL()。反之,则知道不支持。同时发送两种是为了容器能在客户端在此请求时至少用URL rewriting识别客户端。

URL rewriting works with sendRedirect()

response.encodeRedirectURL("/BeerTest.do")

URL encoding is handled by the Response.(call on your HttpServletResponse object)

URLrewriting一段时间不活跃的session回被容器销毁掉。

Key HttpSession methods
除了 getAttribute(),setAttribute(),removeAttribute()。
key-HttpSession-methods

Setting session timeout

全局设定,in DD ,单位为分钟,如果N分钟之内没有新的请求则杀死。

<web-app ...>
  <servlet>...
  </servlet>
  <session-config>
    <session-timeout>15</session-timeout> <!--参数是分钟-->
  </session-config>
</web-app>

为特定 session 设定

session.setMaxInactiveInterval(20*60);// 参数是秒

Cookies for other things

cookies 设计来是为了支持 session 状态,但是也可以用来干别的。
Remember, cookie is nothing more than a little piece of data (a name/value String pair) exchanged between the client and server.
The server sends the cookie to the client, and the client returns the cookie when the client makes another request.

默认情况下,cookie和session共存亡,推出浏览器cookie就消失,但是 可以让cookie在浏览器关闭后仍然存在。
比如,Kim希望每次回到啤酒网站时都能显示他的用户名。
Cookie

Using Cookies with the Servlet API

Cookie-API

//Creating a new Cookie
Cookie cookie = new Cookie("username", name);
//Setting how long a cookie will live on the client
cookie.setMaxAge(30*60);// 单位为秒,参数 -1 表示浏览器退出后立即消失
// Sending the cookie to the client
response.addCookie(cookie);
// Getting the cookie(s) from the client request
Cookie[] cookies = request.getCookies();
for (int i = 0; i < cookies.length; i++) {
    Cookie cookie = cookies[i];
    if(cookie.getName().equals("username")) {
        String userName = cookie.getValue();
        out.println("Hello " + userName);
        break;
    }
}// 没有 getCookie(String) 这个方法,所以只有遍历找到需要的。

Simple custom cookie example

用Eclispe写这个例子时遇到了一些问题。

Session Lifecycle Events 生命周期

Milestone Event Type Listener Type
lifecycle: created, destroyed. HttpSessionEvent HttpSessionListener
Attribute: added, removed, replaced. HttpSessionBindingEvent HttpSessionAttributeListener
Migration: passivated, actived (分布式) HttpSessionEvent HttpSessionActivationListener

HttpSessionBindingEvent 监视 Attribute 的变动,以便更新/同步数据库的数据。
回顾:valueBound(HttpSessionEvent event) , valueUnbound(HttpSessionEvent event) 方法。

注:HttpSessionBindingEvent 下的valueBound,valueUnbound方法,只要拓展类实现了就可实现回调。但是 HttpSessionListener,HttpSessionAttributeListener,HttpSessionActivationListener必须在DD里注册,才能用。因为这三个与session本身相关。详见上一章提到过的八种listener。

因为Session Migration,HttpSessionActivationListener(说上说鲜有用到)与分布式相关,这里就跳过不读了。

Listener Example

package com.example;
import javax.serlvet.http.*;

public class BeerAttributeListenr implements HttpSessionAttributeListener {
    public void attribuiteAdded(HttpSessionBindingEvent event){
        String name = event.getName();
        Object value = event.getValue();
        System.out.println("Attribute added: " + name +": "+value);
    }

    public void attributeRemoved(HttpSessionBindingEvent event){
        String name = event.getName();
        Object value = event.getValue();
        System.out.println("Attribute removed: " + name +": "+value);
    }
    public void attributeReplaced(HttpSessionBindingEvent event){
        String name = event.getName();
        Object value = event.getValue();
        System.out.println("Attribute replaced: " + name +": "+value);
    }
}

Configure the listener in DD

<web-app...>
  ...
    <listener>
      <listener-class>
        com.example.BeerAttributeListener
      <listener-class>
    </listener>
</web-app>

web app 中的 System.out 去向何处?
System.out-catalina.log###Session Related Listeners
session-related Listener### Session-related Event Listeners and Event Objects API overview
events-listener-api注意 getValue() 返回的是旧值。

ch6 Mock Test

第一次正确率:4/15 ,26.7 %
知识漏洞太多,API不熟。必须多复习。
六章暂毕。

猜你喜欢

转载自blog.csdn.net/sinat_34524528/article/details/86885788