springboot配置WebSocket踩坑探索记录(其实挺简单的·_·)

新建springboot项目省略。。。。

pom添加:

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

application配置文件:

spring.application.name=thinkd-webserve
server.port=9800
#server.port=${random.int(9800,9809)}
eureka.instance.ip-address=true
eureka.client.service-url.defaultZone=http://localhost:9000/eureka,http://localhost:9001/eureka

新建html文件,放到资源static目录下:

<!DOCTYPE html>
<!--<html xmlns:th="http://www.thymeleaf.org">-->
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>HELLO WEBSOCKET!</title>
    <!-- 微软压缩版 -->
    <script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-3.5.1.min.js"></script>
<!--    &lt;!&ndash; 官网压缩版 &ndash;&gt;-->
<!--    <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>-->
</head>
<body>
    <h2 align="center" style="color: red"> 欢迎欢迎热烈欢迎!!!</h2>
    <p align="center" style="color: blue">
        这是第一个WebSocket页面啊!!!!!!!!!!
    </p>
    <div align="center">
        <form action="#" id="wsreqform">
            <span style="color: brown"><b>WSmsg: </b></span>&emsp14;
            <input type="text" name="message" value="发送一句话吧"/>

            <br/><br/><span style="color: brown"><b>提交: </b></span>&emsp13;
            <input type="submit" id="subws01"/>
        </form>
    </div>
</body>

</html>


<script type="text/javascript">
    // var socket;
    var index;
    var msgs;
    var ws_id = 2;
    var basepath = "http://localhost:9800/webserve/";//自己的项目访问URI

    $(function () {
        socketChecks();

        verifyMsgInfo();
    });

    function socketChecks() {
        if(typeof(WebSocket) == "undefined") {
            console.log(">>>>>>>>>> 您的浏览器不支持WebSocket");
            alert("您的浏览器不支持WebSocket");
        }else{
            console.log(">>>>>>>>>> 您的浏览器支持WebSocket");
            //实现化WebSocket对象,指定要连接的服务器地址与端口  建立连接
            //等同于
            // index = new WebSocket("ws://"+ host +":"+ port +"/websocket/" + ws_id);
            index = new WebSocket((basepath + "websocket/" + ws_id).replace("http", "ws"));
            //socket = new WebSocket("${basepath}websocket/${cid}".replace("http","ws"));
            //打开事件
            index.onopen = function() {
                console.log(">>>>>>>>>> WebSocket 已打开");
                //socket.send("这是来自客户端的消息" + location.href + new Date());
            };
            //获得消息事件
            index.onmessage = function(msg) {
                console.log(">>>>>>>>>> 发现消息进入  开始处理前端触发逻辑");
                console.log(">>>>>>>>>> WebSocket获得信息: " + msg.data);
                alert(msg.data);
            };
            //关闭事件
            index.onclose = function() {
                console.log(">>>>>>>>>> WebSocket 已关闭");
            };
            //发生了错误事件
            index.onerror = function() {
                console.log(">>>>>>>>>> WebSocket 发生了错误,可以尝试刷新页面");
                alert("WebSocket错误,请尝试刷新页面");
            }           
        }

    }
    // //生成从minNum到maxNum的随机数
    // function randomNum(minNum, maxNum) {
    //     switch (arguments.length) {
    //         case 1:
    //             return parseInt(Math.random() * minNum + 1, 10);
    //             // break;
    //         case 2:
    //             return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10);
    //             // break;
    //         default:
    //             return 0;
    //             // break;
    //     }
    // }

    function verifyMsgInfo() {
        $("#subws01").click(function () {
            // var msgs = $("#wsreqform input[type='text']").value();
            var formData = $("#wsreqform input[type='text']").serialize();
            console.log(" ^^^^^^^^^^^^^^^^ 客户端WebSocket请求参数JSON:" + formData);
            alert(formData);
            //提交URL
            var wsurl = basepath + "sysWS/socket/push/" + ws_id;

            getTestSocket(wsurl, formData);
            return false;
        });
    }

    function getTestSocket(wsurl, wsparam){
        $.ajax({
            type: "post",
            url: wsurl.toString().trim(),
            // data: {},
            data: wsparam,
            dataType: "json",
            success: function (data) {
                console.log(" ^^^^^^^^^^^^^^^^ 服务器WebSocket数据返回正确!" + data.toString());
            },
            error: function () {
                console.log(" ^^^^^^^^^^^^^^^^ 服务器WebSocket数据异常了!");
                alert("【服务器WebSocket数据异常了】");
            }
        });
    }
</script>

websocket配置文件:

//@Configuration
@Component   //开启WebSocket支持
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

websocket服务类:

@ServerEndpoint("/websocket/{sid}")
@Component
@Slf4j
public class WebSocketServer {
    //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int onlineCount = 0;
    //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
    private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();

    //与某个客户端的连接会话,需要通过它来给客户端发送数据
    private Session session;
    //接收sid
    private String sid = "";

    //连接建立成功调用的方法
    @OnOpen
    public void onOpen(Session session, @PathParam("sid") String sid) {
        this.session = session;
        webSocketSet.add(this);     //加入set中
        addOnlineCount();           //在线数加1
        log.info("有新窗口开始监听:" + sid + ",当前在线人数为" + getOnlineCount());
        this.sid = sid;
        try {
            sendMessage("连接成功");
        } catch (IOException e) {
            log.error("websocket IO异常");
        }
    }

    //连接关闭调用的方法
    @OnClose
    public void onClose() {
        webSocketSet.remove(this);  //从set中删除
        subOnlineCount();           //在线数减1
        log.info("有一连接关闭!当前在线人数为" + getOnlineCount());
    }

    //收到客户端消息后调用的方法  message 客户端发送过来的消息
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("收到来自窗口" + sid + "的信息:" + message);
        //群发消息
        for (WebSocketServer item : webSocketSet) {
            try {
                item.sendMessage(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    //  通信异常方法
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("发生错误");
        error.printStackTrace();
    }

    //实现服务器主动推送
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }

    // 群发自定义消息
    public static void sendInfo(String message, @PathParam("sid") String sid) throws IOException {
        log.info("推送消息到窗口" + sid + ",推送内容:" + message);
        for (WebSocketServer item : webSocketSet) {
            try {
                //这里可以设定只推送给这个sid的,为null则全部推送
                if (sid == null) {
                    item.sendMessage(message);
                } else if (item.sid.equals(sid)) {
                    item.sendMessage(message);
                }
            } catch (IOException e) {
                continue;
            }
        }
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }

    public static CopyOnWriteArraySet<WebSocketServer> getWebSocketSet() {
        return webSocketSet;
    }
}

写个controller:

@Controller
@RequestMapping("/sysWS")
public class WebsocketSysController {
    //@Autowired
    //private ThymeleafViewResolver thymeleafViewResolver;
    //@Autowired
    //private MessageSource messageSource;

    //页面请求
    //@RequestMapping(value = "/index/{userId}", method = RequestMethod.GET)
    //public String socket(@PathVariable("userId") String userId) {
    @GetMapping(value = "/actiond")
    //public String socket(@RequestParam("userId") String userId) {//, Model model) {
    //    //ModelAndView mav = new ModelAndView("/wstest1");
    //    //mav.addObject("userId", userId);
    //    //model.addAttribute("userId", userId);
    //    return "wstest1";
    //}
    public Object getSocketd(ModelMap model){
        model.addAttribute("aaa","我是一个兵");
        model.addAttribute("bbb","来自老百姓!");
        return "wstest1";//自定义的html文件
    }

    @ResponseBody   //推送提交数据接口
    @RequestMapping("/socket/push/{cid}")
    public Map pushToWeb(@PathVariable("cid") String cid, String message) {
        Map result = new HashMap();
        try {
            WebSocketServer.sendInfo(message, cid);
            result.put("code", 200);
            result.put("msg", "success");
        } catch (IOException e) {
            e.printStackTrace();
            result.put("code", 500);
            result.put("msg", "ERROR");
        }
        System.out.println("响应数据:》》》》》》》》》 "+JSONObject.toJSONString(result));
        return result;
    }

启动类加上注解:@EnableDiscoveryClient

创建eureka注册中心

pom文件:
	<dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR8</spring-cloud.version>
    </properties>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>    
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
    
*配置文件node01:*
## 两个注册服务name必须一样,不然高可用会导致unavailable-replicas
spring.application.name=thinkd-eureka
#server.port=${random.int(9000,9003)}
server.port=9000

# 指定通过IP注册,一般服务集群时配置,需要ip-address参数一起设置(保证hostName和ip-address一样),
# 以免eureka管理页面出现不可用分片提示信息(unavailable-replicas),
# 服务的注册默认是通过hostName注册的,当判断注册的hostName和服务
eureka.instance.prefer-ip-address=true
# 强制指定eureka的ip地址
eureka.instance.ip-address=${EUREKA_IP:${eureka.instance.hostname}}
# eureka server管理页面显示的服务状态
eureka.instance.instance-id=${eureka.instance.hostname}:${server.port}
eureka.instance.hostname=eureka01
# 集群时需要强制手动指定,fetch-registry、register-with-eureka都需要设置为true
eureka.client.fetch-registry=true
eureka.client.register-with-eureka=true
#eureka.client.service-url.defaultZone=http://localhost:${server.port}/eureka
eureka.client.service-url.defaultZone=http://eureka02:9001/eureka

*配置文件node02:*
## 两个注册服务name必须一样,不然高可用会导致unavailable-replicas
spring.application.name=thinkd-eureka
#server.port=${random.int(9000,9003)}
server.port=9001

# 指定通过IP注册,一般服务集群时配置,需要ip-address参数一起设置(保证hostName和ip-address一样),
# 以免eureka管理页面出现不可用分片提示信息(unavailable-replicas),
# 服务的注册默认是通过hostName注册的,当判断注册的hostName和服务
eureka.instance.prefer-ip-address=true
# 强制指定eureka的ip地址
eureka.instance.ip-address=${EUREKA_IP:${eureka.instance.hostname}}
# eureka server管理页面显示的服务状态
eureka.instance.instance-id=${eureka.instance.hostname}:${server.port}
eureka.instance.hostname=eureka02
# 集群时需要强制手动指定,fetch-registry、register-with-eureka都需要设置为true
eureka.client.fetch-registry=true
eureka.client.register-with-eureka=true
#eureka.client.service-url.defaultZone=http://localhost:${server.port}/eureka
eureka.client.service-url.defaultZone=http://eureka01:9000/eureka

**配置启动:**
# 项目启动会加载激活的配置文件,系统会按需加载配置文件
spring.profiles.active=node02

> 启动类添加注解: @EnableEurekaServer

分别启动eureka,webserver服务

测试效果

访问: http://localhost:9800/webserve/wstest1.html

如下图即开始通信:
在这里插入图片描述
服务端日志:

2020-10-09 12:20:46.833 INFO 6804 — [nio-9800-exec-2]
c.t.a.t.websocket.WebSocketServer : 有新窗口开始监听:2,当前在线人数为1
2020-10-09 12:20:54.143 INFO 6804 — [nio-9800-exec-5]
c.t.a.t.websocket.WebSocketServer : 推送消息到窗口2,推送内容:发送一句话吧
响应数据:》》》》》》》》》 {“msg”:“success”,“code”:200} 2020-10-09 12:21:13.954
INFO 6804 — [nio-9800-exec-7] c.t.a.t.websocket.WebSocketServer
: 推送消息到窗口2,推送内容:aaaaaaaaaaaaaaa 响应数据:》》》》》》》》》
{“msg”:“success”,“code”:200}

好了,可以通信了,唉,真的简单!!! 特此留个爪印,哈哈。。。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值