WebSocket的使用

websocket与http协议

HTTP 协议有一个缺陷:通信只能由客户端发起。只能是客户端向服务器发出请求,服务器返回查询结果。HTTP 协议做不到服务器主动向客户端推送信息。

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

1,pom.xml依赖注入

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

2,yml配置

server:
  port: 9900
spring:
  application:
    name: mywebsk

3,模拟两个客户端

package com.example.mywebsk.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * 监控用户页面
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    /**
     * 注册两个客户端资源名和路径  代表张三和李四分别登录了聊天页面
     * @param registry
     */
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/zs").setViewName("zs");
        registry.addViewController("/ls").setViewName("ls");
    }
}

4,WebSocket核心

package com.example.mywebsk.config;

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

/**
 * WebSocket核心 存放在spring容器中
 */
@Configuration
public class WebSocketConfig {

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

5,service层

package com.example.mywebsk.services;

import org.springframework.stereotype.Component;

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

/**
 * websocket服务器
 */
@Component
@ServerEndpoint("/socket/{name}")
public class WebSocketServer {
    /**
     * 原子类 在多线程情况 原子类会自动上锁 记录在线人数
     */
    private static AtomicInteger online = new AtomicInteger();
    /**
     * 存放每个客户端对当前服务器WebSocket会话对象
     */
    private static Map<String, Session> sessionPools = new HashMap<String,Session>();

    /**
     * 从服务器给某个session发送数据 此方法名(推荐)
     * @param session
     * @param msg
     * @throws Exception
     */
    public void sendMessage(Session session,String msg) throws Exception{
        if (session != null){
            session.getBasicRemote().sendText(msg);
        }
    }

    /**
     * 用户和服务器建立连接
     * @param session
     * @param username
     */
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "name") String username){
        //向session集合中添加一个用户session
        sessionPools.put(username,session);
        //在线人数加1
        addOnline();
        System.out.println(username+",加入服务器!当前在线人数:"+online);
        try {
            //发送一段信息给登录的用户
            sendMessage(session,username+"欢迎加入聊天室");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 用户退出关闭连接
     * @param username
     */
    @OnClose
    public void onClose(@PathParam("name")String username){
        //按照用户的姓名移出session
        sessionPools.remove(username);
        //在线人数-1
        subOnline();
        System.out.println(username+"断开服务器连接!当前人数:"+online);
    }

    /**
     * 向所有的session对象发送消息 群发
     * @param msg
     * @throws Exception
     */
    @OnMessage
    public void onMessage(String msg){
        for (Session session:sessionPools.values()){
            try {
                sendMessage(session,msg);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 某session发生错误 出异常
     * @param session
     * @param throwable
     */
    @OnError
    public void onError(Session session,Throwable throwable){
        System.out.println("发生错误");
        throwable.printStackTrace();
    }

    /**
     * 指定向某人发消息
     * @param name
     * @param msg
     */
    public void sendInfo(String name, String msg){
        Session session = sessionPools.get(name);
        try {
            sendMessage(session,msg);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 对在线人数的操作 增加
     */
    public static void addOnline(){
        online.incrementAndGet();
    }

    /**
     * 对在线人数的操作 减少
     */
    public static void subOnline(){
        online.decrementAndGet();
    }
}

6,controller层

package com.example.mywebsk.controller;

import com.example.mywebsk.services.WebSocketServer;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

@RestController
public class AfterCtrl {
    @Resource
    private WebSocketServer webSocketServer;

    //服务器给某人发送信息
    @RequestMapping(value = "/socket",method = RequestMethod.GET)
    public void singleSocket(@RequestParam("name")String name,@RequestParam("msg")String msg){
        webSocketServer.sendInfo(name,msg);
    }

    //服务器群发
    @RequestMapping(value = "/socket/all",method = RequestMethod.GET)
    public void collectiveSocket(@RequestParam("msg")String msg){
        webSocketServer.onMessage(msg);
    }
}

7,页面1

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>李四的聊天页面</title>
</head>
<body>
<!--    input[id='text' type='text']+button{发送}+button{关闭}+br+div[id='message']-->
<input type="text" id="text">
<button onclick="collective()">发送</button>
<button onclick="exitTalk()">关闭</button>
<br>
<div id="message"></div>
<script type="text/javascript">
    var webSocket = null;
    if ('WebSocket' in window){
        webSocket = new WebSocket("ws://localhost:9900/socket/ls")

    }else {
        alert("当前浏览器不支持html5的webSocket")
    }
    //在div中写信息的方法
    function setMsg(msg){
        document.getElementById("message").innerHTML += msg +"<br/>"
    }
    //前端webSocket错误处理
    webSocket.onerror = function (){
        setMsg("连接服务器错误");
    }
    //开启websocket服务器连接时获取后端服务器返回的数据
    webSocket.onopen=function (event){
        setMsg("登录");
    }
    // 接受服务器群发或单发的信息
    webSocket.onmessage=function (event){
        setMsg(event.data);
    }
    //服务器关闭后显示的信息
    webSocket.onclose=function (){
        setMsg("bye-bye");
    }
    //用户直接关闭浏览器
    window.onbeforeunload=function (){
        webSocket.close();
    }

    //用户发送信息到群里
    function collective(){
        //获取文本框的值
        var msg = document.getElementById("text").value;
        //发送服务器
        webSocket.send(msg);
    }
    //用户点击按钮退出聊天室
    function exitTalk(){
        webSocket.close();
    }
</script>
</body>
</html>

8,页面2

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>张三的聊天页面</title>
</head>
<body>
<!--    input[id='text' type='text']+button{发送}+button{关闭}+br+div[id='message']-->
<input type="text" id="text">
<button onclick="collective()">发送</button>
<button onclick="exitTalk()">关闭</button>
<br>
<div id="message"></div>
<script type="text/javascript">
    var webSocket = null;
    if ('WebSocket' in window){
        webSocket = new WebSocket("ws://localhost:9900/socket/zs")

    }else {
        alert("当前浏览器不支持html5的webSocket")
    }
    //在div中写信息的方法
    function setMsg(msg){
        document.getElementById("message").innerHTML += msg +"<br/>"
    }
    //前端webSocket错误处理
    webSocket.onerror = function (){
        setMsg("连接服务器错误");
    }
    //开启websocket服务器连接时获取后端服务器返回的数据
    webSocket.onopen=function (event){
        setMsg("登录");
    }
    // 接受服务器群发或单发的信息
    webSocket.onmessage=function (event){
        setMsg(event.data);
    }
    //服务器关闭后显示的信息
    webSocket.onclose=function (){
        setMsg("bye-bye");
    }
    //用户直接关闭浏览器
    window.onbeforeunload=function (){
        webSocket.close();
    }

    //用户发送信息到群里
    function collective(){
        //获取文本框的值
        var msg = document.getElementById("text").value;
        //发送服务器
        webSocket.send(msg);
    }
    //用户点击按钮退出聊天室
    function exitTalk(){
        webSocket.close();
    }
</script>
</body>
</html>

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值