原生SSM整合WebSocket

实现了消息的单发和群发,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;

    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值