zoukankan      html  css  js  c++  java
  • android保持Session会话

    android保持Session会话

    在服务端完成实现app在线用户列表的功能,无论是HttpSessionListener还是HttpSessionBindingListener都依赖session机制。但app未退出,服务端的session会话就销毁了,导致无法正确监测到app用户的在线情况。

    1.session的生命周期

    • 当服务端接收到请求时,服务端会为其分配一个session会话

    • 这个session会话有一个最大保存时间MaxInactiveInterval,当用户的不活动状态超过这个时间,session会销毁

    • 如果是网页端,当用户注销或者退出浏览器时,session会销毁

    2.android无法保持会话的原因

    • 网页端的每次请求都是活动,将重置session会话的时间,实现持久访问

    • android端就不同了,它的请求头中是不带sessionId的,所以服务端无法识别它访问的是哪个session,也无法识别请求来自于哪个session

    3.解决问题

    建议大家安装 FireFox浏览器,它的检查功能是真的好用,比谷歌浏览器好用

    • 写个servlet,运行服务端,网页里加个css外链

    • 用FireFox打开网页并检查

    • 注意到高亮的Cookie:JSESSIONID=70943E03B9683A966235579F4D57892F,打印session.getId()验证,发现这个JSESSIONID就是本次session的sessionId

    • 如何查看android访问服务端的请求头呢?在servlet添加以下代码:

      	Cookie[] Cookies = request.getCookies();
      	for(int i =0;i<Cookies.length;i++){
      		Cookie c = Cookies[i];
      		System.out.println(c.getName() + "=" + c.getValue());
      	}
      
    • 使用android发起一个请求,报错java.lang.NullPointerException,说明android默认的请求是不带Cookie的

    • 给android的请求头加上Cookie,我这里使用的是OkHttp3

      Request request = new Request.Builder()
                      .url(url).addHeader("Cookie", "JSESSIONID=" + session_id)
                      .post(body)
                      .build();
      
    • 至于这个session_id,可以这样做:服务端接收到登录请求,获取会话的sessionID,返回给android端,android端存到SharedPreferences里,发送请求的时候取出

    • 使用带Cookie的方法再次访问服务端,可以看到打印出JSESSIONID,这时候android和网页端一样都能实现session持久了

    4.验证Session持久

    • 在服务端工程的web.xml里添加

      <session-config>
      	<session-timeout>1</session-timeout>
      </session-config>
      
    • 表示设置session的最大保存时间为1分钟,设置为1分钟是为了方便验证

    • 添加在线用户监听器,这里给出一个方案:

      //登录处理的Servlet添加,user为用户实体对象
      session.setAttribute("onlineUserBindingListener", new OnlineUserBindingListener(user));
      
      //在线用户监听器,使用注解方式
      import java.util.ArrayList;
      import java.util.List;
      
      import javax.servlet.ServletContext;
      import javax.servlet.annotation.WebListener;
      import javax.servlet.http.HttpSession;
      import javax.servlet.http.HttpSessionBindingEvent;
      import javax.servlet.http.HttpSessionBindingListener;
      
      import domain.User;
      
      @WebListener
      public class OnlineUserBindingListener implements HttpSessionBindingListener {
      
      	private User user;
      
      	public OnlineUserBindingListener() {
      
      	}
      
      	public OnlineUserBindingListener(User user) {
      		this.user = user;
      	}
      
      	@SuppressWarnings("unchecked")
      	public void valueBound(HttpSessionBindingEvent event) {
      		HttpSession session = event.getSession();
      		ServletContext application = session.getServletContext();
      
      		List<User> onlineUserList = (List<User>) application.getAttribute("onlineUserList");
      
      		if (onlineUserList == null) {
      			onlineUserList = new ArrayList<User>();
      			application.setAttribute("onlineUserList", onlineUserList);
      		}
      		onlineUserList.add(this.user);
      	}
      
      	@SuppressWarnings("unchecked")
      	public void valueUnbound(HttpSessionBindingEvent event) {
      		HttpSession session = event.getSession();
      		ServletContext application = session.getServletContext();
      
      		List<User> onlineUserList = (List<User>) 			           application.getAttribute("onlineUserList");
      
      		onlineUserList.remove(this.user);
      	}
      }
      
    • 网页端显示用户列表,直接application.getAttribute("onlineUserList"),我不再赘述。网页每30秒自动刷新:

      <meta http-equiv="refresh" content="30"/>
      
    • app登录后不操作,1分钟后用户列表数据消失

    • app登录后连续操作,每次操作间隔在1分钟内,用户列表数据持续存在。验证成功

    5.其它

    • session的getAttribute和setAttribute方法是不会影响它的生命周期的,仍视为无活动状态

    • 根据sessionId获取session的方法已经再Servlet 2.5后弃用,仍然想实现该功能的可以参考https://blog.csdn.net/sihai12345/article/details/81098765,基本原理是自己维护一个HashMap<String,HttpSession>

    • Jsp中显示实体型列表尽量结合JSTL和EL表达式,简便清楚,用JSTL别忘了导包。示例:

    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
    <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    <c:when test="${requestScope.operat_type eq 'userList'}">
        <table>
            <thead>
                <tr>
                    <th>姓名</th>
                    <th>密码</th>
                    <th>部门</th>
                    <th>等级</th>
                    <th>注册时间</th>
                    <th>最近登录时间</th>
                    <th>最近登录IP</th>
                    <th>登录次数</th>
                </tr>
            </thead>
            <tbody>
                <c:forEach items="${requestScope.userList}" var="user">
                    <tr>
                        <td>${user.name }</td>
                        <td>${user.password }</td>
                        <td>${user.department }</td>
                        <td>${user.grade }</td>
                        <td>${fn:substring(user.reg_time,0,19) }</td>
                        <td>${fn:substring(user.log_time,0,19) }</td>
                        <td>${user.log_ip }</td>
                        <td>${user.log_count }</td>
                    </tr>
                </c:forEach>
            </tbody>
        </table>
    </c:when>
    

    转载请注明博文来源,有什么问题欢迎在评论栏留言。 ——Kevin_Lu 2020/4/14

  • 相关阅读:
    【Elasticsearch 技术分享】—— ES 常用名词及结构
    【Elasticsearch 技术分享】—— Elasticsearch ?倒排索引?这都是什么?
    除了读写锁,JUC 下面还有个 StampedLock!还不过来了解一下么?
    小伙伴想写个 IDEA 插件么?这些 API 了解一下!
    部署Microsoft.ReportViewe
    关于TFS强制undo他人check out
    几段查看数据库表占用硬盘空间的tsql
    How to perform validation on sumbit only
    TFS 2012 Disable Multiple Check-out
    在Chrome Console中加载jQuery
  • 原文地址:https://www.cnblogs.com/kaml8/p/12700138.html
Copyright © 2011-2022 走看看