• 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

  • 相关阅读:
    【BZOJ4538】[Hnoi2016]网络 整体二分+树状数组
    【BZOJ4543】[POI2014]Hotel加强版 长链剖分+DP
    【BZOJ1304】[CQOI2009]叶子的染色 树形DP
    【BZOJ4552】[Tjoi2016&Heoi2016]排序 二分+线段树
    【BZOJ4557】[JLoi2016]侦察守卫 树形DP
    【BZOJ4499】线性函数 线段树
    【BZOJ1576】[Usaco2009 Jan]安全路经Travel 最短路+并查集
    【BZOJ4560】[JLoi2016]字符串覆盖 KMP+状压DP
    【BZOJ2124】等差子序列 树状数组维护hash值
    MDX导航结构层次:《Microsoft SQL Server 2008 MDX Step by Step》学习笔记九
  • 原文地址:https://www.cnblogs.com/kaml8/p/12700138.html
Copyright © 2020-2023  润新知