java实现一个简单的webSocket聊天demo

一、依赖

添加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();
    }
}

三、demo代码编写

创建被@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已创建连接

测试,用初夏2用户给初夏3发聊天消息:
在这里插入图片描述

我们可以看到,只有初夏3收到了聊天消息,初夏1没收到:
在这里插入图片描述
在这里插入图片描述
到这里,我们就实现了webSocke技术,实现聊天功能了。

猜你喜欢

转载自blog.csdn.net/m0_37899908/article/details/131620267