springboot+WebSocket 異步通信(小例)--書籍中有些方法已過時和錯誤

入口類配置

@SpringBootApplication
@EnableWebSocketMessageBroker//開啓Stomp協議來傳輸基於代理(messagebroker)的消息,這時控制器支持使用@MessageMapping(同@RequestMapping)
public class Websocket3Application implements WebSocketMessageBrokerConfigurer {//AbstractWebSocketMessageBrokerConfigurer類在springboot2.x中已過時,新寫法改爲實現接口

    public static void main(String[] args) {
        SpringApplication.run(Websocket3Application.class, args);
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {//註冊Stomp協議的節點,並映射指定的URL
        registry.addEndpoint("/endPointWisely").withSockJS();//註冊一個Stomp協議節點並指定使用SockJS協議
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {//配置消息代理MessageBroker
        registry.enableSimpleBroker("/topic");//廣播式應配置一個/topic消息代理
        //registry.setUserDestinationPrefix("/user");
    }
}

mvc配置---頁面靜態資源訪問題和頁面訪問設置

此配置springboot會自動加載

// .js .css 等的靜態文件放置的目錄 因爲這兩個目錄是我手動建在resource下的,所以必須寫成"/目錄/**"

// 之前寫過springmvc配置有些類似配置,maven根據創建工程自動創建了static和templates兩個目錄也是默認爲項目根目錄下

所以配置爲"/**",根據書中寫的時候就出現了靜態資源訪問不到的錯誤

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {//spring5後 WebMvcConfigurerAdapter已過世

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        System.out.println("---------------1-------------------");
        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
        registry.addResourceHandler("/templates/**").addResourceLocations("classpath:/templates/");

    }

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        System.out.println("---------------2-------------------");
        registry.addViewController("websocket").setViewName("websocket");
        registry.addViewController("test").setViewName("test");
    }
}

瀏覽器向服務端發送消息類

由於前端sockjs向後臺發送的消息需通過反射機制實例化消息類對象,調用相應的get/set方法去實現,這裏必須要在類裏定義一個空構造方法,書籍中只寫了一個帶參的構造方法(寫了帶參的構造方法,空構造方法不再默認給出),導致服務端解析消息類時無法實例化類的對象,繼而無法執行Controller相應的方法(參數解析)

/**
 * 瀏覽器向服務端發送消息類
 */
public class WiselyMessage {
    private String name;

    public WiselyMessage(){}
    public WiselyMessage(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

}

瀏覽器向服務端發送消息類

/**
 * 服務端向瀏覽器發送消息類
 */
public class WiselyResponse {
    private String responseMessage;
    public WiselyResponse(String responseMessage) {
        this.responseMessage = responseMessage;
    }

    public String getResponseMessage() {
        return responseMessage;
    }

    public void setResponseMessage(String responseMessage) {
        this.responseMessage = responseMessage;
    }
}

Controller

@Controller
public class WiselyController {
    @MessageMapping("/welcome")//類似於RequestMapping
    @SendTo("/topicgetResponse")//服務端有消息時,會對訂閱了@SendTo中的路徑的瀏覽器發送消息
    public WiselyResponse say(WiselyMessage wiselyMessage) throws Exception{
        Thread.sleep(3000);
        System.out.println("--------------------ssss---------------");
        return new WiselyResponse("Welcome,"+wiselyMessage.getName()+"!");
    }

}

頁面(可不用模板),引入sockjs.js和stomp.js腳本文件(jquery也可用原生寫法替代)

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Spring Boot+WebSocket 廣播式</title>
    <script th:src="@{/js_ss/stomp.js}" type="text/javascript" ></script>
    <script th:src="@{/js_ss/sockjs.js}" type="text/javascript"></script>
    <script th:src="@{/js/jquery-1.7.1.js}" type="text/javascript"></script>
    <script type="text/javascript">
        var stompClient = null;
        
        function setConnected(connected) {
            //$("#connect").attr("disabled",connected)
           // $("#disconnect").attr("disabled",!connected);
            document.getElementById("connect").disabled=connected;
            document.getElementById("disconnect").disabled=!connected;
            if(connected){
                document.getElementById("conversationDiv").style.display="";
            }else{
                document.getElementById("conversationDiv").style.display="none";
            }
            $("#response").html();
        }
        function connect() {
            var socket= new SockJS('/endPointWisely');//連接SocketJS的endpoint名稱
            stompClient =Stomp.over(socket);//2使用stomp協議的WebSocket客戶端
            stompClient.connect({},function (frame) {//3連接webSocket客戶端
                setConnected(true);
                console.log('開始進行連接Connected:'+frame);
                //接收消息
                stompClient.subscribe('/topicgetResponse',function (response) {//4通過stompClient.subscribe訂閱topicgetResponse目標發送的消息(@SendTo中定義)
                    showResponse(JSON.parse(response.body).responseMessage);
                });
            });
        }
        function disconnect() {
            if (stompClient!=null){
                stompClient.disconnect();
            }
            setConnected(false);
            console.log('Disconnected');
        }
        function showResponse(message) {
            var response=$("#response");
            response.html(message);
        }
        function sendName() {
            var name= $("#name").val();
            //發送消息
            stompClient.send("/welcome",{},JSON.stringify({'name':name}));
        }
    </script>
</head>
<body onload="disconnect()">
    <noscript>
        <h2>貌似你的瀏覽器不支持WebSocket</h2>
    </noscript>
    <div>
        <div>
            <input id="connect" onclick="connect()" type="button" value="連接">
            <input id="disconnect" disabled="disabled" onclick="disconnect()" type="button" value="斷開連接">
        </div>
        <div id="conversationDiv">
            <label>名字:</label>
            <input type="text" id="name"/>
            <input type="button" id="sendName" onclick="sendName();" value="發送"/>
            <p id="response"></p>
        </div>
    </div>
</body>
</html>

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章