Java implements a simple webSocket chat demo
1. Dependence
Add pom file dependency
<!-- websocket-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2. Configuration preparation
Create a webSocketConfig configuration class, that is, register ServerEndpointExporter. This bean is used to scan classes annotated with @ServerEndpoint and serve as the server.
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();
}
}
3. Writing demo code
Create a class annotated with @ServerEndpoint to serve as a webSocket server and specify the connection uri.
Use the annotation to mark the corresponding method, and start the program.
/**
* @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);
}
}
4. Start testing
After the project is started, test whether the websocket is available.
webSocket online test website: Websocket online test link
The log is as follows:
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
: 用户初夏发来消息:你好,我是初夏~
5. Writing business
After successfully completing the basic websocket connection, you can start editing business logic
1. Build the background message entity class;
/**
* @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. Transformation method
@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. Create three new windows for websocket online testing and create three chain connections.
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已创建连接
Test, use Chuxia 2 user to send chat message to Chuxia 3:
We can see that only Chuxia 3 received the chat message, but Chuxia 1 did not:
At this point, we have implemented webSocke technology and implemented the chat function.