WebSocket案例

18 篇文章 0 订阅
11 篇文章 0 订阅

群聊原型

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;


@Component
@ServerEndpoint(value = "/socket/{id}")
public class WebSocketServer {
 
    private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketServer.class);
 
    /**用来记录当前在线连接数*/
    private static int onLineCount = 0;
 
    /**用来存放每个客户端对应的WebSocketServer对象*/
    private static ConcurrentHashMap<String,WebSocketServer> webSocketMap = new ConcurrentHashMap<String, WebSocketServer>();
    
    private Session session;
 
    private String id;
 
    /**
     * 连接建立成功,调用的方法,与前台页面的onOpen相对应
     */
    @OnOpen
    public void onOpen(@PathParam("id")String id, Session session){
        //根据业务,自定义逻辑实现
        this.session = session;
        this.id= id;
        webSocketMap.put(id,this);  //将当前对象放入map中
        addOnLineCount();  //在线人数加一
        LOGGER.info("有新的连接加入,id:{}!当前在线人数:{}",ip,getOnLineCount());
    }
 
    /**
     * 连接关闭调用的方法,与前台页面的onClose相对应
     */
    @OnClose
    public void onClose(@PathParam("id")String id){
        webSocketMap.remove(id);  //根据id(key)移除WebSocketServer对象
        subOnLineCount();
        LOGGER.info("WebSocket关闭,id:{},当前在线人数:{}",id,getOnLineCount());
    }
 
    /**
     * 当服务器接收到客户端发送的消息时所调用的方法,与前台页面的onMessage相对应
     */
    @OnMessage
    public void onMessage(String message,Session session){
        //根据业务,自定义逻辑实现
        LOGGER.info("收到客户端的消息:{}",message);
    }
 
    /**
     * 发生错误时调用,与前台页面的onError相对应
     */
    @OnError
    public void onError(Session session,Throwable error){
        LOGGER.error("WebSocket发生错误");
        error.printStackTrace();
    }
 
    /**
     * 给当前用户发送消息
     */
    public void sendMessage(String message){
        try{
            //getBasicRemote()是同步发送消息,这里我就用这个了,推荐大家使用getAsyncRemote()异步
            this.session.getBasicRemote().sendText(message);
        }catch (IOException e){
            e.printStackTrace();
            LOGGER.info("发送数据错误:,id:{},message:{}",id,message);
        }
    }
 
    /**
     * 给所有用户发消息
     */
    public static void sendMessageAll(final String message){
        //使用entrySet而不是用keySet的原因是,entrySet体现了map的映射关系,遍历获取数据更快。
        Set<Map.Entry<String, WebSocketServer>> entries = webSocketMap.entrySet();
        for (Map.Entry<String, WebSocketServer> entry : entries) {
            final WebSocketServer webSocketServer = entry.getValue();
            //这里使用线程来控制消息的发送,这样效率更高。
            new Thread(new Runnable() {
                @Override
                public void run() {
                    webSocketServer.sendMessage(message);
                }
            }).start();
        }
    }
 
    /**
     * 获取当前的连接数
     */
    public static synchronized int getOnLineCount(){
        return WebSocketServer.onLineCount;
    }
 
    /**
     * 有新的用户连接时,连接数自加1
     */
    public static synchronized void addOnLineCount(){
        WebSocketServer.onLineCount++;
    }
 
    /**
     * 断开连接时,连接数自减1
     */
    public static synchronized void subOnLineCount(){
        WebSocketServer.onLineCount--;
    }
 
    public Session getSession(){
        return session;
    }
    public void setSession(Session session){
        this.session = session;
    }
 
    public static ConcurrentHashMap<String, WebSocketServer> getWebSocketMap() {
        return webSocketMap;
    }
 
    public static void setWebSocketMap(ConcurrentHashMap<String, WebSocketServer> webSocketMap) {
        WebSocketServer.webSocketMap = webSocketMap;
    }
}

简单使用

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpSession;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

@Component
@ServerEndpoint(value = "/socket/{id}")
public class EndpointService {

    private final static Logger LOGGER = LogManager.getLogger(EndpointService.class);

    private HttpSession httpSession;

    /**某个客户端的连接会话,需要通过它来给客户端发送数据*/
    private Session session;

    private static ConcurrentHashMap<String,EndpointService> webSocketMap = new ConcurrentHashMap<String, EndpointService>();

    private String id;

    /**
     * 连接建立成功,调用的方法,与前台页面的onOpen相对应
     */
    @OnOpen
    public void onOpen(@PathParam("id")String id, Session session){
        //根据业务,自定义逻辑实现
        this.session = session;
        this.id= id;
        webSocketMap.put(ip, this);
        LOGGER.info("有新的连接加入,id:{}!当前在线人数:{}",id);
    }

    /**
     * 连接关闭调用的方法,与前台页面的onClose相对应
     */
    @OnClose
    public void onClose(@PathParam("id")String ip){
        webSocketMap.remove(id);
        LOGGER.info("WebSocket关闭,id:{},当前在线人数:{}",id);
    }

    /**
     * 当服务器接收到客户端发送的消息时所调用的方法,与前台页面的onMessage相对应
     */
    @OnMessage
    public void onMessage(String message,Session session){
        //根据业务,自定义逻辑实现
        LOGGER.info("收到客户端的消息:{}",message);
        sendMessageAll(message);
    }

    /**
     * 发生错误时调用,与前台页面的onError相对应
     */
    @OnError
    public void onError(Session session,Throwable error){
        LOGGER.error("WebSocket发生错误");
        error.printStackTrace();
    }

    /**
     * 给所有用户发消息
     */
    public static void sendMessageAll(final String message){
        //使用entrySet而不是用keySet的原因是,entrySet体现了map的映射关系,遍历获取数据更快。
        Set<Map.Entry<String, EndpointService>> entries = webSocketMap.entrySet();
        for (Map.Entry<String, EndpointService> entry : entries) {
            final EndpointService endpointService = entry.getValue();
            //这里使用线程来控制消息的发送,这样效率更高。
            new Thread(new Runnable() {
                @Override
                public void run() {
                    endpointService.sendMessage(message);
                }
            }).start();
        }
    }

    /**
     * 给当前用户发送消息
     */
    public void sendMessage(String message){
        try{
            //getBasicRemote()是同步发送消息,这里我就用这个了,推荐大家使用getAsyncRemote()异步
            this.session.getBasicRemote().sendText(message);
        }catch (IOException e){
            e.printStackTrace();
            LOGGER.info("发送数据错误:,id:{},message:{}",id,message);
        }
    }
}

前台代码

<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" th:src="@{/js/jquery-2.1.1.min.js}"></script>
    <style type="text/css">
        .bis{
            display: block;
        }
    </style>
</head>
<body>
<img src="/index/getCaptcha" style="width:80px; height: 30px;"/>
<div>
    <label class="bis">
        用户名:<input type="text" id="username" value="" />
    </label>
    <label class="bis">
        编号:<input type="text" id="userid" value="" />
    </label>
    <label class="bis">
        性别:<input type="text" id="gender" value="" />
    </label>
    <button onclick="joinIn()">加入</button><span id="errMag" style="color: red;"></span>
</div>
<div id="divWin" style="width: 400px;height: 200px;background-color: #bbe6ff;overflow-y: auto;">

</div>
<textarea id="editMsg" style="width: 400px;height: 100px;background-color: #bbffbc"></textarea>
<button onclick="sendMsg()">发送</button>
</body>
<script type="text/javascript">
let webSocket;
let userId;
let username;
$(function () {
})
// 加入群聊
function joinIn() {
    let id = $("#userid").val();
    let name = $("#username").val();
    if (!id || !name) {
        $("#errMag").text("加入失败,请输入用户信息!");
        return false;
    }else {
        userId = id;
        username = name;
        connection();
    }
}
// 建立连接
function connection() {
    let host = window.location.host;//带有端口号
    let wsUri = `ws://${host}/socket/${userId}`;
    webSocket = new WebSocket(wsUri);
    $("#divWin").html($("#divWin").html()+wsUri);

    /**
     * 建立链接
     */
    webSocket.onopen = function () {
        console.log(`<p>用户:${username}<span style='float: right;color: greenyellow;'>上线了</span></p>`);
        $("#divWin").html($("#divWin").html()+`<p>用户:${username}<span style='float: right;color: greenyellow;'>上线了</span></p>`);
    }

    /**
     * 接收到服务端返回的消息
     * @param event
     */
    webSocket.onmessage = function (event) {
        let result = JSON.parse(event.data);
        console.log(result);
        $("#divWin").html($("#divWin").html()+`<br/>${result.fromName}${result.message}`);
    }

    // 关闭连接
    webSocket.onclose = function () {
        $("#divWin").html($("#divWin").html()+`用户:${username}<span style="color:red;">离线</span>`);
    }

    // 出现错误
    webSocket.onerror = function () {
        console.log("=========οnerrοr=========");
        $("#divWin").html($("#divWin").html()+"连接出错");
    }
}
// 发送消息
function sendMsg() {
    let msg = $("#editMsg").val();
    if (msg) {
        let jsonMessage = {
            "fromName": username, //消息发送人姓名
            "fromId": userId, //消息发送人id
            "toName": "", //消息接收人姓名
            "toId": "", //消息接收人id
            "message": msg //发送的消息内容
        };
        webSocket.send(JSON.stringify(jsonMessage));
        $("#editMsg").val('');
    }
}
</script>
</html>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值