webSocket

WebSocket 是一种网络通信协议,很多高级功能都需要它。

一、简介

WebSocket 协议在2008年诞生,2011年成为国际标准。所有浏览器都已经支持了。

它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。

其他特点包括:

(1)建立在 TCP 协议之上,服务器端的实现比较容易。

(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。

(3)数据格式比较轻量,性能开销小,通信高效。

(4)可以发送文本,也可以发送二进制数据。

(5)没有同源限制,客户端可以与任意服务器通信。

(6)协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。


ws://example.com:80/some/path

 二、springboot+webscoet整合

     1.maven

<!--     websocket   -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>

2.新建configuration文件夹,在里面创建以下几个文件

WebsocketConfig.java

package com.panku.configuration;

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

/**
 * @Author: jack
 * @Description: websocket配置
 * @Date Create in 17:23 2020-02-05
 **/
@Configuration
public class WebsocketConfig {

    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

}

 WebSocketMessageResult.java

package com.panku.configuration;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

/**
 * @program: hycloudoa
 * @description: webScoet消息返回实体
 * @author: xwf
 * @create: 2020-07-02 16:44
 **/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class WebSocketMessageResult implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 消息标题
     */
    private String title;

    /**
     * 消息内容
     */
    private String content;


    /**
     * 消息连接,没有不填
     */
    private String pageUrl;


    /**
     * 消息类型:success/warning/info/error
     */
    private String msgType;

    /**
     * 发送成功消息
     * @param title
     * @param content
     * @param pageUrl
     * @return
     */
    public static WebSocketMessageResult success(String title, String content, String pageUrl){
        return new WebSocketMessageResult(title,content,pageUrl,"success");
    }


    public static WebSocketMessageResult success(String title, String content){
        return success(title,content,null);
    }


    public static WebSocketMessageResult success(String content){
        return success("成功",content,null);
    }
    /**
     * 消息
     * @param title
     * @param content
     * @param pageUrl
     * @return
     */
    public static WebSocketMessageResult info(String title, String content, String pageUrl){
        return new WebSocketMessageResult(title,content,pageUrl,"info");
    }

    /**
     * 错误
     * @param title
     * @param content
     * @param pageUrl
     * @return
     */
    public static WebSocketMessageResult error(String title, String content, String pageUrl){
        return new WebSocketMessageResult(title,content,pageUrl,"error");
    }

    public static WebSocketMessageResult error(String content){
        return  error("错误",content,null);
    }
    /**
     * 警告
     * @param title
     * @param content
     * @param pageUrl
     * @return
     */
    public static WebSocketMessageResult warning(String title, String content, String pageUrl){
        return new WebSocketMessageResult(title,content,pageUrl,"warning");
    }

}
WebSocketServer.java
package com.panku.configuration;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @program: hycloudoa
 * @description: WebSocket配置
 * @author: xwf
 * @create: 2020-06-28 10:00
 **/
@Slf4j
@ServerEndpoint("/imserver/{userIp}")
@Component
public class WebSocketServer {

    /**静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。*/
    private static AtomicInteger onlineCount = new AtomicInteger(0);

    /**
     * 的线程安全的HashMap,存放每个客户端对应的WebSocket对象。
     */
    private static ConcurrentHashMap<String, WebSocketServer> webSocketMap = new ConcurrentHashMap<>();

    /**
     * 用户session会话连接,需通过他来发消息
     */
    private Session session;

    /**
     * 连接用户ip,医生编号
     */
    private String userIp;


    /**
     * 建立连接成功方法
     * @param session session会话
     * @param userIp 连接者id
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("userIp") String userIp){
        this.session = session;
        this.userIp = userIp;
        //如map中不存在用户信息,则添加;如存在,删除重新添加
        if(webSocketMap.containsKey(userIp)){
            webSocketMap.remove(userIp);
            webSocketMap.put(userIp, this);
        }else{
            //加入map
            webSocketMap.put(userIp, this);
            //在线人数+1
            onlineCount.incrementAndGet();
        }
        log.info("用户【{}】连接成功,当前在线人数为:{}",userIp,onlineCount.get());
        sendMessage(WebSocketMessageResult.success("消息服务连接成功"));
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(){
        if(webSocketMap.containsKey(userIp)){
            webSocketMap.remove(userIp);
            //在线人数-1
            onlineCount.decrementAndGet();
        }
        log.info("用户【{}】退出成功,当前在线人数为:{}" ,userIp,onlineCount.get());
    }


    /**
     * 接受客户端消息
     */
    @OnMessage
    public void onMessage(String message, Session session){
        log.info("用户消息【{}】,报文:{}",userIp,message);
        if(!StringUtils.isEmpty(message)){
            JSONObject jsonObject= JSON.parseObject(message);
            //发送人id
            jsonObject.put("fromuserIp",userIp);
            Object touserIp = jsonObject.get("touserIp");
            //传送给对应touserIp用户的websocket
            if(touserIp!=null&&webSocketMap.containsKey(touserIp)){
                webSocketMap.get(touserIp).sendMessage(JSONObject.toJavaObject(jsonObject,WebSocketMessageResult.class));
            }else{
                //否则不在这个服务器上,发送到mysql或者redis
                log.error("请求的userIp:"+touserIp+"不在该服务器上");
            }
        }
    }

    /**
     * 实现服务器主动推送
     * @param message 消息内容
     */
    public void sendMessage(WebSocketMessageResult message){
        try {
            log.info("服务器推送消息【{}】", JSON.toJSONString(message));
            this.session.getBasicRemote().sendText(JSON.toJSONString(message));
        } catch (Exception e) {
            e.printStackTrace();
            log.error("用户【{}】推送消息失败,原因【{}】", userIp, e.getMessage());
        }
    }
    /**
     * 实现服务器主动推送
     */
    public void sendMessage(String message) {
        try {
            this.session.getBasicRemote().sendText(message);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 发送自定义消息
     * @param bizMsg  消息
     */
    public static void sendInfo(BizMsg bizMsg){
        String macceptUser = bizMsg.getMacceptUser();
        if(macceptUser!=null&&webSocketMap.containsKey(macceptUser)){
            webSocketMap.get(macceptUser).sendMessage(JSONObject.toJSONString(bizMsg));
        }else{
            log.error("用户【{}】不在线!",macceptUser);
        }
    }

    /**
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error){
        log.error("用户【{}】错误,原因:{}" ,userIp,error.getMessage());
        error.printStackTrace();
    }





}

 BizMsg.java

package com.panku.configuration;

import lombok.Data;

import java.io.Serializable;

/**
 * <p>
 *
 * </p>
 *
 * @author 盘古
 * @since 2020-11-24
 */
@Data
public class BizMsg implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 消息类型 1刷新 2选呼,顺呼,重呼
     */
    private Integer msgType;
    /**
     * 消息标题
     */
    private String mtitle;

    /**
     * 排号ID
     */
    private Long issueId;

    /**
     * 消息接收人
     */
    private String macceptUser;
    /**
     * 诊室编号
     */
    private String zsbh;


}

JavaScript调用浏览器接口实例如下:

var wsServer = 'ws://localhost:8888/Demo'; //服务器地址
var websocket = new WebSocket(wsServer); //创建WebSocket对象
websocket.send("hello");//向服务器发送消息
alert(websocket.readyState);//查看websocket当前状态
websocket.onopen = function (evt) {
//已经建立连接
};
websocket.onclose = function (evt) {
//已经关闭连接
};
websocket.onmessage = function (evt) {
//收到服务器消息,使用evt.data提取
};
websocket.onerror = function (evt) {
//产生异常
}; 

前端调用代码(完整代码见阿里云盘   "websocket前端测试代码")

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
	</head>
	<body>
		<script src="./js/reconnecting-websocket.js" type="text/javascript" charset="utf-8"></script>
		<script>
			// const userId = `${Date.now()}_${Math.random()}`
			const webHttp = "ws/url"
			let websocket
			
			function initWS () {
			  // 初始化websocket
			  websocket = new ReconnectingWebSocket(webHttp)
			  console.log(webHttp)
			
			  // 监听websocket 连接成功
			  websocket.onopen = function (e) {
			    console.log('-----websocket 连接成功-----')
			  }
			
			  // websocket 连接失败
			  websocket.onerror = function (e) {
			    console.log('-----websocket 连接失败-----')
			  }
			
			  // websocket 连接关闭
			  websocket.onclose = function (e) {
			    console.log('-----websocket 连接关闭------')
			  }
			
			  // websocket 收到消息
			  websocket.onmessage = function (e) {
			    console.log(e)
			    // 接收到消息后,找到对应的订单项目,然后将聊天记录加入
			    let msg = e.data
			    // instanceof 就是判断一个实例是否属于某种类型
			    msg = msg instanceof Object ? msg : JSON.parse(msg)
			    console.log(msg)
			  }
			}
			
			// 发送消息,格式化数据
			function xiaoXis (msgObj) {
			  // 发送消息
			  console.log('发送消息', msgObj)
			  websocket.send(JSON.stringify(msgObj))
			}
		</script>
	</body>
</html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值