作者 crossoverJie

:sparkles: Introducing new features.新增拒绝重复登录2

@@ -47,29 +47,26 @@ public class CIMClient { @@ -47,29 +47,26 @@ public class CIMClient {
47 private SocketChannel channel; 47 private SocketChannel channel;
48 48
49 @Autowired 49 @Autowired
50 - private RouteRequest routeRequest ; 50 + private RouteRequest routeRequest;
51 51
52 @PostConstruct 52 @PostConstruct
53 - public void start() { 53 + public void start() throws Exception {
54 54
55 - try {  
56 - //登录 + 获取可以使用的服务器 ip+port  
57 - CIMServerResVO.ServerInfo cimServer = userLogin(); 55 + //登录 + 获取可以使用的服务器 ip+port
  56 + CIMServerResVO.ServerInfo cimServer = userLogin();
58 57
59 - //启动客户端  
60 - startClient(cimServer); 58 + //启动客户端
  59 + startClient(cimServer);
61 60
62 - //向服务端注册  
63 - loginCIMServer(); 61 + //向服务端注册
  62 + loginCIMServer();
64 63
65 - }catch (Exception e){  
66 - LOGGER.error("Exception",e);  
67 - }  
68 64
69 } 65 }
70 66
71 /** 67 /**
72 * 启动客户端 68 * 启动客户端
  69 + *
73 * @param cimServer 70 * @param cimServer
74 * @throws InterruptedException 71 * @throws InterruptedException
75 */ 72 */
@@ -89,13 +86,14 @@ public class CIMClient { @@ -89,13 +86,14 @@ public class CIMClient {
89 86
90 /** 87 /**
91 * 登录+路由服务器 88 * 登录+路由服务器
  89 + *
92 * @return 路由服务器信息 90 * @return 路由服务器信息
93 * @throws Exception 91 * @throws Exception
94 */ 92 */
95 private CIMServerResVO.ServerInfo userLogin() throws Exception { 93 private CIMServerResVO.ServerInfo userLogin() throws Exception {
96 - LoginReqVO loginReqVO = new LoginReqVO(userId,userName) ; 94 + LoginReqVO loginReqVO = new LoginReqVO(userId, userName);
97 CIMServerResVO.ServerInfo cimServer = routeRequest.getCIMServer(loginReqVO); 95 CIMServerResVO.ServerInfo cimServer = routeRequest.getCIMServer(loginReqVO);
98 - LOGGER.info("cimServer=[{}]",cimServer.toString()); 96 + LOGGER.info("cimServer=[{}]", cimServer.toString());
99 return cimServer; 97 return cimServer;
100 } 98 }
101 99
@@ -119,8 +117,8 @@ public class CIMClient { @@ -119,8 +117,8 @@ public class CIMClient {
119 * @param msg 117 * @param msg
120 */ 118 */
121 public void sendStringMsg(String msg) { 119 public void sendStringMsg(String msg) {
122 - ByteBuf message = Unpooled.buffer(msg.getBytes().length) ;  
123 - message.writeBytes(msg.getBytes()) ; 120 + ByteBuf message = Unpooled.buffer(msg.getBytes().length);
  121 + message.writeBytes(msg.getBytes());
124 ChannelFuture future = channel.writeAndFlush(message); 122 ChannelFuture future = channel.writeAndFlush(message);
125 future.addListener((ChannelFutureListener) channelFuture -> 123 future.addListener((ChannelFutureListener) channelFuture ->
126 LOGGER.info("客户端手动发消息成功={}", msg)); 124 LOGGER.info("客户端手动发消息成功={}", msg));
@@ -2,12 +2,12 @@ package com.crossoverjie.cim.client.service.impl; @@ -2,12 +2,12 @@ package com.crossoverjie.cim.client.service.impl;
2 2
3 import com.alibaba.fastjson.JSON; 3 import com.alibaba.fastjson.JSON;
4 import com.alibaba.fastjson.JSONObject; 4 import com.alibaba.fastjson.JSONObject;
  5 +import com.crossoverjie.cim.client.config.AppConfiguration;
5 import com.crossoverjie.cim.client.service.RouteRequest; 6 import com.crossoverjie.cim.client.service.RouteRequest;
6 import com.crossoverjie.cim.client.vo.req.GroupReqVO; 7 import com.crossoverjie.cim.client.vo.req.GroupReqVO;
7 import com.crossoverjie.cim.client.vo.req.LoginReqVO; 8 import com.crossoverjie.cim.client.vo.req.LoginReqVO;
8 import com.crossoverjie.cim.client.vo.res.CIMServerResVO; 9 import com.crossoverjie.cim.client.vo.res.CIMServerResVO;
9 import com.crossoverjie.cim.common.enums.StatusEnum; 10 import com.crossoverjie.cim.common.enums.StatusEnum;
10 -import com.crossoverjie.cim.common.exception.CIMException;  
11 import okhttp3.*; 11 import okhttp3.*;
12 import org.slf4j.Logger; 12 import org.slf4j.Logger;
13 import org.slf4j.LoggerFactory; 13 import org.slf4j.LoggerFactory;
@@ -40,6 +40,9 @@ public class RouteRequestImpl implements RouteRequest { @@ -40,6 +40,9 @@ public class RouteRequestImpl implements RouteRequest {
40 @Value("${cim.server.route.request.url}") 40 @Value("${cim.server.route.request.url}")
41 private String serverRouteRequestUrl; 41 private String serverRouteRequestUrl;
42 42
  43 + @Autowired
  44 + private AppConfiguration appConfiguration ;
  45 +
43 @Override 46 @Override
44 public void sendGroupMsg(GroupReqVO groupReqVO) throws Exception { 47 public void sendGroupMsg(GroupReqVO groupReqVO) throws Exception {
45 48
@@ -82,7 +85,8 @@ public class RouteRequestImpl implements RouteRequest { @@ -82,7 +85,8 @@ public class RouteRequestImpl implements RouteRequest {
82 85
83 //重复登录 86 //重复登录
84 if (cimServerResVO.getCode().equals(StatusEnum.REPEAT_LOGIN.getCode())){ 87 if (cimServerResVO.getCode().equals(StatusEnum.REPEAT_LOGIN.getCode())){
85 - throw new CIMException(StatusEnum.REPEAT_LOGIN) ; 88 + LOGGER.error(appConfiguration.getUserName() + ":" + StatusEnum.REPEAT_LOGIN.getMessage());
  89 + System.exit(-1);
86 } 90 }
87 91
88 if (!cimServerResVO.getCode().equals(StatusEnum.SUCCESS.getCode())){ 92 if (!cimServerResVO.getCode().equals(StatusEnum.SUCCESS.getCode())){
@@ -8,12 +8,22 @@ swagger.enable = true @@ -8,12 +8,22 @@ swagger.enable = true
8 8
9 logging.level.root=info 9 logging.level.root=info
10 10
  11 +
  12 +###=======生产模拟======###
11 # 群发消息 13 # 群发消息
12 cim.group.route.request.url=http://45.78.28.220:8083/groupRoute 14 cim.group.route.request.url=http://45.78.28.220:8083/groupRoute
13 15
14 # 登录并获取服务器ip+port 16 # 登录并获取服务器ip+port
15 cim.server.route.request.url=http://45.78.28.220:8083/login 17 cim.server.route.request.url=http://45.78.28.220:8083/login
16 18
  19 +
  20 +###=======本地模拟======###
  21 +## 群发消息
  22 +#cim.group.route.request.url=http://localhost:8083/groupRoute
  23 +#
  24 +## 登录并获取服务器ip+port
  25 +#cim.server.route.request.url=http://localhost:8083/login
  26 +
17 # 客户端唯一ID 27 # 客户端唯一ID
18 cim.user.id=1545574841528 28 cim.user.id=1545574841528
19 cim.user.userName=zhangsan 29 cim.user.userName=zhangsan
@@ -20,5 +20,10 @@ public final class Constant { @@ -20,5 +20,10 @@ public final class Constant {
20 */ 20 */
21 public final static String ROUTE_PREFIX = "cim-route:"; 21 public final static String ROUTE_PREFIX = "cim-route:";
22 22
  23 + /**
  24 + * 登录状态前缀
  25 + */
  26 + public final static String LOGIN_STATUS_PREFIX = "login-status";
  27 +
23 28
24 } 29 }
@@ -17,5 +17,23 @@ public interface UserInfoCacheService { @@ -17,5 +17,23 @@ public interface UserInfoCacheService {
17 * @return 17 * @return
18 * @throws Exception 18 * @throws Exception
19 */ 19 */
20 - CIMUserInfo loadUserInfoByUserId(long userId) throws Exception ; 20 + CIMUserInfo loadUserInfoByUserId(Long userId) throws Exception ;
  21 +
  22 + /**
  23 + * 保存和检查用户登录情况
  24 + * @param userId userId 用户唯一 ID
  25 + * @return true 为可以登录 false 为已经登录
  26 + * @throws Exception
  27 + */
  28 + boolean saveAndCheckUserLoginStatus(Long userId) throws Exception ;
  29 +
  30 + /**
  31 + * 清除用户的登录状态
  32 + * @param userId
  33 + * @throws Exception
  34 + */
  35 + void removeLoginStatus(Long userId) throws Exception ;
  36 +
  37 +
  38 +
21 } 39 }
@@ -68,14 +68,6 @@ public class AccountServiceRedisImpl implements AccountService { @@ -68,14 +68,6 @@ public class AccountServiceRedisImpl implements AccountService {
68 68
69 @Override 69 @Override
70 public boolean login(LoginReqVO loginReqVO) throws Exception { 70 public boolean login(LoginReqVO loginReqVO) throws Exception {
71 -  
72 - //先判断是否已经登录,第一次登录 cimUserInfo 为空  
73 - CIMUserInfo cimUserInfo = userInfoCacheService.loadUserInfoByUserId(loginReqVO.getUserId());  
74 - if (cimUserInfo != null){  
75 - //重复登录  
76 - return false ;  
77 - }  
78 -  
79 //再去Redis里查询 71 //再去Redis里查询
80 String key = ACCOUNT_PREFIX + loginReqVO.getUserId(); 72 String key = ACCOUNT_PREFIX + loginReqVO.getUserId();
81 String userName = redisTemplate.opsForValue().get(key); 73 String userName = redisTemplate.opsForValue().get(key);
@@ -86,6 +78,14 @@ public class AccountServiceRedisImpl implements AccountService { @@ -86,6 +78,14 @@ public class AccountServiceRedisImpl implements AccountService {
86 if (!userName.equals(loginReqVO.getUserName())) { 78 if (!userName.equals(loginReqVO.getUserName())) {
87 return false; 79 return false;
88 } 80 }
  81 +
  82 + //登录成功,保存登录状态
  83 + boolean status = userInfoCacheService.saveAndCheckUserLoginStatus(loginReqVO.getUserId());
  84 + if (status == false){
  85 + //重复登录
  86 + return false;
  87 + }
  88 +
89 return true; 89 return true;
90 } 90 }
91 91
@@ -148,6 +148,10 @@ public class AccountServiceRedisImpl implements AccountService { @@ -148,6 +148,10 @@ public class AccountServiceRedisImpl implements AccountService {
148 148
149 @Override 149 @Override
150 public void offLine(Long userId) throws Exception { 150 public void offLine(Long userId) throws Exception {
  151 + //删除路由
151 redisTemplate.delete(ROUTE_PREFIX + userId) ; 152 redisTemplate.delete(ROUTE_PREFIX + userId) ;
  153 +
  154 + //删除登录状态
  155 + userInfoCacheService.removeLoginStatus(userId);
152 } 156 }
153 } 157 }
@@ -10,6 +10,7 @@ import java.util.Map; @@ -10,6 +10,7 @@ import java.util.Map;
10 import java.util.concurrent.ConcurrentHashMap; 10 import java.util.concurrent.ConcurrentHashMap;
11 11
12 import static com.crossoverjie.cim.route.constant.Constant.ACCOUNT_PREFIX; 12 import static com.crossoverjie.cim.route.constant.Constant.ACCOUNT_PREFIX;
  13 +import static com.crossoverjie.cim.route.constant.Constant.LOGIN_STATUS_PREFIX;
13 14
14 /** 15 /**
15 * Function: 16 * Function:
@@ -30,7 +31,7 @@ public class UserInfoCacheServiceImpl implements UserInfoCacheService { @@ -30,7 +31,7 @@ public class UserInfoCacheServiceImpl implements UserInfoCacheService {
30 private RedisTemplate<String,String> redisTemplate ; 31 private RedisTemplate<String,String> redisTemplate ;
31 32
32 @Override 33 @Override
33 - public CIMUserInfo loadUserInfoByUserId(long userId) throws Exception { 34 + public CIMUserInfo loadUserInfoByUserId(Long userId) throws Exception {
34 35
35 //优先从本地缓存获取 36 //优先从本地缓存获取
36 CIMUserInfo cimUserInfo = USER_INFO_MAP.get(userId); 37 CIMUserInfo cimUserInfo = USER_INFO_MAP.get(userId);
@@ -47,4 +48,21 @@ public class UserInfoCacheServiceImpl implements UserInfoCacheService { @@ -47,4 +48,21 @@ public class UserInfoCacheServiceImpl implements UserInfoCacheService {
47 48
48 return cimUserInfo; 49 return cimUserInfo;
49 } 50 }
  51 +
  52 + @Override
  53 + public boolean saveAndCheckUserLoginStatus(Long userId) throws Exception {
  54 +
  55 + Long add = redisTemplate.opsForSet().add(LOGIN_STATUS_PREFIX, userId.toString());
  56 + if (add == 0){
  57 + return false ;
  58 + }else {
  59 + return true ;
  60 + }
  61 + }
  62 +
  63 + @Override
  64 + public void removeLoginStatus(Long userId) throws Exception {
  65 + redisTemplate.opsForSet().remove(LOGIN_STATUS_PREFIX,userId.toString()) ;
  66 + }
  67 +
50 } 68 }
  1 +package com.crossoverjie.cim.route.service.impl;
  2 +
  3 +import com.crossoverjie.cim.route.RouteApplication;
  4 +import com.crossoverjie.cim.route.service.UserInfoCacheService;
  5 +import org.junit.Test;
  6 +import org.junit.runner.RunWith;
  7 +import org.slf4j.Logger;
  8 +import org.slf4j.LoggerFactory;
  9 +import org.springframework.beans.factory.annotation.Autowired;
  10 +import org.springframework.boot.test.context.SpringBootTest;
  11 +import org.springframework.test.context.junit4.SpringRunner;
  12 +
  13 +@SpringBootTest(classes = RouteApplication.class)
  14 +@RunWith(SpringRunner.class)
  15 +public class UserInfoCacheServiceImplTest {
  16 +
  17 + private final static Logger LOGGER = LoggerFactory.getLogger(UserInfoCacheServiceImplTest.class);
  18 +
  19 +
  20 + @Autowired
  21 + private UserInfoCacheService userInfoCacheService;
  22 +
  23 + @Test
  24 + public void checkUserLoginStatus() throws Exception {
  25 + boolean status = userInfoCacheService.saveAndCheckUserLoginStatus(2000L);
  26 + LOGGER.info("status={}", status);
  27 + }
  28 +
  29 + @Test
  30 + public void removeLoginStatus() throws Exception {
  31 + userInfoCacheService.removeLoginStatus(2000L);
  32 + }
  33 +
  34 +}