欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

原生SSM整合WebSocket

程序员文章站 2022-10-03 17:05:39
实现了消息的单发和群发,**Tomcat8**及以上版本才可使用,看清楚**util**工具类的格式,可以重新定义消息的格式,前端发消息也要按这个格式发,一段时间不访问服务器,服务器一般会断开连接,可以做一个心跳包,每隔几十秒访问一次服务器,这样服务器就不会断开连接了,心跳包是前端做的,最好再让前端做一个重连,防止意外情况。依赖 org.springframework
实现了消息的单发和群发,Tomcat8及以上版本才可使用,看清楚util工具类的格式,可以重新定义消息的格式,前端发消息也要按这个格式发,一段时间不访问服务器,服务器一般会断开连接,可以做一个心跳包,每隔几十秒访问一次服务器,这样服务器就不会断开连接了,心跳包是前端做的,最好再让前端做一个重连,防止意外情况。

依赖

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-websocket</artifactId>
            <version>5.1.16.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-websocket</artifactId>
            <version>8.5.31</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-messaging</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>

Java代码

config

这个类controller里会用,但是里面不要写bean,写了在服务器上会报错

import org.springframework.context.annotation.Configuration;
@Configuration
public class WebSocketConfig {
 //里面什么也不写,否则到服务器上会报错
}

controller

客户端的注册onOpen方法
客户端发送消息onMessage方法
客户端下线onClose方法
客户端异常断开连接(断网,强制中断连接等)onError方法
通知其他客户端noticeUser方法

import com.fasterxml.jackson.databind.ObjectMapper;
import com.web.chat.pojo.Message;
import com.web.chat.util.MessageUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.socket.server.standard.SpringConfigurator;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
//前端访问地址ws://..../chat.do/{当前客户端的标识}
@Controller
@ServerEndpoint(value = "/chat.do/{username}",configurator = SpringConfigurator.class)
public class ChatEndpoint {

    private static Map<String, Session> onlineUsers= new ConcurrentHashMap<>();

    /**
     * 连接建立时调用
     * @param session  长连接
     * @param username  用户名
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("username") String username){
        //将对象存储到容器中
        onlineUsers.put(username, session);
        //通知其他客户端
        noticeUser(username,onlineUsers);
    }

    /**
     *  接收到客户端发送的数据时被调用
     * @param message  消息的具体内容
     * @param session  长连接
     */
    @OnMessage
    public void onMessage(String message, Session session){
        try {
            //将message转化成message对象
            ObjectMapper mapper = new ObjectMapper();
            Message mess = mapper.readValue(message, Message.class);
            String username = mess.getUsername();
            //获取发送目标
            List<String> users = mess.getUsers();
            //获取消息数据
            String data = mess.getMessage();
            //获取数据类型,是否是心跳包
            String messageType = mess.getMessageType();
            //不是心跳包
            if (!Message.HEARTBEAT.equals(messageType)){
                //保存数据到数据库
                //这里可以写方法,把数据存到数据库中
                
                //获取推送给指定用户的消息格式的数据
                String resultMessage = MessageUtils.getMessage(false, username, data,"");
                //发送数据
                if (users .size()>0){
                    for (String user : users ) {
                        if (onlineUsers.get(user)!=null){
                            onlineUsers.get(user).getBasicRemote().sendText(resultMessage);
                        }
                    }
                }
            }
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 连接断开时调用
     * @param session  长连接
     * @param username  用户名
     */
    @OnClose
    public void onClose(Session session, @PathParam("username") String username){
        //从容器中删除当前的用户
        onlineUsers.remove(username);
        //通知所有客户端
        noticeUser(username,onlineUsers);
    }

    /**
     * 异常处理
     * @param session  长连接
     * @param error  异常
     * @param username  用户名
     */
    @OnError
    public void onError(Session session, Throwable error, @PathParam("username")String username) {
    	//可以打印异常,可以把异常放到日志中
        //error.printStackTrace();
        //调用关闭链接方法,关闭链接
        onClose(session,username);
    }

    /**
     * 通知所有在线客户
     * @param username 用户的唯一标识
     * @param onlineUsers 缓存中用户
     */
    public void noticeUser(String username,Map<String,Session> onlineUsers){
        List<String> onlineNurseList = chatService.onlineNurseList(username,onlineUsers);
        try {
            if (onlineNurseList.size()>0){
                for (String nurse : onlineNurseList) {
                    if (onlineUsers.get(nurse)!=null){
                        String resultMessage = MessageUtils.getMessage(true, null,username,"");
                        onlineUsers.get(nurse).getBasicRemote().sendText(resultMessage);
                    }
                }
            }
        } catch (Exception e){
            e.printStackTrace();
        }
    }

}

pojo

Message 类

  接收前端传过来的参数
import java.io.Serializable;
import java.util.List;

public class Message implements Serializable {
	//心跳包
    public static final String HEARTBEAT="heartbeat";

	//注册用户的唯一标识
    private String username;

	//要发送的目标
    private List<String> users;

	//消息内容
    private String message;

	//消息类型,判断是不是心跳包,
    private String messageType;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public List<String> getUsers() {
        return users;
    }

    public void setUsers(List<String> users) {
        this.users = users;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public String getMessageType() {
        return messageType;
    }

    public void setMessageType(String messageType) {
        this.messageType = messageType;
    }
}

ResultMessage 类

 封装消息格式的类
import java.io.Serializable;

public class ResultMessage implements Serializable {
	//判断是不是系统消息
    private boolean isSystem;

	//发送人
    private String fromName;

	//消息内容
    private Object message;

	//消息类型,这是判断心跳包的
    private String messageType;

    public boolean isSystem() {
        return isSystem;
    }

    public void setSystem(boolean system) {
        isSystem = system;
    }

    public String getFromName() {
        return fromName;
    }

    public void setFromName(String fromName) {
        this.fromName = fromName;
    }

    public Object getMessage() {
        return message;
    }

    public void setMessage(Object message) {
        this.message = message;
    }

    public String getMessageType() {
        return messageType;
    }

    public void setMessageType(String messageType) {
        this.messageType = messageType;
    }
}

util

封装消息的工具类
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.web.chat.pojo.ResultMessage;

public class MessageUtils {
    public static String getMessage(boolean isSystemMessage,String fromName,Object message,String messageType){
        try {
            ResultMessage result = new ResultMessage();
            result.setSystem(isSystemMessage);
            result.setMessage(message);
            result.setMessageType(messageType);
            if (fromName != null){
                result.setFromName(fromName);
            }
            ObjectMapper mapper = new ObjectMapper();
            return mapper.writeValueAsString(result);
        } catch (JsonProcessingException e){
            e.printStackTrace();
        }
        return null;

    }
}

本文地址:https://blog.csdn.net/weixin_46765054/article/details/107490847

相关标签: Java spring