项目结构:pc管理端,pc机构端,vue,springboot,mysql,activeMq,redis
项目需求:需要记录用户登陆时间,登出时间,登陆时长
注:一般用户不会走退出登录操作,会直接关闭页面,或者关闭浏览器
人员:java后端(不懂前端)
解决方案:
假设pc管理端 admin账户ID为1 用户标识为 1-1(管理端-用户ID)
步骤一:先生成用户身份信息
1、用户登陆后将token存进redis,数据结构为string
(其实可以把token和用户标识存到一块,改的我麻了,就这样吧)
步骤二:监听用户在线状态
这有个坑,本来想的是前端定时刷新token状态,但是用户切换tab页后就不调了,明显不行!
1、写一个定时任务的方法,五分钟执行一次
//每五分钟执行一次 判断用户在线状态,
//从redis中查询在线的用户,然后获取mqtt的消费者数量,如果为0,则清除token
@Scheduled(cron = "0 0/5 * * * ?")
// @Scheduled(cron = "0/30 * * * * ?")
public void run() {
SetOperations<String, String> sSet = redisTemplate.opsForSet();
Set<String> cxHxsUserToken = sSet.members(redisUserTokenSet);
String data = DateUtil.getData();
for (String userTypeId : cxHxsUserToken) {
String url = activemqOnlineInfo + userTypeId;
String s = ActiveMQUtil.sendPost(url);
// log.info("定时任务执行:" + s);
Integer status = JSONObject.parseObject(s).getInteger("status");
//如果没有消费者,则删除redis记录,并且记录下线时间
if (status.intValue() == 404 || JSONObject.parseObject(s).getJSONObject("value").getInteger("ConsumerCount").intValue()==0) {
sSet.remove(redisUserTokenSet, userTypeId);
redisTemplate.delete(userTypeId);
String[] split = userTypeId.split("-");
threadPoolExecutor.execute(() -> {
// TODO 此处修改数据库登陆状态
});
}
}
}
补充数据:
redisUserTokenSet = cx_hxs_user_token
activemqOnlineInfo = http://127.0.0.1:8161/api/jolokia/read/org.apache.activemq:type=Broker,brokerName=localhost,destinationType=Queue,destinationName=
ActiveMQUtil.sendPost
import lombok.extern.slf4j.Slf4j;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Base64;
@Slf4j
public class ActiveMQUtil {
public static void main(String[] args) {
String url ="http://127.0.0.1:8161/api/jolokia/read/org.apache.activemq:type=Broker,brokerName=localhost,destinationType=Queue,destinationName=1-1";
String mpa =sendPost(url);
System.err.println(mpa);
}
/***
* 获取消息面板中对应消费者的各种数据
* 返回Map中数据格式
* @return
*/
public static String sendPost(String url){
String result = "";
try {
URL realUrl = new URL(url);
String Authorization = Base64.getEncoder().encodeToString("admin:admin".getBytes());
// log.info(Authorization);
HttpURLConnection conn = (HttpURLConnection)realUrl.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/json");
conn.setRequestProperty("Accept-Encoding", "gzip, deflate");
conn.setRequestProperty("Accept-Language", "zh-CN,zh;q=0.9");
conn.setRequestProperty("Authorization", "Basic "+Authorization);
conn.setRequestProperty("Cache-Control", "max-age=0");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("Host", "application/json; charset=utf-8");
conn.setRequestProperty("Upgrade-Insecure-Requests", "1");
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream(),"utf-8"));
String line;
while((line = in.readLine()) != null){
result +="\n" + line;
}
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
}
主题代码完成,在拦截器中校验下 redis中有没有token
//判断token是否存在
try {
String userRedisKey = "1-1"
Boolean aBoolean = redisTemplate.hasKey(userRedisKey);
if(!aBoolean){
getMsg("请登录后访问",request,response);
return false;
}
}catch (Exception e){
log.error("登陆报错:",e);
getMsg("请登录后访问",request,response);
return false;
}
可以再补充一个退出登录的功能,还没写,
搞定,虽然代码马马虎虎,但功能实现了,后边再优化;
各位大佬多多指点,请评论区留言