springboot+websocket实现聊天即时通讯

springboot+websocket实现聊天即时通讯

1.在很多业务场景中,对实时数据要求比较高,我们就不能采用轮训拉取的方式来获取数据了。就可以采用websocket的长链接的形式,实时有服务端或者客户端推送数据,已达到数据的实时展示。

目录

springboot+websocket实现聊天即时通讯_第1张图片

WebSocketConfig

package com.example.springboot_websocket.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

@Configuration
public class WebSocketConfig {

    /**
     * 服务器节点
     *
     * 如果使用独立的servlet容器,而不是直接使用springboot的内置容器,就不要注入ServerEndpointExporter,因为它将由容器自己提供和管理
     * @return
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

}

WebsocketController

package com.example.springboot_websocket.controller;
import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * websocket类
 * @ServerEndpoint: socket链接地址
 */
@ServerEndpoint("/websocket/{username}")
@Controller
public class WebsocketController {
 
    private Logger logger = LoggerFactory.getLogger(this.getClass());




    
    /**
     * 在线人数
     */
    public static int onlineNumber = 0;
    /**
     * 以用户的姓名为key,WebSocket为对象保存起来
     */
    private static Map clients = new ConcurrentHashMap();
    /**
     * 会话
     */
    private Session session;
    /**
     * 用户名称
     */
    private String username;
    
    
    /**
     *   进入聊天室 --> 项目中读取用户信息获取用户名 
     */
    @RequestMapping("/websocket")
    public String webSocket(Model model) {
        
        //定义随机时间戳名称
        String name = "游客:";
        //String  datename = new SimpleDateFormat("yyyyMMddHHmmsss").format(new Date());
        String  datename = new SimpleDateFormat("msss").format(new Date());
        name = name + datename;
        
        //websock链接地址+游客名-->  项目中请定义在配置文件 -->或直接读取服务器,ip 端口
        // 读取服务器,ip 端口可看:https://blog.csdn.net/qq_41463655/article/details/92002474
        String path="ws://127.0.0.1:8080/websocket/";
        model.addAttribute("path",path);
        model.addAttribute("username",name);
        return "socket";
    }

    
    /**
     * 监听连接(有用户连接,立马到来执行这个方法)
     * session 发生变化
     *
     * @param session
     */
    @OnOpen
    public void onOpen(@PathParam("username") String username, Session session) {
        onlineNumber++;
        //把新用户名赋给变量
        this.username = username;
        //把新用户的 session 信息赋给变量
        this.session = session;
        //输出 websocket 信息
        logger.info("现在来连接的客户id:" + session.getId() + "用户名:" + username);
        logger.info("有新连接加入! 当前在线人数" + onlineNumber);
        try {
            //把自己的信息加入到map当中去,this=当前类(把当前类作为对象保存起来)
            clients.put(username, this);
            //获得所有的用户
            Set lists = clients.keySet();

            // 先给所有人发送通知,说我上线了
            //messageType 1代表上线 2代表下线 3代表在线名单 4代表普通消息
            Map map1 = new HashMap();
            //  把所有用户列表
            map1.put("onlineUsers", lists);
            //  返回上线状态
            map1.put("messageType", 1);
            //  返回用户名
            map1.put("username", username);
            //  返回在线人数
            map1.put("number", onlineNumber);
            //  发送全体信息(用户上线信息)
            sendMessageAll(JSON.toJSONString(map1), username);


            // 给自己发一条消息:告诉自己现在都有谁在线
            Map map2 = new HashMap();
            //messageType 1代表上线 2代表下线 3代表在线名单 4代表普通消息
            map2.put("messageType", 3);
            //把所有用户放入map2
            map2.put("onlineUsers", lists);
            //返回在线人数
            map2.put("number", onlineNumber);
            // 消息发送指定人(所有的在线用户信息)
            sendMessageTo(JSON.toJSONString(map2), username);
        } catch (IOException e) {
            logger.info(username + "上线的时候通知所有人发生了错误");
        }
    }


    /**
     * 监听连接断开(有用户退出,会立马到来执行这个方法)
     */
    @OnClose
    public void onClose() {
        onlineNumber--;        
        //所有在线用户中去除下线用户
        clients.remove(username); 
        try {
            //messageType 1代表上线 2代表下线 3代表在线名单  4代表普通消息
            Map map1 = new HashMap();
            map1.put("messageType", 2);
            //所有在线用户
            map1.put("onlineUsers", clients.keySet());
            //下线用户的用户名
            map1.put("username", username);
            //返回在线人数
            map1.put("number", onlineNumber);
            //发送信息,所有人,通知谁下线了
            sendMessageAll(JSON.toJSONString(map1), username);
        } catch (IOException e) {
            logger.info(username + "下线的时候通知所有人发生了错误");
        }
        logger.info("有连接关闭! 当前在线人数" + onlineNumber);
    }

    @OnError
    public void onError(Session session, Throwable error) {
        logger.info("服务端发生了错误" + error.getMessage());
        //error.printStackTrace();
    }

    /**
     * 监听消息(收到客户端的消息立即执行)
     *
     * @param message 消息
     * @param session 会话
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        try {
            logger.info("来自客户端消息:" + message + "客户端的id是:" + session.getId());
            //用户发送的信息
            com.alibaba.fastjson.JSONObject jsonObject = JSON.parseObject(message);
            //发送的内容
            String textMessage = jsonObject.getString("message");
            //发送人
            String fromusername = jsonObject.getString("username");
            //接收人  to=all 发送消息给所有人 || to= !all   to == 用户名
            String tousername = jsonObject.getString("to");

            //发送消息  -- messageType 1代表上线 2代表下线 3代表在线名单  4代表消息
            Map map1 = new HashMap();
            map1.put("messageType", 4);
            map1.put("textMessage", textMessage);
            map1.put("fromusername", fromusername);
            if (tousername.equals("All")) {
                //消息发送所有人(同步)
                map1.put("tousername", "所有人");
                sendMessageAll(JSON.toJSONString(map1), fromusername);
            } else {
                //消息发送指定人(同步)
                map1.put("tousername", tousername);
                sendMessageTo(JSON.toJSONString(map1), tousername);
            }
        } catch (Exception e) {
            logger.info("发生了错误了");
        }
    }

    /**
     *  消息发送指定人
     */
    public void sendMessageTo(String message, String ToUserName) throws IOException {
        //遍历所有用户
        for (WebsocketController item : clients.values()) {
            if (item.username.equals(ToUserName)) {
                //消息发送指定人(同步)
                item.session.getBasicRemote().sendText(message);
                break;
            }
        }
    }

    /**
     *  消息发送所有人
     */
    public void sendMessageAll(String message, String FromUserName) throws IOException {
        for (WebsocketController item : clients.values()) {
            //消息发送所有人(同步)getAsyncRemote
            item.session.getBasicRemote().sendText(message); 
        }
    }

    public static synchronized int getOnlineCount() {
        return onlineNumber;
    }
}





/*
 *  注解说明
 *  @MessageMapping(value = "/chat")   // 匹配客户端 send 消息时的URL
 *  @SendTo("/topic/getResponse")      //用于给客户端订阅广播消息
 *  @SendToUser(value = "/personal")   //用于给客户端订阅点对点消息;
 *  @Payload:使用客户端 STOMP 帧的 body 赋值
 *  @Header(“xxx”):使用客户端 STOMP 帧的 headers 中的 xxx 赋值
 *
 **/

/**
 * 广播推送
 **/
//    @MessageMapping(value = "/chat") // 匹配客户端 send 消息时的URL
//    @SendTo("/topic/getResponse")   //分别用于给客户端订阅广播消息
//    public String talk(@Payload String text, @Header("simpSessionId") String sessionId) throws Exception {
//        return "【" + sessionId + "】说:【" + text + "】";
//    }
  
/**
 * 点对点推送
 */
/*
    @MessageMapping(value = "/speak")  // 匹配客户端 send 消息时的URL
    @SendToUser(value = "/personal")   //分别用于给客户端订阅点对点消息;
    public String speak(@Payload String text, @Header("simpSessionId") String sessionId) throws Exception {
        return text;
    }
    */

/**
 * 异常信息推送
 */
/*
    @MessageExceptionHandler
    @SendToUser(value = "/errors")
    public String handleException(Throwable exception) {
        return exception.getMessage();
    }*/

SpringbootWebsocketApplication

package com.example.springboot_websocket;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringbootWebsocketApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootWebsocketApplication.class, args);
    }

}

socket.html




    
    
    
    
    
    
    
    websocket
    
    
    















  • 群聊信息
  • 在线列表
  • 消息发送至:
  • 私聊信息


  • pom

    
    
        4.0.0
        
            org.springframework.boot
            spring-boot-starter-parent
            2.1.5.RELEASE
             
        
        com.example
        springboot_websocket
        0.0.1-SNAPSHOT
        springboot_websocket
        Demo project for Spring Boot
    
        
            1.8
        
    
        
    
            
            
                org.springframework.boot
                spring-boot-starter-thymeleaf
            
    
            
            
            
                com.alibaba
                fastjson
                1.2.54
            
    
            
            
                org.springframework.boot
                spring-boot-devtools
                true
            
    
            
            
                org.springframework.boot
                spring-boot-starter-websocket
            
    
            
                org.springframework.boot
                spring-boot-starter-web
            
    
            
                org.springframework.boot
                spring-boot-starter-test
                test
            
        
    
        
            
                
                    org.springframework.boot
                    spring-boot-maven-plugin
                
            
        
    
    
    

    测试结果
    springboot+websocket实现聊天即时通讯_第2张图片

    你可能感兴趣的:(java,springboot,websocket,spring,boot,websocket,windows)