0


Springboot 接入 WebSocket 实战

Springboot 接入 WebSocket 实战

前言:
WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。

简单理解:
1,常见开发过程中我们知道 Http协议,客户端请求一次,服务器响应一次,推送数据,不能主动的推送数据,每次请求都要做一个连接,非常消耗性能。

2,websocket 建立一次链接,可以主动向客户端推送数据。

需求说明:
1,项目需要做一个知识助手,远程调用三方接口,那边是websocket 实时推送数据,类似gpt
2,后端需要连接三方服务,调用接口返回数据给前端,做渲染

在这里插入图片描述

功能实现

1,依赖

  1. <dependency><groupId>javax.websocket</groupId><artifactId>javax.websocket-api</artifactId><version>1.1</version></dependency><dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp</artifactId></dependency>

2,代码接口实现

controller:

  1. @GetMapping("/callxxxxModel")
  2. public String callxxxxModel(@RequestParam("paramOne") String paramOne){return webSocketxxxClientService.callxxxxModel(paramOne);}

service:

  1. /**
  2. *
  3. * @param paramOne
  4. * 参数1
  5. */
  6. String callxxxxModel(String paramOne);

serviceImpl:

  1. @Slf4j
  2. @Service("webSocketxxxClientService")
  3. public class WebSocketxxxClientServiceImpl implements WebSocketxxxClientService{
  4. @Override
  5. public String callxxxxModel(String paramOne, Integer executeType){
  6. String uri ="ws://10.xx.xx.13:123/sss/xxx/aa/xxx_v2";
  7. String xappid ="lsjdfljsdxxx09980dsfsd";
  8. String xappkey ="xxsfdsf12123123";long timestamp = System.currentTimeMillis();
  9. String seqid ="";
  10. log.info("timestamp="+ timestamp);
  11. log.info("seqid="+ seqid);
  12. WebSocketClientRemote client = new WebSocketClientRemote(uri, xappid, xappkey);// Prepare message
  13. Map<String, Object> message = new HashMap<>();
  14. message.put("uid", xappid);
  15. message.put("timestamp", timestamp);
  16. message.put("seqid", seqid);
  17. message.put("stream","true");// 会话识别码,切换话题可能需要更换
  18. message.put("session_id", seqid);
  19. message.put("prov","xxsdfsdf23424332");
  20. message.put("param1", paramOne);
  21. message.put("param2","xvsdfds23423423xxxxx");
  22. String jsonMessage = JSON.toJSONString(message);
  23. client.sendMessage(jsonMessage);
  24. String responseMessage = client.getResponseMessage();
  25. client.close();return responseMessage;}
  1. package com.xx.xx.xx.web;
  2. import com.xx.xx.common.result.ResultCodeEnum;
  3. import com.xx.xx.xxx.exception.CloudException;
  4. import lombok.extern.slf4j.Slf4j;
  5. import okhttp3.*;
  6. import okio.ByteString;
  7. import javax.websocket.ClientEndpoint;
  8. import java.util.concurrent.CountDownLatch;/**
  9. * @author nobuyboday
  10. */
  11. @Slf4j
  12. @ClientEndpoint
  13. public class WebSocketClientRemote {
  14. private final OkHttpClient client;
  15. private final WebSocket webSocket;// public final CountDownLatch latch = new CountDownLatch(50);// 记录websocket 返回的信息
  16. public String responseMessage ="";
  17. public WebSocketClientRemote(String uri, String xappid, String xappkey){
  18. client = new OkHttpClient();
  19. Request request = new Request.Builder().url(uri)// 添加自定义头.addHeader("X-App-ID","xxxfjslfjslj1231321xxxx3")// 添加自定义头.addHeader("X-App-Key","0923jhdjflsdjflsdjljxxxxxxflsn").build();
  20. webSocket = client.newWebSocket(request, new WebSocketListener(){
  21. @Override
  22. public voidonOpen(WebSocket webSocket, Response response){
  23. log.info("已连接到服务器................");}
  24. @Override
  25. public voidonMessage(WebSocket webSocket, String text){// log.info("收到消息: " + text);
  26. responseMessage += text;}
  27. @Override
  28. public voidonMessage(WebSocket webSocket, ByteString bytes){
  29. log.info("收到字节消息: "+ bytes.hex());}
  30. @Override
  31. public voidonClosing(WebSocket webSocket,int code, String reason){
  32. webSocket.close(1000, null);
  33. log.info("连接关闭: "+ reason);// latch.countDown();}
  34. @Override
  35. public voidonFailure(WebSocket webSocket, Throwable t, Response response){
  36. log.info("连接失败: "+ t.getMessage());}});}
  37. public voidsendMessage(String message){
  38. webSocket.send(message);}
  39. public voidclose(){
  40. webSocket.close(1000,"关闭连接");}
  41. public voidawait() throws InterruptedException {// latch.await();}
  42. public String getResponseMessage(){// 对方数据是以 <#END> 代表推送数据完毕,这个\\u003c#END\\u003e是<#END>编码问题 不用管
  43. boolean isReturn = responseMessage.endsWith("<#END>")|| responseMessage.endsWith("\\u003c#END\\u003e")|| responseMessage.contains("#END")|| responseMessage.contains("\\u003c#END\\u003e");if(isReturn){// log.info("最终的responseMessage:================>>>:{}", responseMessage);return responseMessage.substring(0, responseMessage.length()-"<#END>".length());}else{// 循环等待
  44. try {
  45. Thread.sleep(3000);}catch(Exception e){
  46. throw new CloudException(ResultCodeEnum.CALL_GROUP_DCOOS_TYCLOUD_KNOWLEDGE_ASSISTANT_FAIL.getCode(),
  47. ResultCodeEnum.CALL_GROUP_DCOOS_TYCLOUD_KNOWLEDGE_ASSISTANT_FAIL.getMessage()+":"+ e);}returngetResponseMessage();}}}

遇到的问题:

1,websocket 没有返回值,需要加一个接口获取返回值
2,对方返回的数据 <#END> 结尾,在接收判断是否完毕后,字符集问题 不识别 <#END>
3,推送数据要保证全部推送完毕,要有个循环调用

喜欢我的文章记得点个在看,或者点赞,持续更新中ing…


本文转载自: https://blog.csdn.net/qq_45938780/article/details/142869991
版权归原作者 on the way 123 所有, 如有侵权,请联系我们删除。

“Springboot 接入 WebSocket 实战”的评论:

还没有评论