From e52c30cff0d43adcfe2b2e39d5f439fe8296dba9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BF=9E=E6=89=AC?= Date: Fri, 11 Aug 2023 11:40:56 +0800 Subject: [PATCH] websocket --- .../com/cool/store/request/CallUpReq.java | 29 +++ coolstore-partner-service/pom.xml | 5 + .../cool/store/handler/WebSocketServer.java | 166 ++++++++++++++++++ .../com/cool/store/service/CallService.java | 13 ++ .../store/service/impl/CallServiceImpl.java | 20 +++ .../store/config/TokenValidateFilter.java | 4 +- .../cool/store/config/WebSocketConfig.java | 17 ++ .../cool/store/controller/CallController.java | 37 ++++ 8 files changed, 290 insertions(+), 1 deletion(-) create mode 100644 coolstore-partner-model/src/main/java/com/cool/store/request/CallUpReq.java create mode 100644 coolstore-partner-service/src/main/java/com/cool/store/handler/WebSocketServer.java create mode 100644 coolstore-partner-service/src/main/java/com/cool/store/service/CallService.java create mode 100644 coolstore-partner-service/src/main/java/com/cool/store/service/impl/CallServiceImpl.java create mode 100644 coolstore-partner-webb/src/main/java/com/cool/store/config/WebSocketConfig.java create mode 100644 coolstore-partner-webb/src/main/java/com/cool/store/controller/CallController.java diff --git a/coolstore-partner-model/src/main/java/com/cool/store/request/CallUpReq.java b/coolstore-partner-model/src/main/java/com/cool/store/request/CallUpReq.java new file mode 100644 index 000000000..90447ade0 --- /dev/null +++ b/coolstore-partner-model/src/main/java/com/cool/store/request/CallUpReq.java @@ -0,0 +1,29 @@ +package com.cool.store.request; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @Author: young.yu + * @Date: 2023-08-10 19:24 + * @Description: + */ +@Data +@ApiModel +public class CallUpReq { + @ApiModelProperty(value = "线索id", required = true) + private String lineId; + + @ApiModelProperty(value = "呼出人用户id", required = true) + private String outgoingUserId; + + @ApiModelProperty(value = "呼出人手机号", required = true) + private String outgoingMobile; + + @ApiModelProperty(value = "接听人用户id", required = true) + private String incomingUserId; + + @ApiModelProperty(value = "接听人手机号", required = true) + private String incomingMobile; +} diff --git a/coolstore-partner-service/pom.xml b/coolstore-partner-service/pom.xml index 05dea92c7..033ef4886 100644 --- a/coolstore-partner-service/pom.xml +++ b/coolstore-partner-service/pom.xml @@ -85,6 +85,11 @@ dysmsapi20170525 2.0.1 + + + org.springframework.boot + spring-boot-starter-websocket + \ No newline at end of file diff --git a/coolstore-partner-service/src/main/java/com/cool/store/handler/WebSocketServer.java b/coolstore-partner-service/src/main/java/com/cool/store/handler/WebSocketServer.java new file mode 100644 index 000000000..8c81b69d9 --- /dev/null +++ b/coolstore-partner-service/src/main/java/com/cool/store/handler/WebSocketServer.java @@ -0,0 +1,166 @@ +package com.cool.store.handler; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; + +import javax.websocket.*; +import javax.websocket.server.PathParam; +import javax.websocket.server.ServerEndpoint; +import java.io.IOException; +import java.util.concurrent.ConcurrentHashMap; + +@Component +@Slf4j +@ServerEndpoint("/websocket/{tenantId}") +public class WebSocketServer { + + /** + * 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。 + */ + private static int onlineCount = 0; + /** + * concurrent包的线程安全Set,用来存放每个客户端对应的WebSocket对象。 + */ + private static final ConcurrentHashMap webSocketMap = new ConcurrentHashMap<>(); + /** + * 与某个客户端的连接会话,需要通过它来给客户端发送数据 + */ + private Session session; + /** + * 接收userId + */ + private String tenantId = ""; + + /** + * 连接建立成 + * 功调用的方法 + */ + @OnOpen + public void onOpen(Session session, @PathParam("tenantId") String tenantId) { + this.session = session; + this.tenantId = tenantId; + if (webSocketMap.containsKey(tenantId)) { + webSocketMap.remove(tenantId); + //加入set中 + webSocketMap.put(tenantId, this); + } else { + //加入set中 + webSocketMap.put(tenantId, this); + //在线数加1 + addOnlineCount(); + } + log.info("用户连接:" + tenantId + ",当前在线人数为:" + getOnlineCount()); + sendMessage("连接成功"); + } + + /** + * 连接关闭 + * 调用的方法 + */ + @OnClose + public void onClose() { + if (webSocketMap.containsKey(tenantId)) { + webSocketMap.remove(tenantId); + //从set中删除 + subOnlineCount(); + } + log.info("用户退出:" + tenantId + ",当前在线人数为:" + getOnlineCount()); + } + + /** + * 收到客户端消 + * 息后调用的方法 + * + * @param message 客户端发送过来的消息 + **/ + @OnMessage + public void onMessage(String message, Session session) { + log.info("用户消息:" + tenantId + ",报文:" + message); + //可以群发消息 + //消息保存到数据库、redis + if (StringUtils.isNotBlank(message)) { + try { + //解析发送的报文 + JSONObject jsonObject = JSON.parseObject(message); + //追加发送人(防止串改) + jsonObject.put("fromUserId", this.tenantId); + String toUserId = jsonObject.getString("toUserId"); + //传送给对应toUserId用户的websocket + if (StringUtils.isNotBlank(toUserId) && webSocketMap.containsKey(toUserId)) { + webSocketMap.get(toUserId).sendMessage(message); + } else { + //否则不在这个服务器上,发送到mysql或者redis + log.error("请求的userId:" + toUserId + "不在该服务器上"); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + + /** + * @param session Session + * @param error Throwable + */ + @OnError + public void onError(Session session, Throwable error) { + + log.error("用户错误:" + this.tenantId + ",原因:" + error.getMessage()); + error.printStackTrace(); + } + + /** + * 实现服务 + * 器主动推送 + */ + public void sendMessage(String message) { + try { + this.session.getBasicRemote().sendText(message); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * 发送自定 + * 义消息 + **/ + public static void sendInfo(String message, String tenantId) { + log.info("发送消息到:" + tenantId + ",报文:" + message); + if (StringUtils.isNotBlank(tenantId) && webSocketMap.containsKey(tenantId)) { + webSocketMap.get(tenantId).sendMessage(message); + } else { + log.error("用户" + tenantId + ",不在线!"); + } + } + + /** + * 获得此时的 + * 在线人数 + * + * @return int + */ + public static synchronized int getOnlineCount() { + return onlineCount; + } + + /** + * 在线人 + * 数加1 + */ + public static synchronized void addOnlineCount() { + WebSocketServer.onlineCount++; + } + + /** + * 在线人 + * 数减1 + */ + public static synchronized void subOnlineCount() { + WebSocketServer.onlineCount--; + } +} \ No newline at end of file diff --git a/coolstore-partner-service/src/main/java/com/cool/store/service/CallService.java b/coolstore-partner-service/src/main/java/com/cool/store/service/CallService.java new file mode 100644 index 000000000..3c44a5146 --- /dev/null +++ b/coolstore-partner-service/src/main/java/com/cool/store/service/CallService.java @@ -0,0 +1,13 @@ +package com.cool.store.service; + +import com.cool.store.exception.ApiException; +import com.cool.store.request.CallUpReq; + +/** + * @Author: young.yu + * @Date: 2023-08-10 18:56 + * @Description: + */ +public interface CallService { + void callUp(CallUpReq request) throws ApiException; +} diff --git a/coolstore-partner-service/src/main/java/com/cool/store/service/impl/CallServiceImpl.java b/coolstore-partner-service/src/main/java/com/cool/store/service/impl/CallServiceImpl.java new file mode 100644 index 000000000..d849573e3 --- /dev/null +++ b/coolstore-partner-service/src/main/java/com/cool/store/service/impl/CallServiceImpl.java @@ -0,0 +1,20 @@ +package com.cool.store.service.impl; + +import com.cool.store.exception.ApiException; +import com.cool.store.request.CallUpReq; +import com.cool.store.service.CallService; +import org.springframework.stereotype.Service; + +/** + * @Author: young.yu + * @Date: 2023-08-10 18:58 + * @Description: + */ +@Service +public class CallServiceImpl implements CallService { + + @Override + public void callUp(CallUpReq request) throws ApiException { + + } +} diff --git a/coolstore-partner-webb/src/main/java/com/cool/store/config/TokenValidateFilter.java b/coolstore-partner-webb/src/main/java/com/cool/store/config/TokenValidateFilter.java index ecda3ae86..eb0e7f293 100644 --- a/coolstore-partner-webb/src/main/java/com/cool/store/config/TokenValidateFilter.java +++ b/coolstore-partner-webb/src/main/java/com/cool/store/config/TokenValidateFilter.java @@ -49,7 +49,9 @@ public class TokenValidateFilter implements Filter { //腾讯音视频回调,单独做验签 "/partner/pc/video/**", //TODO 800回调地址暂时不做验证 - "/partner/pc/flow/qualificationReview/callback","/**/ecSync/ecToApplet/**"); + "/partner/pc/flow/qualificationReview/callback", + "/**/ecSync/ecToApplet/**", + "/partner/pc/websocket/**"); /** diff --git a/coolstore-partner-webb/src/main/java/com/cool/store/config/WebSocketConfig.java b/coolstore-partner-webb/src/main/java/com/cool/store/config/WebSocketConfig.java new file mode 100644 index 000000000..9d59b0d38 --- /dev/null +++ b/coolstore-partner-webb/src/main/java/com/cool/store/config/WebSocketConfig.java @@ -0,0 +1,17 @@ +package com.cool.store.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.socket.server.standard.ServerEndpointExporter; + +/** + * WebSocket的配置信息 + */ +@Configuration +public class WebSocketConfig { + @Bean + public ServerEndpointExporter serverEndpointExporter() { + + return new ServerEndpointExporter(); + } +} \ No newline at end of file diff --git a/coolstore-partner-webb/src/main/java/com/cool/store/controller/CallController.java b/coolstore-partner-webb/src/main/java/com/cool/store/controller/CallController.java new file mode 100644 index 000000000..c5069cbd5 --- /dev/null +++ b/coolstore-partner-webb/src/main/java/com/cool/store/controller/CallController.java @@ -0,0 +1,37 @@ +package com.cool.store.controller; + +import com.cool.store.exception.ApiException; +import com.cool.store.request.CallUpReq; +import com.cool.store.request.GetTipsInfoReq; +import com.cool.store.response.ResponseResult; +import com.cool.store.service.CallService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @Author: young.yu + * @Date: 2023-08-10 18:05 + * @Description: + */ +@RestController +@RequestMapping("call") +@Api(tags = "通话") +@Slf4j +public class CallController { + + @Autowired + private CallService callService; + + @PostMapping("/callUp") + @ApiOperation("呼出电话") + public ResponseResult callUp(@RequestBody CallUpReq request) throws ApiException { + callService.callUp(request); + return ResponseResult.success(); + } +}