WebSocket后端调用前端总结

文章展示了如何使用SpringBoot框架集成WebSocket,创建连接管理,包括连接开启、关闭的处理,以及向特定或所有客户端发送消息的逻辑。同时,提供了前端HTML页面的JavaScript代码示例,用于建立WebSocket连接、发送和接收消息。测试类说明了如何从后端向客户端发送数据。
所需依赖
        <!-- websocket-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
            <version>2.7.0</version>
        </dependency>
实体类
import lombok.Data;

@Data
public class NoticeWebsocketResp {
    //通知类型
    private String noticeType;

    //通知内容
    private Object noticeInfo;
}

保持连接的Bean
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

@Configuration
public class WebSocketConfig {

    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}
配置类
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.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;


@Slf4j
@Component
@ServerEndpoint(value = "/SetRulesLogsend/{buildingId}")
public class SetRulesLogSocket { //记录连接的客户端
        public static Map<String, Session> clients = new ConcurrentHashMap<>();

        /**
         * buildingId关联sid(解决同一用户id,在多个web端连接的问题)
         */
        public static Map<String, Set<String>> conns = new ConcurrentHashMap<>();

        private String sid = null;

        private String buildingId;


        /**
         * 连接成功后调用的方法
         * @param session
         * @param buildingId
         */
        @OnOpen
        public void onOpen(Session session, @PathParam("buildingId") String buildingId) {
            this.sid = UUID.randomUUID().toString();
            this.buildingId = buildingId;
            clients.put(this.sid, session);

            Set<String> clientSet = conns.get(buildingId);

            if (clientSet==null){
                clientSet = new HashSet<>();
                conns.put(buildingId,clientSet);
            }
            clientSet.add(this.sid);
            log.info(this.sid + "连接开启!");
        }

        /**
         * 连接关闭调用的方法
         */
        @OnClose
        public void onClose() {
            log.info(this.sid + "连接断开!");
            clients.remove(this.sid);
        }

        /**
         * 判断是否连接的方法
         * @return
         */
        public static boolean isServerClose() {
            if (SetRulesLogSocket.clients.values().size() == 0) {
                log.info("已断开");
                return true;
            }else {
                log.info("已连接");
                return false;
            }
        }

        /**
         * 发送给所有用户
         * @param noticeType
         */
        public static void sendMessage(String noticeType){
            NoticeWebsocketResp noticeWebsocketResp = new NoticeWebsocketResp();
            noticeWebsocketResp.setNoticeType(noticeType);
            sendMessage(noticeWebsocketResp);
        }


        /**
         * 发送给所有用户
         * @param noticeWebsocketResp
         */
        public static void sendMessage(NoticeWebsocketResp noticeWebsocketResp){
            String message = JSONObject.toJSONString(noticeWebsocketResp);
            for (Session session1 : SetRulesLogSocket.clients.values()) {
                try {
                    session1.getBasicRemote().sendText(message);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        /**
         * 根据buildingId-id发送给某一个用户
         * **/
        public static void sendMessageBybuildingId(String buildingId, NoticeWebsocketResp noticeWebsocketResp) {
            if (!StringUtils.isEmpty(buildingId)) {
                String message = JSONObject.toJSONString(noticeWebsocketResp);
                Set<String> clientSet = conns.get(buildingId);
                if (clientSet != null) {
                    Iterator<String> iterator = clientSet.iterator();
                    while (iterator.hasNext()) {
                        String sid = iterator.next();
                        Session session = clients.get(sid);
                        if (session != null) {
                            try {
                                session.getBasicRemote().sendText(message);
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        }

        /**
         * 收到客户端消息后调用的方法
         * @param message
         * @param session
         */
        @OnMessage
        public void onMessage(String message, Session session) {
            log.info("收到来自项目"+this.buildingId+"的信息:"+message);
        }

        /**
         * 发生错误时的回调函数
         * @param error
         */
        @OnError
        public void onError(Throwable error) {
            log.info("错误");
            error.printStackTrace();
        }
}

测试类

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.iot.base.entity.SetRulesLog;
import com.iot.base.service.ISetRulesLogService;
import com.iot.common.api.ApiResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@RestController
public class wsController {
    @Autowired
    private ISetRulesLogService setRulesLog;
    @Autowired
    private SetRulesLogSocket socket;
    @GetMapping("/test")
    public ApiResult test() {
    //获取需要的数据通过sendMessageBybuildingId类发送给对应的会话
        List<SetRulesLog> list = setRulesLog.list(Wrappers.<SetRulesLog>lambdaQuery().eq(SetRulesLog::getReadStatus, 0));
        Map<String, List<SetRulesLog>> collect = list.stream().collect(Collectors.groupingBy(SetRulesLog::getBuildId));
        collect.forEach((k,v)->{
            NoticeWebsocketResp noticeWebsocketResp = new NoticeWebsocketResp();
            noticeWebsocketResp.setNoticeType(k);
            noticeWebsocketResp.setNoticeInfo(v);
            socket.sendMessageBybuildingId(k,noticeWebsocketResp);
        });
        return ApiResult.ok();
    }
}

前端代码

<!DOCTYPE HTML>
<html>
<head>
        <meta charset="UTF-8">
        <title>My WebSocket</title>
        <style>
            #message{
        margin-top: 40px;
        border: 1px solid gray;
        padding:20px;
                }
        </style>
</head>
<body>
<button onclick="conectWebSocket()">连接WebSocket</button>
<button onclick="closeWebSocket()">断开连接</button>
<hr />
<br />
消息:<input id="text" type="text" />
<button onclick="send()">发送消息</button>
<div id="message"></div>
</body>
<script type="text/javascript">
    var websocket = null;
    function conectWebSocket(){
        //判断当前浏览器是否支持WebSocket
        if ('WebSocket'in window) {
            // 连接信息 我的两个测试页面只有该处不同
            //websocket = new WebSocket("ws://localhost:8082/SetRulesLogsend/7");
            websocket = new WebSocket("ws://localhost:8082/SetRulesLogsend/8");
        } else {
            alert('Not support websocket')
        }
        //连接发生错误的回调方法
        websocket.onerror = function() {
            setMessageInnerHTML("error");
        };
        //连接成功建立的回调方法
        websocket.onopen = function(event) {
            setMessageInnerHTML("Loc MSG: 成功建立连接");
        }
        //接收到消息的回调方法
        websocket.onmessage = function(event) {
            setMessageInnerHTML(event.data);
        }
        //连接关闭的回调方法
        websocket.onclose = function() {
            setMessageInnerHTML("Loc MSG:关闭连接");
        }
        //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
        window.onbeforeunload = function() {
            websocket.close();
        }
    }
    //将消息显示在网页上
    function setMessageInnerHTML(innerHTML) {
        document.getElementById('message').innerHTML += innerHTML + '<br/>';
    }
    //关闭连接
    function closeWebSocket() {
        websocket.close();
    }
    //发送消息
    function send() {
        var message = document.getElementById('text').value;
        websocket.send(message);
    }
</script>
</html>

测试结果:
在这里插入图片描述

总结:WebSocket后端调用前端非自动进行,需要线程来触发此代码实现向前端通讯。做需求时需要考虑怎么触发

### Java 后端调用前端并获取响应 在Web应用程序中,Java后端前端之间的通信通常是异步的。为了使Java后端能够有效地调用前端并接收其响应,可以采用AJAX技术或WebSocket协议。 #### AJAX 方式 通过发送HTTP请求到服务器,前端JavaScript代码可以在不刷新整个页面的情况下更新部分网页内容。对于Java后端来说,这意味着设置好RESTful API以便于接受来自前端发出的各种类型的HTTP请求(GET, POST等)。下面是一个简单的例子说明如何从前端后端传递数据以及后端怎样处理这些信息: ##### 前端 JavaScript (使用 jQuery) ```javascript $.ajax({ url: '/api/data', // 请求地址 type: 'POST', contentType: "application/json", data: JSON.stringify({ key: value }), // 发送的数据对象转换成JSON字符串形式 success: function(response){ console.log('Success:', response); // 成功后的回调函数 }, error:function(errorThrown){ console.error('Error occurred.', errorThrown); } }); ``` ##### Spring Boot Controller 处理请求 ```java @RestController @RequestMapping("/api") public class DataController { @PostMapping(value="/data", consumes="application/json", produces={"application/json"}) public ResponseEntity<String> postData(@RequestBody Map<String,Object> payload) { String result = processPayload(payload); // 对接收到的数据做进一步操作 return new ResponseEntity<>(result, HttpStatus.OK); } } ``` 此段代码展示了当接收到带有特定路径`/api/data` 的POST请求时,会触发控制器中的相应方法,并将请求体内的JSON数据映射为Map结构供后续处理[^1]。 #### WebSocket 协议 如果应用场景涉及到实时双向通讯,则推荐使用WebSocket代替传统的轮询机制。建立连接之后,客户端和服务端都可以主动推送消息给对方而无需等待另一方先发起请求。这使得它非常适合聊天室应用或其他需要即时反馈的功能模块。 以下是创建一个基本WebSocket配置类的例子: ```java @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.enableSimpleBroker("/topic"); // 定义广播目的地前缀 config.setApplicationDestinationPrefixes("/app"); // 设置应用目的地方前缀 } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/ws").withSockJS(); // 注册STOMP终端点 } } ``` 在这个基础上,可以通过编写专门的消息处理器来监听某些事件的发生并向订阅者分发通知。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值