1.引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
当然我这里还有一些其他的依赖:
2.配置
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
3.编写websocket服务端
/**
* @Author: ChenTaoTao
* @Date: 2022/1/11 19:42
* @Describe:
*/
@ServerEndpoint("/socket/{userId}")
@Component
@Slf4j
public class UserWebSocket {
private static Map<String, Session> onlineSessions = new ConcurrentHashMap<>();
/**
* 连接建立成功调用的方法*/
@OnOpen
public void onOpen(Session session, @PathParam("userId") String userId){
log.info("连接建立{}",userId);
onlineSessions.put(userId,session);
}
@OnClose
public void onClose(@PathParam("userId")String userId) {
log.info("关闭{}",userId);
onlineSessions.remove(userId);
}
@OnError
public void onError(Throwable e){
log.info("错误{}",e);
}
@OnMessage
public void onMessage(String message,Session session) throws IOException {
log.info("消息数据为{}",message);
session.getBasicRemote().sendText("好了我收到了");
}
}
以上的几个注解分别为连接建立、连接关闭、连接错误、收到消息时会调用的方法
4. Vue中简单封装Websocket
// websocket的域名和端口号的配置
const BASE_URL = 'localhost';
const WS_PORT = '9000';
//当然,这里的id应该是用户的id或者唯一标识等,由于我没有做登录的块,所以直接加上了'/id'本质上应该是在调用socket的时候拼接参数给后端的
const WS_ADDRESS = `ws://${BASE_URL}:${WS_PORT}/socket/id`;
export const useWebSocket = (handleMessage) => {
const ws = new WebSocket(WS_ADDRESS );
//ws.binaryType = 'arraybuffer'; //可将 WebSocket 对象的 binaryType 属性设为“blob”或“arraybuffer”。默认格式为“blob”(您不必在发送时校正 binaryType 参数)。
const init = () => {
ws.addEventListener('open', handleOpen, false);
ws.addEventListener('close', handleClose, false);
ws.addEventListener('error', handleError, false);
//消息处理方法,本处是以构造参数传入的方式更为灵活的处理消息
ws.addEventListener('message', handleMessage, false);
};
//连接建立时会调用的方法
function handleOpen(e) {
console.log('WebSocket open', e);
}
//连接关闭时会调用的方法
function handleClose(e) {
console.log('WebSocket close', e);
}
//连接出现异常时需要调用的方法
function handleError(e) {
console.log('WebSocket error', e);
}
init();
return ws;
};
然后再home.vue中添加部分代码
<template>
<div class="home">
<img alt="Vue logo" src="../assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
<button @click="init">初始化</button>
<input v-model="msg"/>
<button @click="sendMsg">发消息</button>
<button @click="close">关闭</button>
</div>
</template>
<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'
//这个就是引入刚刚封装的websocket
import {useWebSocket} from "../config";
export default {
name: 'Home',
components: {
HelloWorld
},
created() {
},
methods: {
init(){
this.ws = useWebSocket(this.handleMessage);
},
handleMessage(evt) {
if (evt.data) {
console.log("获取到的数据为:"+evt.data)
}
},
sendMsg(){
console.log(this.msg)
this.ws.send(this.msg)
},
close(){
this.ws.close();
}
},
data() {
return {
ws:'',
msg:""
}
},
}
</script>
运行:
5.测试
1.建立连接:
点击初始化按钮:
前后端执行了两端段代码,分别为
后端onOpen
前端handleOpen中我们封装的内容
2.发送消息
在输入框中输入消息内容
可以看到获取到了后端返回的内容,同时后端也打印了前端发送过去的数据:
3.关闭连接
以上说明连接关闭了,同时后端结果如下
说明websocket已经关闭
6.gateway中对ws的转发配置:
spring:
cloud:
gateway:
routes:
- id: usersocket
uri: lb:ws://userservice
predicates:
- Path=/socket/**
在均衡负载lb后面再添加一个ws的协议,将对应请求转发到指定的服务即可,我本次的项目就是
SpringCloud Gateway +Nacos+OpenFeign+Dubbo等构建的,之所以这里同时用了OpenFeign和dubbo也是想试试同一个大系统中是否可以在服务间调用中同时使用不同技术,结果是可以的