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
原文地址:https://www.cnblogs.com/kaml8/p/12700138.html
- 解决服务器SID引起虚拟机不能加入AD域用户,无法远程登录的问题
- 【Python环境】如何使用 Docker 快速配置数据科学开发环境?
- Java中UUID的2种创建方法——有代码实例
- 使用“消息服务框架”(MSF)实现分布式事务的三阶段提交协议(电商创建订单的示例)
- Android基础总结(3)——UI界面布局
- 常见.NET功能代码汇总 (2)
- 问题系列之Java中删除有序List的重复数据——提供两种方法
- 二叉树的基本概念和遍历
- Java中MD5加密算法实现方法——附上具体代码
- 新手,Visual Studio 2015 配置Boost库,如何编译和选择,遇到无法打开文件“libboost_thread-vc140-mt-gd-1_63.lib“的解决办法
- Java中处理正则表达式的工具类——总有一个适合你
- 【Spark研究】用Apache Spark进行大数据处理第一部分:入门介绍
- “一切都是消息”--MSF(消息服务框架)入门简介
- 【Spark研究】用Apache Spark进行大数据处理第二部分:Spark SQL
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- android实现录屏小功能
- Android控件CardView实现卡片效果
- 非常好看的android音量旋钮
- Android实现按钮拖拽还原功能
- 百度地图实现小车规划路线后平滑移动功能
- frp内网穿透部署搭建教程,内网端口暴露给了外网
- Android使用Intent的Action和Data属性实现点击按钮跳转到拨打电话和发送短信界面
- Linux安装Collabora Online让NextCloud支持Office在线编辑
- 教你在CentOS7安装Vuze(Azureus)
- Pwn-EXP模板
- Linux学习随手记
- PHP session用法其实很简单
- 爬虫代理适合的业务和场景
- Flutter基础widgets教程-OverflowBox篇
- iOS音视频接入- TRTC语音聊天室