作者 crossoverJie

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

... ... @@ -47,29 +47,26 @@ public class CIMClient {
private SocketChannel channel;
@Autowired
private RouteRequest routeRequest ;
private RouteRequest routeRequest;
@PostConstruct
public void start() {
public void start() throws Exception {
try {
//登录 + 获取可以使用的服务器 ip+port
CIMServerResVO.ServerInfo cimServer = userLogin();
//登录 + 获取可以使用的服务器 ip+port
CIMServerResVO.ServerInfo cimServer = userLogin();
//启动客户端
startClient(cimServer);
//启动客户端
startClient(cimServer);
//向服务端注册
loginCIMServer();
//向服务端注册
loginCIMServer();
}catch (Exception e){
LOGGER.error("Exception",e);
}
}
/**
* 启动客户端
*
* @param cimServer
* @throws InterruptedException
*/
... ... @@ -89,13 +86,14 @@ public class CIMClient {
/**
* 登录+路由服务器
*
* @return 路由服务器信息
* @throws Exception
*/
private CIMServerResVO.ServerInfo userLogin() throws Exception {
LoginReqVO loginReqVO = new LoginReqVO(userId,userName) ;
LoginReqVO loginReqVO = new LoginReqVO(userId, userName);
CIMServerResVO.ServerInfo cimServer = routeRequest.getCIMServer(loginReqVO);
LOGGER.info("cimServer=[{}]",cimServer.toString());
LOGGER.info("cimServer=[{}]", cimServer.toString());
return cimServer;
}
... ... @@ -119,8 +117,8 @@ public class CIMClient {
* @param msg
*/
public void sendStringMsg(String msg) {
ByteBuf message = Unpooled.buffer(msg.getBytes().length) ;
message.writeBytes(msg.getBytes()) ;
ByteBuf message = Unpooled.buffer(msg.getBytes().length);
message.writeBytes(msg.getBytes());
ChannelFuture future = channel.writeAndFlush(message);
future.addListener((ChannelFutureListener) channelFuture ->
LOGGER.info("客户端手动发消息成功={}", msg));
... ...
... ... @@ -2,12 +2,12 @@ package com.crossoverjie.cim.client.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.crossoverjie.cim.client.config.AppConfiguration;
import com.crossoverjie.cim.client.service.RouteRequest;
import com.crossoverjie.cim.client.vo.req.GroupReqVO;
import com.crossoverjie.cim.client.vo.req.LoginReqVO;
import com.crossoverjie.cim.client.vo.res.CIMServerResVO;
import com.crossoverjie.cim.common.enums.StatusEnum;
import com.crossoverjie.cim.common.exception.CIMException;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
... ... @@ -40,6 +40,9 @@ public class RouteRequestImpl implements RouteRequest {
@Value("${cim.server.route.request.url}")
private String serverRouteRequestUrl;
@Autowired
private AppConfiguration appConfiguration ;
@Override
public void sendGroupMsg(GroupReqVO groupReqVO) throws Exception {
... ... @@ -82,7 +85,8 @@ public class RouteRequestImpl implements RouteRequest {
//重复登录
if (cimServerResVO.getCode().equals(StatusEnum.REPEAT_LOGIN.getCode())){
throw new CIMException(StatusEnum.REPEAT_LOGIN) ;
LOGGER.error(appConfiguration.getUserName() + ":" + StatusEnum.REPEAT_LOGIN.getMessage());
System.exit(-1);
}
if (!cimServerResVO.getCode().equals(StatusEnum.SUCCESS.getCode())){
... ...
... ... @@ -8,12 +8,22 @@ swagger.enable = true
logging.level.root=info
###=======生产模拟======###
# 群发消息
cim.group.route.request.url=http://45.78.28.220:8083/groupRoute
# 登录并获取服务器ip+port
cim.server.route.request.url=http://45.78.28.220:8083/login
###=======本地模拟======###
## 群发消息
#cim.group.route.request.url=http://localhost:8083/groupRoute
#
## 登录并获取服务器ip+port
#cim.server.route.request.url=http://localhost:8083/login
# 客户端唯一ID
cim.user.id=1545574841528
cim.user.userName=zhangsan
... ...
... ... @@ -20,5 +20,10 @@ public final class Constant {
*/
public final static String ROUTE_PREFIX = "cim-route:";
/**
* 登录状态前缀
*/
public final static String LOGIN_STATUS_PREFIX = "login-status";
}
... ...
... ... @@ -17,5 +17,23 @@ public interface UserInfoCacheService {
* @return
* @throws Exception
*/
CIMUserInfo loadUserInfoByUserId(long userId) throws Exception ;
CIMUserInfo loadUserInfoByUserId(Long userId) throws Exception ;
/**
* 保存和检查用户登录情况
* @param userId userId 用户唯一 ID
* @return true 为可以登录 false 为已经登录
* @throws Exception
*/
boolean saveAndCheckUserLoginStatus(Long userId) throws Exception ;
/**
* 清除用户的登录状态
* @param userId
* @throws Exception
*/
void removeLoginStatus(Long userId) throws Exception ;
}
... ...
... ... @@ -68,14 +68,6 @@ public class AccountServiceRedisImpl implements AccountService {
@Override
public boolean login(LoginReqVO loginReqVO) throws Exception {
//先判断是否已经登录,第一次登录 cimUserInfo 为空
CIMUserInfo cimUserInfo = userInfoCacheService.loadUserInfoByUserId(loginReqVO.getUserId());
if (cimUserInfo != null){
//重复登录
return false ;
}
//再去Redis里查询
String key = ACCOUNT_PREFIX + loginReqVO.getUserId();
String userName = redisTemplate.opsForValue().get(key);
... ... @@ -86,6 +78,14 @@ public class AccountServiceRedisImpl implements AccountService {
if (!userName.equals(loginReqVO.getUserName())) {
return false;
}
//登录成功,保存登录状态
boolean status = userInfoCacheService.saveAndCheckUserLoginStatus(loginReqVO.getUserId());
if (status == false){
//重复登录
return false;
}
return true;
}
... ... @@ -148,6 +148,10 @@ public class AccountServiceRedisImpl implements AccountService {
@Override
public void offLine(Long userId) throws Exception {
//删除路由
redisTemplate.delete(ROUTE_PREFIX + userId) ;
//删除登录状态
userInfoCacheService.removeLoginStatus(userId);
}
}
... ...
... ... @@ -10,6 +10,7 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static com.crossoverjie.cim.route.constant.Constant.ACCOUNT_PREFIX;
import static com.crossoverjie.cim.route.constant.Constant.LOGIN_STATUS_PREFIX;
/**
* Function:
... ... @@ -30,7 +31,7 @@ public class UserInfoCacheServiceImpl implements UserInfoCacheService {
private RedisTemplate<String,String> redisTemplate ;
@Override
public CIMUserInfo loadUserInfoByUserId(long userId) throws Exception {
public CIMUserInfo loadUserInfoByUserId(Long userId) throws Exception {
//优先从本地缓存获取
CIMUserInfo cimUserInfo = USER_INFO_MAP.get(userId);
... ... @@ -47,4 +48,21 @@ public class UserInfoCacheServiceImpl implements UserInfoCacheService {
return cimUserInfo;
}
@Override
public boolean saveAndCheckUserLoginStatus(Long userId) throws Exception {
Long add = redisTemplate.opsForSet().add(LOGIN_STATUS_PREFIX, userId.toString());
if (add == 0){
return false ;
}else {
return true ;
}
}
@Override
public void removeLoginStatus(Long userId) throws Exception {
redisTemplate.opsForSet().remove(LOGIN_STATUS_PREFIX,userId.toString()) ;
}
}
... ...
package com.crossoverjie.cim.route.service.impl;
import com.crossoverjie.cim.route.RouteApplication;
import com.crossoverjie.cim.route.service.UserInfoCacheService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@SpringBootTest(classes = RouteApplication.class)
@RunWith(SpringRunner.class)
public class UserInfoCacheServiceImplTest {
private final static Logger LOGGER = LoggerFactory.getLogger(UserInfoCacheServiceImplTest.class);
@Autowired
private UserInfoCacheService userInfoCacheService;
@Test
public void checkUserLoginStatus() throws Exception {
boolean status = userInfoCacheService.saveAndCheckUserLoginStatus(2000L);
LOGGER.info("status={}", status);
}
@Test
public void removeLoginStatus() throws Exception {
userInfoCacheService.removeLoginStatus(2000L);
}
}
\ No newline at end of file
... ...