Ver código fonte

fix : 客服聊天的webSocket测试

bilingfeng 1 ano atrás
pai
commit
cc9ec194fa

+ 16 - 0
game-module/game-module-base/src/main/java/com/zanxiang/game/module/base/rpc/IKfMsgRpc.java

@@ -0,0 +1,16 @@
+package com.zanxiang.game.module.base.rpc;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-02-26
+ * @description : 客服消息rpc
+ */
+public interface IKfMsgRpc {
+
+    /**
+     * 小程序消息
+     *
+     * @param postData : 消息内容
+     */
+    void appletMsg(String postData);
+}

+ 1 - 1
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/ManageApplication.java

@@ -23,7 +23,7 @@ public class ManageApplication {
 
     public static void main(String[] args) {
         SpringApplication.run(ManageApplication.class, args);
-        System.out.println("赞象Manage服务启动成功 <导量逻辑> ( ´・・)ノ(._.`) \n" +
+        System.out.println("赞象Manage服务启动成功 <长连接测试> ( ´・・)ノ(._.`) \n" +
                 "___  ___  ___   _   _   ___  _____  _____ \n" +
                 "|  \\/  | / _ \\ | \\ | | / _ \\|  __ \\|  ___|\n" +
                 "| .  . |/ /_\\ \\|  \\| |/ /_\\ \\ |  \\/| |__  \n" +

+ 1 - 1
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/pojo/dto/AppletMsgDTO.java → game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/pojo/dto/KfAppletMsgDTO.java

@@ -8,7 +8,7 @@ import lombok.Data;
  * @description : 小程序消息
  */
 @Data
-public class AppletMsgDTO {
+public class KfAppletMsgDTO {
 
     /**
      * 回调事件消息

+ 49 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/pojo/dto/KfMsgDTO.java

@@ -0,0 +1,49 @@
+package com.zanxiang.game.module.manage.pojo.dto;
+
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-02-26
+ * @description : 客服消息
+ */
+@Data
+public class KfMsgDTO {
+
+    /**
+     * 消息id
+     */
+    private String msgId;
+
+    /**
+     * 消息类型
+     */
+    private String msgType;
+
+    /**
+     * 已读状态
+     */
+    private Boolean readStatus;
+
+    /**
+     * 房间id
+     */
+    private Long roomId;
+
+    /**
+     * 消息归属
+     */
+    private String msgOwner;
+
+    /**
+     * 消息内容
+     */
+    private String content;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+}

+ 15 - 1
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/rpc/impl/KfMsgRpcImpl.java

@@ -1,9 +1,23 @@
 package com.zanxiang.game.module.manage.rpc.impl;
 
+import com.zanxiang.game.module.base.rpc.IKfMsgRpc;
+import com.zanxiang.game.module.manage.service.IKfRoomMsgService;
+import org.apache.dubbo.config.annotation.DubboService;
+import org.springframework.beans.factory.annotation.Autowired;
+
 /**
  * @author : lingfeng
  * @time : 2024-02-26
  * @description : 客服消息rpc接口
  */
-public class KfMsgRpcImpl {
+@DubboService
+public class KfMsgRpcImpl implements IKfMsgRpc {
+
+    @Autowired
+    private IKfRoomMsgService kfRoomMsgService;
+
+    @Override
+    public void appletMsg(String postData) {
+        kfRoomMsgService.appletMsg(postData);
+    }
 }

+ 7 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/IKfRoomMsgService.java

@@ -9,4 +9,11 @@ import com.zanxiang.game.module.mybatis.entity.KfRoomMsg;
  * @description : 客服房间消息
  */
 public interface IKfRoomMsgService extends IService<KfRoomMsg> {
+
+    /**
+     * 接收到SDK转发的小程序消息
+     *
+     * @param postData : 消息内容
+     */
+    void appletMsg(String postData);
 }

+ 101 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/api/KfWxApiService.java

@@ -0,0 +1,101 @@
+package com.zanxiang.game.module.manage.service.api;
+
+import com.zanxiang.game.module.base.ServerInfo;
+import com.zanxiang.game.module.base.pojo.enums.HttpStatusEnum;
+import com.zanxiang.game.module.base.rpc.IWxApiServiceRpc;
+import com.zanxiang.game.module.manage.pojo.dto.GameAppletDTO;
+import com.zanxiang.game.module.manage.pojo.dto.KfUploadTempMediaDTO;
+import com.zanxiang.module.util.JsonUtil;
+import com.zanxiang.module.util.exception.BaseException;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.Resource;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Service;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-02-26
+ * @description : 客服聊天腾讯API接口
+ */
+@Slf4j
+@Service
+public class KfWxApiService {
+
+    @Autowired
+    private RestTemplate restTemplate;
+
+    @DubboReference(providedBy = ServerInfo.SERVER_SDK_DUBBO_NAME)
+    private IWxApiServiceRpc wxApiServiceRpc;
+
+    /**
+     * 通过腾讯API给玩家发送消息
+     */
+    private String sendCustomMessageApi(GameAppletDTO gameAppletDTO, String openId, String msgType, Map<String, Object> msgMap) {
+        //客服消息参数构造
+        Map<String, Object> paramMap = new HashMap<>(3);
+        paramMap.put("touser", openId);
+        paramMap.put("msgtype", msgType);
+        paramMap.put(msgType, msgMap);
+        log.error("客服消息发送参数, paramMap : {}", JsonUtil.toString(paramMap));
+        //获取接口token
+        String accessToken = wxApiServiceRpc.getAccessToken(gameAppletDTO.getAppId(), gameAppletDTO.getAppSecret());
+        URI uri = UriComponentsBuilder.fromHttpUrl("https://api.weixin.qq.com/cgi-bin/message/custom/send")
+                .queryParam("access_token", accessToken)
+                .build().toUri();
+        // 发送请求
+        String result = restTemplate.postForObject(uri, paramMap, String.class);
+        log.error("客服消息发送结果, result : {}", result);
+        return HttpStatusEnum.SUCCESS.getMsg();
+    }
+
+    /**
+     * 上传临时素材
+     */
+    public String mediaUpload(String accessToken, MultipartFile files) {
+        URI uri = UriComponentsBuilder.fromHttpUrl("https://api.weixin.qq.com/cgi-bin/media/upload")
+                .queryParam("access_token", accessToken)
+                .queryParam("type", "image")
+                .build().toUri();
+        //最外层请求头
+        HttpHeaders httpHeaders = new HttpHeaders();
+        httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
+        LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
+        //素材内容请求头
+        HttpHeaders formHeader = new HttpHeaders();
+        formHeader.setContentDispositionFormData("media", files.getOriginalFilename());
+        formHeader.setContentType(MediaType.MULTIPART_FORM_DATA);
+        HttpEntity<Resource> formEntity = new HttpEntity<>(files.getResource(), formHeader);
+        map.add("media", formEntity);
+        //http请求头
+        HttpEntity<LinkedMultiValueMap<String, Object>> httpEntity = new HttpEntity<>(map, httpHeaders);
+        Object result;
+        try {
+            result = restTemplate.postForObject(uri, httpEntity, Object.class);
+        } catch (Exception e) {
+            log.error("客服消息上传临时素材异常, e : {}", e.getMessage());
+            throw new BaseException("上传临时素材异常");
+        }
+        if (result == null) {
+//            log.error("企微上传临时素材异常, accessToken : {}, type : {}", accessToken, type);
+            throw new BaseException("企微上传临时素材返回结果为空");
+        }
+        KfUploadTempMediaDTO res = JsonUtil.toObj(JsonUtil.toString(result), KfUploadTempMediaDTO.class);
+        if (res.isSuccess()) {
+            return res.getMedia_id();
+        }
+//        log.error("企微上传临时素材异常, accessToken : {}, type : {}, errmsg : {}", accessToken, type, res.getErrmsg());
+        throw new BaseException("企微上传临时素材失败");
+    }
+}

+ 2 - 1
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/impl/CpCallServiceImpl.java

@@ -27,6 +27,7 @@ public class CpCallServiceImpl {
 //    }
 
     public static void test() throws Exception {
+        String key =  "355b7f07125c1ef71cfd10166e0b90aa";
         RestTemplate restTemplate = new RestTemplate();
 
         String url = "https://ht.lttx.t5yx.cn/extapi?action=BgzszhSendTip";
@@ -42,7 +43,7 @@ public class CpCallServiceImpl {
         Long time = 1708484041L;
         param.put("time", time);
 
-        String signStr = "key=asd123&msgId=" + msgId + "&strRan=" + strRan + "&time=" + time;
+        String signStr = "key=355b7f07125c1ef71cfd10166e0b90aa&msgId=" + msgId + "&strRan=" + strRan + "&time=" + time;
 
         System.out.println("加密字符串 : " + signStr);
 

+ 45 - 96
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/impl/KfRoomMsgServiceImpl.java

@@ -1,32 +1,24 @@
 package com.zanxiang.game.module.manage.service.impl;
 
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.zanxiang.game.module.base.ServerInfo;
-import com.zanxiang.game.module.base.pojo.enums.HttpStatusEnum;
-import com.zanxiang.game.module.base.rpc.IWxApiServiceRpc;
-import com.zanxiang.game.module.manage.pojo.dto.GameAppletDTO;
-import com.zanxiang.game.module.manage.pojo.dto.KfUploadTempMediaDTO;
+import com.zanxiang.game.module.manage.enums.KfRoomMsgOwnerEnum;
+import com.zanxiang.game.module.manage.enums.KfRoomMsgTypeEnum;
+import com.zanxiang.game.module.manage.pojo.dto.KfAppletMsgDTO;
+import com.zanxiang.game.module.manage.pojo.dto.KfMsgDTO;
 import com.zanxiang.game.module.manage.service.IKfRoomMsgService;
+import com.zanxiang.game.module.manage.websocket.KfMsgWebsocketHandler;
 import com.zanxiang.game.module.mybatis.entity.KfRoomMsg;
 import com.zanxiang.game.module.mybatis.mapper.KfRoomMsgMapper;
 import com.zanxiang.module.util.JsonUtil;
-import com.zanxiang.module.util.exception.BaseException;
+import com.zanxiang.module.util.bean.BeanUtil;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.dubbo.config.annotation.DubboReference;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.core.io.Resource;
-import org.springframework.http.HttpEntity;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
 import org.springframework.stereotype.Service;
-import org.springframework.util.LinkedMultiValueMap;
-import org.springframework.web.client.RestTemplate;
-import org.springframework.web.multipart.MultipartFile;
-import org.springframework.web.util.UriComponentsBuilder;
 
-import java.net.URI;
+import java.time.LocalDateTime;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Objects;
 
 /**
  * @author : lingfeng
@@ -37,92 +29,49 @@ import java.util.Map;
 @Service
 public class KfRoomMsgServiceImpl extends ServiceImpl<KfRoomMsgMapper, KfRoomMsg> implements IKfRoomMsgService {
 
-    @Autowired
-    private RestTemplate restTemplate;
-
-    @DubboReference(providedBy = ServerInfo.SERVER_SDK_DUBBO_NAME)
-    private IWxApiServiceRpc wxApiServiceRpc;
 
-    /**
-     * 通过腾讯API给玩家发送消息
-     */
-    private String sendCustomMessageApi(GameAppletDTO gameAppletDTO, String openId, String msgType, Map<String, Object> msgMap) {
-        //客服消息参数构造
-        Map<String, Object> paramMap = new HashMap<>(3);
-        paramMap.put("touser", openId);
-        paramMap.put("msgtype", msgType);
-        paramMap.put(msgType, msgMap);
-        log.error("客服消息发送参数, paramMap : {}", JsonUtil.toString(paramMap));
-        //获取接口token
-        String accessToken = wxApiServiceRpc.getAccessToken(gameAppletDTO.getAppId(), gameAppletDTO.getAppSecret());
-        URI uri = UriComponentsBuilder.fromHttpUrl("https://api.weixin.qq.com/cgi-bin/message/custom/send")
-                .queryParam("access_token", accessToken)
-                .build().toUri();
-        // 发送请求
-        String result = restTemplate.postForObject(uri, paramMap, String.class);
-        log.error("客服消息发送结果, result : {}", result);
-        return HttpStatusEnum.SUCCESS.getMsg();
-    }
+    @Autowired
+    private KfMsgWebsocketHandler kfMsgWebsocketHandler;
 
-    /**
-     * 图片上传临时素材
-     */
-    private String uploadTempMedia(GameAppletDTO gameAppletDTO, String openId, String msgType, Map<String, Object> msgMap) {
-        //客服消息参数构造
-        Map<String, Object> paramMap = new HashMap<>(3);
-        paramMap.put("touser", openId);
-        paramMap.put("msgtype", msgType);
-        paramMap.put(msgType, msgMap);
-        log.error("客服消息发送参数, paramMap : {}", JsonUtil.toString(paramMap));
-        //获取接口token
-        String accessToken = wxApiServiceRpc.getAccessToken(gameAppletDTO.getAppId(), gameAppletDTO.getAppSecret());
-        URI uri = UriComponentsBuilder.fromHttpUrl("https://api.weixin.qq.com/cgi-bin/media/upload")
-                .queryParam("access_token", accessToken)
-                .build().toUri();
-        // 发送请求
-        String result = restTemplate.postForObject(uri, paramMap, String.class);
-        log.error("客服消息发送结果, result : {}", result);
-        return HttpStatusEnum.SUCCESS.getMsg();
+    @Override
+    public void appletMsg(String postData) {
+        log.error("接收到SDK转发的小程序消息, postData : {}", postData);
+        KfAppletMsgDTO kfAppletMsgDTO = JsonUtil.toObj(postData, KfAppletMsgDTO.class);
+        //用户进入会话事件
+        if (Objects.equals(kfAppletMsgDTO.getMsgType(), KfAppletMsgDTO.MSG_TYPE_EVENT)
+                && Objects.equals(kfAppletMsgDTO.getEvent(), KfAppletMsgDTO.EVENT_USER_ENTER_TEMP_SESSION)) {
+            //创建用户信息
+            return;
+        }
+        //非玩家消息, 不做处理
+        if (kfAppletMsgDTO.getMsgId() == null) {
+            return;
+        }
+        //消息存储
+        KfRoomMsg kfRoomMsg = KfRoomMsg.builder()
+                .msgId(String.valueOf(kfAppletMsgDTO.getMsgId()))
+                .msgType(kfAppletMsgDTO.getMsgType())
+                .readStatus(Boolean.FALSE)
+                .msgOwner(KfRoomMsgOwnerEnum.KF_MSG_OWNER_USER.getValue())
+                .content(this.getMsgContent(kfAppletMsgDTO))
+                .source(postData)
+                .createTime(LocalDateTime.now())
+                .build();
+        super.save(kfRoomMsg);
+        // 消息转发到redis频道
+        kfMsgWebsocketHandler.pushMessage(JsonUtil.toString(BeanUtil.copy(kfRoomMsg, KfMsgDTO.class)));
     }
 
-
-    /**
-     * 上传临时素材
-     */
-    public String mediaUpload(String accessToken, MultipartFile files) {
-        URI uri = UriComponentsBuilder.fromHttpUrl("https://api.weixin.qq.com/cgi-bin/media/upload")
-                .queryParam("access_token", accessToken)
-                .queryParam("type", "image")
-                .build().toUri();
-        //最外层请求头
-        HttpHeaders httpHeaders = new HttpHeaders();
-        httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
-        LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
-        //素材内容请求头
-        HttpHeaders formHeader = new HttpHeaders();
-        formHeader.setContentDispositionFormData("media", files.getOriginalFilename());
-        formHeader.setContentType(MediaType.MULTIPART_FORM_DATA);
-        HttpEntity<Resource> formEntity = new HttpEntity<>(files.getResource(), formHeader);
-        map.add("media", formEntity);
-        //http请求头
-        HttpEntity<LinkedMultiValueMap<String, Object>> httpEntity = new HttpEntity<>(map, httpHeaders);
-        Object result;
-        try {
-            result = restTemplate.postForObject(uri, httpEntity, Object.class);
-        } catch (Exception e) {
-            log.error("客服消息上传临时素材异常, e : {}", e.getMessage());
-            throw new BaseException("上传临时素材异常");
-        }
-        if (result == null) {
-//            log.error("企微上传临时素材异常, accessToken : {}, type : {}", accessToken, type);
-            throw new BaseException("企微上传临时素材返回结果为空");
+    private String getMsgContent(KfAppletMsgDTO kfAppletMsgDTO) {
+        Map<String, String> contentMap = new HashMap<>(2);
+        if (Objects.equals(KfRoomMsgTypeEnum.KF_MSG_TYPE_TEXT.getValue(), kfAppletMsgDTO.getMsgType())) {
+            contentMap.put("text", kfAppletMsgDTO.getContent());
         }
-        KfUploadTempMediaDTO res = JsonUtil.toObj(JsonUtil.toString(result), KfUploadTempMediaDTO.class);
-        if (res.isSuccess()) {
-            return res.getMedia_id();
+        if (Objects.equals(KfRoomMsgTypeEnum.KF_MSG_TYPE_IMAGE.getValue(), kfAppletMsgDTO.getMsgType())) {
+            contentMap.put("picUrl", kfAppletMsgDTO.getPicUrl());
+            contentMap.put("mediaId", kfAppletMsgDTO.getMediaId());
         }
-//        log.error("企微上传临时素材异常, accessToken : {}, type : {}, errmsg : {}", accessToken, type, res.getErrmsg());
-        throw new BaseException("企微上传临时素材失败");
+        return JsonUtil.toString(contentMap);
     }
 
 }

+ 6 - 3
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/websocket/KfMsgRedisListener.java

@@ -1,6 +1,6 @@
 package com.zanxiang.game.module.manage.websocket;
 
-import com.zanxiang.erp.security.util.SecurityUtil;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.connection.Message;
 import org.springframework.data.redis.connection.MessageListener;
@@ -16,6 +16,7 @@ import java.io.IOException;
  * @description : 客服消息redis监听器
  */
 @Component
+@Slf4j
 public class KfMsgRedisListener implements MessageListener {
 
     @Autowired
@@ -25,12 +26,14 @@ public class KfMsgRedisListener implements MessageListener {
     public void onMessage(Message message, byte[] pattern) {
         //从redis中拿到的消息
         String messageBody = new String(message.getBody());
+        log.error("redis监听器监听到消息 messageBody : {}", messageBody);
+        String[] by = messageBody.split("_");
         //从消息中获取userId
-        WebSocketSession session = kfMsgWebSocketSessionRegistry.getSession(SecurityUtil.getUserId().toString());
+        WebSocketSession session = kfMsgWebSocketSessionRegistry.getSession(by[0]);
         //判断连接存在, 且未来断开, 发送消息
         if (session != null && session.isOpen()) {
             try {
-                session.sendMessage(new TextMessage(messageBody));
+                session.sendMessage(new TextMessage(by[1]));
             } catch (IOException e) {
                 // Handle exception
             }

+ 2 - 3
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/websocket/KfMsgWebsocketHandler.java

@@ -1,6 +1,5 @@
 package com.zanxiang.game.module.manage.websocket;
 
-import com.zanxiang.erp.security.util.SecurityUtil;
 import com.zanxiang.game.module.manage.constant.RedisKeyConstant;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -34,7 +33,6 @@ public class KfMsgWebsocketHandler implements WebSocketHandler {
     @Override
     public void afterConnectionEstablished(WebSocketSession session) throws Exception {
         log.error("前端长连接建立成功");
-        kfMsgWebSocketSessionRegistry.addSession(SecurityUtil.getUserId().toString(), session);
     }
 
     /**
@@ -44,7 +42,8 @@ public class KfMsgWebsocketHandler implements WebSocketHandler {
     public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
         String msgStr = message.getPayload().toString();
         log.error("收到前端消息 msgStr : {}", msgStr);
-        this.pushMessage("你好!武哥");
+        kfMsgWebSocketSessionRegistry.addSession(msgStr, session);
+        this.pushMessage(msgStr + "_" + "你好!武哥");
     }
 
     /**

+ 5 - 0
game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/entity/KfRoomMsg.java

@@ -53,6 +53,11 @@ public class KfRoomMsg {
      */
     private String content;
 
+    /**
+     * 源数据
+     */
+    private String source;
+
     /**
      * 创建时间
      */