前端测试springboot websocket订阅示例代码
时间: 2023-11-17 14:01:24 浏览: 34
以下是一个前端测试Spring Boot WebSocket订阅示例代码:
```javascript
var socket = new WebSocket('ws://localhost:8080/chat');
socket.onopen = function(event) {
console.log('WebSocket is connected.');
};
socket.onmessage = function(event) {
console.log('Received message: ' + event.data);
};
socket.onclose = function(event) {
console.log('WebSocket is closed.');
};
// 订阅聊天室
socket.send(JSON.stringify({
'type': 'subscribe',
'room': 'chatroom'
}));
// 发送消息
socket.send(JSON.stringify({
'type': 'message',
'room': 'chatroom',
'content': 'Hello, world!'
}));
```
这段代码创建了一个WebSocket连接,并订阅了名为“chatroom”的聊天室。它还发送了一条消息到该聊天室。你可以根据自己的需求修改代码。
相关问题
springboot 动态websocket
Spring Boot 支持使用 Spring WebSocket 模块来实现 WebSocket 功能。在 Spring WebSocket 中,我们可以通过实现 WebSocketHandler 接口来处理 WebSocket 请求,也可以使用 @Controller 注解和 @MessageMapping 注解来处理 WebSocket 请求。
动态 WebSocket 可以通过在后端使用 WebSocketSession 对象动态向前端推送数据。我们可以在后端创建一个 WebSocketSession 对象,然后将其存储在一个 Map 中,当需要向前端推送数据时,可以根据前端的连接 ID 从 Map 中获取相应的 WebSocketSession 对象,然后使用该对象向前端推送数据。
下面是一个使用 Spring WebSocket 实现动态 WebSocket 的示例代码:
```java
@Controller
public class WebSocketController {
private static final Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>();
@Autowired
private SimpMessagingTemplate messagingTemplate;
@MessageMapping("/connect")
public void connect(Principal principal, WebSocketSession session) throws Exception {
sessions.put(principal.getName(), session);
}
@MessageMapping("/push")
public void push(Principal principal, String message) throws Exception {
WebSocketSession session = sessions.get(principal.getName());
if (session != null && session.isOpen()) {
messagingTemplate.convertAndSendToUser(principal.getName(), "/topic/push", message);
}
}
@MessageMapping("/disconnect")
public void disconnect(Principal principal) throws Exception {
sessions.remove(principal.getName());
}
}
```
在上述代码中,我们使用了 @Controller 注解来标注 WebSocketController 类,并使用 @MessageMapping 注解来标注处理 WebSocket 请求的方法。在 connect 方法中,我们将 WebSocketSession 对象存储在 sessions Map 中,并在 push 方法中使用 messagingTemplate 对象向前端推送数据。disconnect 方法用于在断开连接时从 sessions Map 中移除 WebSocketSession 对象。
在前端实现时,我们可以使用 Stomp.js 库来实现 WebSocket 连接和消息推送。下面是一个使用 Stomp.js 实现动态 WebSocket 的示例代码:
```javascript
var stompClient = null;
function connect() {
var socket = new SockJS('/websocket');
stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
stompClient.subscribe('/user/topic/push', function(message) {
var data = JSON.parse(message.body);
// 处理推送的数据
});
stompClient.send('/app/connect');
});
}
function push(data) {
stompClient.send('/app/push', {}, data);
}
function disconnect() {
stompClient.send('/app/disconnect');
stompClient.disconnect();
}
```
在上述代码中,我们使用 connect 方法来建立 WebSocket 连接,使用 push 方法来向后端推送数据,使用 disconnect 方法来断开 WebSocket 连接。在 connect 方法中,我们使用 Stomp.over 方法创建一个 Stomp 客户端,并使用 subscribe 方法来订阅推送消息。在 push 方法中,我们使用 send 方法来向后端推送数据。在 disconnect 方法中,我们使用 send 方法来通知后端断开 WebSocket 连接,并使用 disconnect 方法来关闭 Stomp 客户端。
springboot+vue+websocket+redis实现单聊代码、存储历史消息
这里提供一个简单的示例代码,实现了Spring Boot和Vue.js的单聊功能,使用WebSocket进行实时通信,并使用Redis存储历史消息。
后端代码(Spring Boot):
1. 依赖:
```xml
<dependencies>
<!-- Spring Boot Websocket -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!-- Spring Boot Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- JSON -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
</dependencies>
```
2. 配置文件:
```yml
spring:
redis:
host: localhost
port: 6379
logging:
level:
org.springframework.web.socket: DEBUG
```
3. 实体类:
```java
public class Message {
private String from;
private String to;
private String content;
private Date time;
// getters and setters
}
```
4. WebSocket配置:
```java
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Autowired
private WebSocketHandler webSocketHandler;
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(webSocketHandler, "/chat").setAllowedOrigins("*");
}
}
```
5. WebSocket处理器:
```java
@Component
public class WebSocketHandler extends TextWebSocketHandler {
@Autowired
private RedisTemplate<String, Message> redisTemplate;
private ObjectMapper objectMapper = new ObjectMapper();
private static final String KEY_PREFIX = "chat:";
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
// 获取当前用户
String user = (String) session.getAttributes().get("user");
// 订阅Redis频道
redisTemplate.execute(new RedisCallback<Void>() {
@Override
public Void doInRedis(RedisConnection connection) throws DataAccessException {
connection.subscribe(new MessageListener(), KEY_PREFIX + user);
return null;
}
});
// 发送历史消息
List<Message> messages = redisTemplate.opsForList().range(KEY_PREFIX + user, 0, -1);
if (messages != null && messages.size() > 0) {
for (Message message : messages) {
session.sendMessage(new TextMessage(objectMapper.writeValueAsString(message)));
}
}
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
// 获取当前用户
String user = (String) session.getAttributes().get("user");
// 解析消息
Message msg = objectMapper.readValue(message.getPayload(), Message.class);
msg.setFrom(user);
msg.setTime(new Date());
// 存储到Redis
redisTemplate.opsForList().rightPush(KEY_PREFIX + msg.getTo(), msg);
// 发送给对方
WebSocketSession targetSession = sessions.get(msg.getTo());
if (targetSession != null && targetSession.isOpen()) {
targetSession.sendMessage(new TextMessage(objectMapper.writeValueAsString(msg)));
}
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
// 获取当前用户
String user = (String) session.getAttributes().get("user");
// 取消订阅Redis频道
redisTemplate.execute(new RedisCallback<Void>() {
@Override
public Void doInRedis(RedisConnection connection) throws DataAccessException {
connection.unsubscribe(KEY_PREFIX + user);
return null;
}
});
}
private Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>();
private class MessageListener implements MessageListenerAdapter {
@Override
public void onMessage(Message message, byte[] pattern) {
WebSocketSession session = sessions.get(message.getTo());
if (session != null && session.isOpen()) {
try {
session.sendMessage(new TextMessage(objectMapper.writeValueAsString(message)));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
```
6. 控制器:
```java
@RestController
@RequestMapping("/api/chat")
public class ChatController {
@Autowired
private RedisTemplate<String, Message> redisTemplate;
@PostMapping("/send")
public void send(@RequestBody Message message) {
// 存储到Redis
redisTemplate.opsForList().rightPush("chat:" + message.getFrom(), message);
redisTemplate.opsForList().rightPush("chat:" + message.getTo(), message);
// 发布消息
redisTemplate.convertAndSend("chat:" + message.getTo(), message);
}
@GetMapping("/history")
public List<Message> history(String user1, String user2) {
String key = "chat:" + user1 + ":" + user2;
List<Message> messages = redisTemplate.opsForList().range(key, 0, -1);
Collections.reverse(messages);
return messages;
}
}
```
前端代码(Vue.js):
1. 依赖:
```html
<script src="/js/vue.min.js"></script>
<script src="/js/sockjs.min.js"></script>
<script src="/js/stomp.min.js"></script>
<script src="/js/lodash.min.js"></script>
```
2. HTML:
```html
<div id="app">
<div>
<label>当前用户:</label>
<select v-model="currentUser" @change="connect">
<option v-for="user in users" :value="user">{{ user }}</option>
</select>
</div>
<div v-if="connected">
<div>
<label>对方用户:</label>
<input v-model="otherUser">
</div>
<div>
<textarea v-model="message"></textarea>
<button @click="send">发送</button>
</div>
<div>
<ul>
<li v-for="msg in messages">{{ msg.from }} -> {{ msg.to }}: {{ msg.content }}</li>
</ul>
</div>
</div>
</div>
```
3. JavaScript:
```javascript
var app = new Vue({
el: '#app',
data: {
users: ['user1', 'user2', 'user3'],
currentUser: 'user1',
otherUser: '',
message: '',
connected: false,
messages: []
},
methods: {
connect: function () {
var self = this;
if (self.stompClient != null) {
self.stompClient.disconnect();
}
var socket = new SockJS('/chat');
self.stompClient = Stomp.over(socket);
self.stompClient.connect({}, function () {
self.stompClient.subscribe('/user/queue/messages', function (msg) {
var message = JSON.parse(msg.body);
self.messages.push(message);
});
self.connected = true;
}, function (error) {
console.log(error);
});
},
send: function () {
var self = this;
var message = {
from: self.currentUser,
to: self.otherUser,
content: self.message
};
self.stompClient.send('/app/chat/send', {}, JSON.stringify(message));
self.message = '';
},
loadHistory: function () {
var self = this;
axios.get('/api/chat/history', {
params: {
user1: self.currentUser,
user2: self.otherUser
}
}).then(function (response) {
self.messages = response.data;
}).catch(function (error) {
console.log(error);
});
}
},
watch: {
otherUser: function (newValue) {
var self = this;
self.loadHistory();
}
}
});
```
注意事项:
1. Redis的键名使用了前缀“chat:”,以便区分其他数据;
2. 存储历史消息和订阅消息时,使用了当前用户的名称作为频道名称;
3. 在订阅消息时,使用了内部类MessageListener处理接收到的消息,然后发送给对应的WebSocketSession;
4. 在WebSocketSession关闭时,需要取消订阅Redis频道,以免造成资源浪费;
5. 前端使用了STOMP协议进行通信,需要安装sockjs-client和stompjs库;
6. 前端通过WebSocket连接到后端时,需要指定当前用户;
7. 前端通过WebSocket接收到消息时,需要将消息添加到消息列表中;
8. 前端通过REST API加载历史消息时,需要指定当前用户和对方用户。
这是一个基础的示例,具体实现可以根据自己的需求进行调整。