导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
配置
package com.qi.demo1.config;
import com.qi.demo1.interceptor.MyChannelInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.messaging.support.ChannelInterceptor;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
/**
* @author qyb
* @version 1.0
* @date 2022/7/26-11:34
*/
@Configuration
@EnableWebSocketMessageBroker
public class WebsocketConfig implements WebSocketMessageBrokerConfigurer {
@Autowired
MyChannelInterceptor myChannelInterceptor;
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
使用sockjs
// registry.addEndpoint("/socket")
// .setAllowedOrigins("*")
// .withSockJS();
// 使用原生
registry.addEndpoint("/socket")
.setAllowedOrigins("*");
}
@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.interceptors(myChannelInterceptor);
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
// 点对点 默认为/user
registry.setUserDestinationPrefix("/user");
接收客户端消息前缀
// registry.setApplicationDestinationPrefixes("/app");
// // 声明在/user、/topic可以像客户端发送消息 (声明了这个必须加上/user ,不然一对一消息发送不了)
registry.enableSimpleBroker("/user","/topic");
}
}
配置客户端入站通道拦截器
用于认证授权,没有登录不能连接
package com.qi.demo1.interceptor;
import com.qi.demo1.entity.AuthUser;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.simp.stomp.StompCommand;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.messaging.support.ChannelInterceptor;
import org.springframework.stereotype.Component;
import java.security.Principal;
import java.util.List;
/**
* @author qyb
* @version 1.0
* @date 2022/7/27-10:28
*/
@Slf4j
@Component
public class MyChannelInterceptor implements ChannelInterceptor {
@Override
public Message<?> preSend(@NotNull Message<?> message, @NotNull MessageChannel channel) {
StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message);
StompCommand command = accessor.getCommand();
if (StompCommand.CONNECT.equals(command)) {
// 认证校验,没有登录的用户不允许连接
List<String> authorization = accessor.getNativeHeader("Authorization");
if (authorization != null && authorization.size() > 0) {
String token = authorization.get(0);
if (!"123456".equals(token)) {
throw new RuntimeException("认证失败");
}
accessor.setUser(new AuthUser(token));
log.info("用户【{}】连接成功", token);
}
} else if (StompCommand.DISCONNECT.equals(command)) {
Principal user = accessor.getUser();
log.info("用户【{}】断开连接", user);
}
System.out.println(message);
return message;
}
}
前端代码
import {Client} from '@stomp/stompjs'
export default class WebSocketApi {
constructor() {
this.client = new Client({
brokerURL: 'ws://localhost:8090/socket', //可以不赋值,因为后面用SockJS来代替
connectHeaders: {
"Authorization": "123456"
},
debug:(msg)=> console.log(msg),
reconnectDelay: 10000, //重连时间
heartbeatIncoming: 4000,
heartbeatOutgoing: 4000,
//错误
onStompError: () => console.log('连接失败') //这里不需要重连了,新版自带重连
})
}
connect(url, callback) {
this.client.onConnect = () => this.client.subscribe(url, callback)
this.client.activate()
}
disConnect() {
if (this.client != null) this.client.deactivate()
}
}
前端使用
created() {
this.websocket=new WebsocketApi()
this.websocket.connect("/user/123456/message/chat",(res)=>{
console.log(res.body);
console.log(111);
})
},
后端发送消息的接口
package com.qi.demo1.controller;
import com.qi.demo1.common.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.messaging.simp.user.SimpUser;
import org.springframework.messaging.simp.user.SimpUserRegistry;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Set;
/**
* @author qyb
* @version 1.0
* @date 2022/7/27-11:42
*/
@RestController
public class WsController {
@Autowired
SimpMessagingTemplate simpMessagingTemplate;
@Autowired
SimpUserRegistry simpUserRegistry;
@GetMapping("/send")
public R<?> sendToUser(String msg) {
Set<SimpUser> users = simpUserRegistry.getUsers();
System.out.println(users);
simpMessagingTemplate.convertAndSendToUser("123456","/message/chat","123467");
return R.ok();
}
}