添加pom文件依赖
<!-- websocket-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
创建webSocketConfig配置类,即注册ServerEndpointExporter,该bean用于扫描被@ServerEndpoint注解的类,并将其作为服务端.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* @Author: chuxia0811
* @Date: 2023/7/9 10:15
* @Description : webSocketConfig配置类,该bean用于扫描被@ServerEndpoint注解的类
*/
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
创建被@ServerEndpoint注解的类用于作为webSocket服务器并指定连接的uri
使用注解标记对应的方法,,并启动程序。
/**
* @Author: chuxia0811
* @Date: 2023/7/9 10:21
* @Description :
*/
@ServerEndpoint(value = "/chat/{username}")
@Component
@Slf4j
public class SocketServer {
Logger log = LoggerFactory.getLogger(getClass());
// 保存链接的session,key为用户名,value为对应的session名
private ConcurrentHashMap<String, Session> sessionMap = new ConcurrentHashMap<>();
/**
* 创建连接
* 用于监听建立连接,当有客户端与该服务端点建立连接时,将会自回调该注解标注的方法
* @param session
* @param username
*/
@OnOpen
public void onOpen(Session session, @PathParam(value = "username") String username) {
log.info("用户{}已创建连接", username);
}
/**
* 用于监听客户端向服务端发送消息,当客户端与服务端发送消息时,将会回调该注解标注的方法
* @param msg
* @param username
*/
@OnMessage
public void onMessage(String msg,@PathParam(value = "username") String username){
log.info("用户{}发来消息:{}",username,msg);
}
/**
* 用于监听连接关闭,当客户端与该服务端点断开连接时,将会回调该注解标注的方法
* @param session
* @param username
*/
@OnClose
public void onClose(Session session,@PathParam(value = "username") String username){
log.info("用户{}已关闭连接", username);
}
/**
* 用于监听该连接上的任何错误,当客户端与该服务端点的连接发生任何异常,都将回调该注解标注的方法
* 注意该方法的参数必选Throwable,可选Sessiion以及0-n个String参数,且String参数需要使用@PathParam注解标注
* @param throwable
* @param username
*/
@OnError
public void onError(Throwable throwable,@PathParam(value = "username") String username){
log.error("用户{}连接发生异常", username);
}
}
项目启动后,测试websocket是否可用。
webSocket在线测试网站: Websocket在线测试链接
2023-07-09 10:49:29.185 INFO 16308 --- [nio-8080-exec-5] org.sang.websocket.SocketServer
: 用户初夏已创建连接
2023-07-09 10:49:35.672 INFO 16308 --- [nio-8080-exec-6] org.sang.websocket.SocketServer
: 用户初夏已创建连接
2023-07-09 10:49:43.470 INFO 16308 --- [nio-8080-exec-7] org.sang.websocket.SocketServer
: 用户初夏发来消息:你好,我是初夏~
成功完成基础的websocket连接,可以开始编辑业务逻辑
1.构建后台message实体类;
/**
* @Author: chuxia0811
* @Date: 2023/7/9 10:58
* @Description :
*/
public class Message {
private Integer id;
private String from;
private String to;
private String msg;
private String date;
private Integer type;//消息发送的类型,0系统群发,1用户私聊
private Integer is_read;//消息是否已读,0未读,1已读
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public Integer getType() {
return type;
}
public void setType(Integer type) {
this.type = type;
}
public Integer getIs_read() {
return is_read;
}
public void setIs_read(Integer is_read) {
this.is_read = is_read;
}
}
2.改造方法
@ServerEndpoint(value = "/chat/{username}")
@Component
@Slf4j
public class SocketServer {
Logger log = LoggerFactory.getLogger(getClass());
// 保存链接的session,key为用户名,value为对应的session名
private ConcurrentHashMap<String, Session> sessionMap = new ConcurrentHashMap<>();
/**
* 创建连接
* 用于监听建立连接,当有客户端与该服务端点建立连接时,将会自回调该注解标注的方法
* @param session
* @param username
*/
@OnOpen
public void onOpen(Session session, @PathParam(value = "username") String username) {
log.info("用户{}已创建连接", username);
sessionMap.put(username,session);
}
/**
* 用于监听客户端向服务端发送消息,当客户端与服务端发送消息时,将会回调该注解标注的方法
* @param msg
* @param username
*/
@OnMessage
public void onMessage(String msg,@PathParam(value = "username") String username){
log.info("用户{}发来消息:{}",username,msg);
Message message = JSON.parseObject(msg, Message.class);
//根据message中的to属性获取接收消息的用户的session,利用其session将消息转发过去
Session toSession = sessionMap.get(message.getTo());
sendMessage(toSession, message.getMsg());
}
/**
* 用于监听连接关闭,当客户端与该服务端点断开连接时,将会回调该注解标注的方法
* @param session
* @param username
*/
@OnClose
public void onClose(Session session,@PathParam(value = "username") String username){
log.info("用户{}已关闭连接", username);
sessionMap.remove(username);
}
/**
* 用于监听该连接上的任何错误,当客户端与该服务端点的连接发生任何异常,都将回调该注解标注的方法
* 注意该方法的参数必选Throwable,可选Sessiion以及0-n个String参数,且String参数需要使用@PathParam注解标注
* @param throwable
* @param username
*/
@OnError
public void onError(Throwable throwable,@PathParam(value = "username") String username){
log.error("用户{}连接发生异常", username);
}
/**
* 用来发送消息的方法,参数分别为接收消息的用户的session,和对应的消息
*/
private void sendMessage(Session toSession,String msg){
try {
toSession.getBasicRemote().sendText(msg);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
3.新建三个websocket在线测试的窗口创建三个链连接
2023-07-09 11:34:13.330 INFO 5812 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 20 ms
2023-07-09 11:34:13.372 INFO 5812 --- [nio-8080-exec-1] org.sang.websocket.SocketServer : 用户初夏1已创建连接
2023-07-09 11:34:15.302 INFO 5812 --- [nio-8080-exec-2] org.sang.websocket.SocketServer : 用户初夏2已创建连接
2023-07-09 11:34:18.101 INFO 5812 --- [nio-8080-exec-3] org.sang.websocket.SocketServer : 用户初夏3已创建连接