From 24d943fe431d02480f1f46f52cd16b239bfe5e36 Mon Sep 17 00:00:00 2001 From: liu <liujiatong112@163.com> Date: Tue, 5 Dec 2023 17:58:23 +0800 Subject: [PATCH] =?UTF-8?q?=E9=97=AE=E8=AF=8A=E5=A4=A7=E5=8E=85=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 1 + virtual-patient-common/pom.xml | 6 +++ .../constant/UserTokenConstant.java | 3 +- virtual-patient-web/pom.xml | 1 + .../controller/WebSocketServer.java | 26 ++++++----- .../pojo/vo/AskPhysicalResultReqVO.java | 1 - .../service/impl/DiagnoseHallServiceImpl.java | 13 +++--- .../usermanage/UserResourceCheck.java | 45 +++++++++++++++++++ .../usermanage/UserWebSocketDTO.java | 1 + 9 files changed, 75 insertions(+), 22 deletions(-) create mode 100644 virtual-patient-web/src/main/java/com/supervision/usermanage/UserResourceCheck.java diff --git a/pom.xml b/pom.xml index a4a59a2e..48b22f29 100644 --- a/pom.xml +++ b/pom.xml @@ -43,6 +43,7 @@ <freemarker.version>2.3.31</freemarker.version> <mysql-connector-java.version>8.0.26</mysql-connector-java.version> <io-swagger.version>1.5.22</io-swagger.version> + <lock4j.version>2.2.5</lock4j.version> </properties> <dependencyManagement> diff --git a/virtual-patient-common/pom.xml b/virtual-patient-common/pom.xml index 39517bdf..4eb50d36 100644 --- a/virtual-patient-common/pom.xml +++ b/virtual-patient-common/pom.xml @@ -38,6 +38,12 @@ <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </dependency> + <!--redis分布式锁 https://gitee.com/baomidou/lock4j --> + <dependency> + <groupId>com.baomidou</groupId> + <artifactId>lock4j-redis-template-spring-boot-starter</artifactId> + <version>${lock4j.version}</version> + </dependency> <!-- 其他依赖 --> <dependency> diff --git a/virtual-patient-common/src/main/java/com/supervision/constant/UserTokenConstant.java b/virtual-patient-common/src/main/java/com/supervision/constant/UserTokenConstant.java index 2e1d4769..a45b5bd2 100644 --- a/virtual-patient-common/src/main/java/com/supervision/constant/UserTokenConstant.java +++ b/virtual-patient-common/src/main/java/com/supervision/constant/UserTokenConstant.java @@ -1,7 +1,8 @@ package com.supervision.constant; public interface UserTokenConstant { - String USER_ID_CACHE = "USER:ID:CACHE"; + String USER_WEBSOCKET_CACHE = "USER:ID:CACHE"; String KICK_CHANNEL = "USER:KICK:CHANNEL"; + } diff --git a/virtual-patient-web/pom.xml b/virtual-patient-web/pom.xml index 34155a28..4830043f 100644 --- a/virtual-patient-web/pom.xml +++ b/virtual-patient-web/pom.xml @@ -58,6 +58,7 @@ <artifactId>spring-boot-starter-websocket</artifactId> </dependency> + </dependencies> <build> diff --git a/virtual-patient-web/src/main/java/com/supervision/controller/WebSocketServer.java b/virtual-patient-web/src/main/java/com/supervision/controller/WebSocketServer.java index 05b1b078..0aa39942 100644 --- a/virtual-patient-web/src/main/java/com/supervision/controller/WebSocketServer.java +++ b/virtual-patient-web/src/main/java/com/supervision/controller/WebSocketServer.java @@ -2,12 +2,11 @@ package com.supervision.controller; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; -import cn.hutool.json.JSONUtil; import com.supervision.constant.UserTokenConstant; -import com.supervision.usermanage.UserWebSocketDTO; -import lombok.RequiredArgsConstructor; +import com.supervision.usermanage.UserResourceCheck; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; @@ -28,16 +27,19 @@ public class WebSocketServer { //concurrent包的线程安全Set,用来存放每个客户端对应的WebSocketServer对象。 private static final ConcurrentHashMap<String, Session> SESSION_POOL = new ConcurrentHashMap<>(); + @Value("${human.resourceMaxNumber}") + private String resourceNumber; + + @Autowired + private UserResourceCheck userResourceCheck; + /** * 有客户端连接成功 */ @OnOpen - public void onOpen(Session session, @PathParam(value = "uid") String uid) throws IOException { - log.info("用户:{}登录,缓存到Redis", uid); - // 链接之前先把之前的用户踢下线(ignoreSessionId防止把当前用户踢下线) - redisTemplate.convertAndSend(UserTokenConstant.KICK_CHANNEL, JSONUtil.toJsonStr(new UserWebSocketDTO(uid, session.getId()))); + public void onOpen(Session session, @PathParam(value = "uid") String uid) { + userResourceCheck.achieveDiagnoseResourceAndOpenConnection(uid, session); SESSION_POOL.put(uid, session); - redisTemplate.opsForHash().put(UserTokenConstant.USER_ID_CACHE, uid, session.getId()); } /** @@ -45,9 +47,9 @@ public class WebSocketServer { */ @OnClose public void onClose(Session session, @PathParam(value = "uid") String uid) { - redisTemplate.opsForHash().delete(UserTokenConstant.USER_ID_CACHE, uid, session.getId()); + redisTemplate.opsForHash().delete(UserTokenConstant.USER_WEBSOCKET_CACHE, uid, session.getId()); SESSION_POOL.remove(uid); - log.info("用户:{}关闭,从Redis中移除,当前连接数为:{}", uid, redisTemplate.opsForHash().size(UserTokenConstant.USER_ID_CACHE)); + log.info("用户:{}关闭,从Redis中移除,当前连接数为:{}", uid, redisTemplate.opsForHash().size(UserTokenConstant.USER_WEBSOCKET_CACHE)); } /** @@ -55,9 +57,9 @@ public class WebSocketServer { */ @OnError public void onError(Session session, @PathParam(value = "uid") String uid, Throwable throwable) { - redisTemplate.opsForHash().delete(UserTokenConstant.USER_ID_CACHE, uid, session.getId()); + redisTemplate.opsForHash().delete(UserTokenConstant.USER_WEBSOCKET_CACHE, uid, session.getId()); SESSION_POOL.remove(uid); - log.error("用户:{}发生错误,从Redis中移除,当前连接数为:{}", uid, redisTemplate.opsForHash().size(UserTokenConstant.USER_ID_CACHE), throwable); + log.error("用户:{}发生错误,从Redis中移除,当前连接数为:{}", uid, redisTemplate.opsForHash().size(UserTokenConstant.USER_WEBSOCKET_CACHE), throwable); } // 实现一个方法用于踢下线用户,走的是Redis的消息队列 diff --git a/virtual-patient-web/src/main/java/com/supervision/pojo/vo/AskPhysicalResultReqVO.java b/virtual-patient-web/src/main/java/com/supervision/pojo/vo/AskPhysicalResultReqVO.java index d30311b1..8174b7b7 100644 --- a/virtual-patient-web/src/main/java/com/supervision/pojo/vo/AskPhysicalResultReqVO.java +++ b/virtual-patient-web/src/main/java/com/supervision/pojo/vo/AskPhysicalResultReqVO.java @@ -18,7 +18,6 @@ public class AskPhysicalResultReqVO { private String locationCode; @ApiModelProperty("初步诊断ID") - @NotBlank(message = "初步诊断ID不能为空") private String primaryId; @NotBlank(message = "流程ID不能为空") diff --git a/virtual-patient-web/src/main/java/com/supervision/service/impl/DiagnoseHallServiceImpl.java b/virtual-patient-web/src/main/java/com/supervision/service/impl/DiagnoseHallServiceImpl.java index 586c1eda..9bbcf208 100644 --- a/virtual-patient-web/src/main/java/com/supervision/service/impl/DiagnoseHallServiceImpl.java +++ b/virtual-patient-web/src/main/java/com/supervision/service/impl/DiagnoseHallServiceImpl.java @@ -1,8 +1,9 @@ package com.supervision.service.impl; -import cn.hutool.core.util.ObjectUtil; +import com.baomidou.lock.annotation.Lock4j; import com.supervision.constant.UserTokenConstant; import com.supervision.service.DiagnoseHallService; +import com.supervision.usermanage.UserResourceCheck; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; @@ -14,17 +15,13 @@ import org.springframework.stereotype.Service; @Slf4j public class DiagnoseHallServiceImpl implements DiagnoseHallService { - private final RedisTemplate<String,String> redisTemplate; - - @Value("${human.resourceMaxNumber}") - private String resourceNumber; + private final UserResourceCheck userResourceCheck; + @Lock4j(name = "achieveDiagnoseResource") @Override public boolean achieveDiagnoseResource() { - long humanMaxNumber = Long.parseLong(resourceNumber); - long currentUserNum = redisTemplate.opsForHash().size(UserTokenConstant.USER_ID_CACHE); // 如果小于数字人最大连接数,则可以连接 - return currentUserNum <= humanMaxNumber; + return userResourceCheck.achieveDiagnoseResource(); } } diff --git a/virtual-patient-web/src/main/java/com/supervision/usermanage/UserResourceCheck.java b/virtual-patient-web/src/main/java/com/supervision/usermanage/UserResourceCheck.java new file mode 100644 index 00000000..4d18a7ea --- /dev/null +++ b/virtual-patient-web/src/main/java/com/supervision/usermanage/UserResourceCheck.java @@ -0,0 +1,45 @@ +package com.supervision.usermanage; + +import cn.hutool.json.JSONUtil; +import com.baomidou.lock.annotation.Lock4j; +import com.supervision.constant.UserTokenConstant; +import com.supervision.exception.BusinessException; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; + +import javax.websocket.*; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@RequiredArgsConstructor +public class UserResourceCheck { + + @Value("${human.resourceMaxNumber}") + private String resourceNumber; + + private final RedisTemplate<String, String> redisTemplate; + + @Lock4j(name = "achieveDiagnoseResource") + public boolean achieveDiagnoseResource() { + long humanMaxNumber = Long.parseLong(resourceNumber); + long currentSize = redisTemplate.opsForHash().size(UserTokenConstant.USER_WEBSOCKET_CACHE); + // 如果小于数字人最大连接数,则可以连接 + return currentSize < humanMaxNumber; + } + + @Lock4j(name = "achieveDiagnoseResourceAndOpenConnection") + public void achieveDiagnoseResourceAndOpenConnection(String uid, Session session){ + // 如果小于数字人最大连接数,则可以连接 + if (!achieveDiagnoseResource()) { + throw new BusinessException("暂时没有资源,建立连接失败"); + } + log.info("用户:{}登录,缓存到Redis", uid); + // 链接之前先把之前的用户踢下线(ignoreSessionId防止把当前用户踢下线) + // 注意,这里如果用户没有进到问诊页面,只是在问诊大厅时,是不会被踢掉的.(因为这时没有建立websocket连接) + redisTemplate.convertAndSend(UserTokenConstant.KICK_CHANNEL, JSONUtil.toJsonStr(new UserWebSocketDTO(uid, session.getId()))); + redisTemplate.opsForHash().put(UserTokenConstant.USER_WEBSOCKET_CACHE, uid, session.getId()); + } +} diff --git a/virtual-patient-web/src/main/java/com/supervision/usermanage/UserWebSocketDTO.java b/virtual-patient-web/src/main/java/com/supervision/usermanage/UserWebSocketDTO.java index 42a50b7a..063401f1 100644 --- a/virtual-patient-web/src/main/java/com/supervision/usermanage/UserWebSocketDTO.java +++ b/virtual-patient-web/src/main/java/com/supervision/usermanage/UserWebSocketDTO.java @@ -13,4 +13,5 @@ public class UserWebSocketDTO { * 忽略提除的ID */ private String ignoreSessionId; + }