springboot成神之——websocket发送和请求消息

Posted 叶家伟的博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springboot成神之——websocket发送和请求消息相关的知识,希望对你有一定的参考价值。

本文介绍如何使用websocket发送和请求消息

项目目录

依赖

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

DemoApplication

package com.springlearn.learn;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {

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

MessageModel

package com.springlearn.learn.model;

public class MessageModel {

    private String name;

    public String getName() {
        return "测试成功" + name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

WebConfig

package com.springlearn.learn.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableScheduling
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowedOrigins("*").allowedMethods("GET", "POST", "PUT", "DELETE").allowedOrigins("*")
        .allowedHeaders("*");
    }
}

WebSocketConfig

package com.springlearn.learn.config;

import com.springlearn.learn.Handler.HttpHandshakeInterceptor;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
     
    @Autowired
    private HttpHandshakeInterceptor handshakeInterceptor; // 这个是自定义的拦截器
 
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws").setAllowedOrigins("*").withSockJS().setInterceptors(handshakeInterceptor);
    }
 
    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.setApplicationDestinationPrefixes("/app"); // 前端发送消息的前缀
        registry.enableSimpleBroker("/topic"); // 前端接收后台消息和后台发送消息给前端的前缀
    }
 
}

HttpHandshakeInterceptor

package com.springlearn.learn.Handler;

import java.util.Map;

import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.HandshakeInterceptor;

@Component
public class HttpHandshakeInterceptor implements HandshakeInterceptor {
 
    private static final Logger logger = LoggerFactory.getLogger(HttpHandshakeInterceptor.class);
     
    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
         
        logger.info("Call beforeHandshake"); // 和out一样,输出语句,正式开发用这个多
         
        if (request instanceof ServletServerHttpRequest) {
            ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
            HttpSession session = servletRequest.getServletRequest().getSession();
            attributes.put("sessionId", session.getId());
        }

        return true;
    }
 
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
            Exception ex) {
        logger.info("Call afterHandshake");
    }
     
}

WebSocketEventListener

// 监听器,监听socket连接和短线
package com.springlearn.learn.listener;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.messaging.simp.SimpMessageSendingOperations;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.messaging.SessionConnectedEvent;
import org.springframework.web.socket.messaging.SessionDisconnectEvent;

@Component
public class WebSocketEventListener {
 
    private static final Logger logger = LoggerFactory.getLogger(WebSocketEventListener.class);
 
    @Autowired
    private SimpMessageSendingOperations messagingTemplate;
 
    @EventListener
    public void handleWebSocketConnectListener(SessionConnectedEvent event) {
        logger.info("Received a new web socket connection");
    }
 
    @EventListener
    public void handleWebSocketDisconnectListener(SessionDisconnectEvent event) {
        StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(event.getMessage());
 
        String username = (String) headerAccessor.getSessionAttributes().get("username");
         
        if(username != null) {
            logger.info("User Disconnected : " + username);
            messagingTemplate.convertAndSend("/topic/getResponse", "User Disconnected : " + username);
        }
    }
     
}

WebSocketController

package com.springlearn.learn.controller;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

import com.springlearn.learn.model.MessageModel;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
import org.springframework.messaging.simp.SimpMessageSendingOperations;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Controller;


@Controller
public class WebSocketController {

    private static final DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss sss");

    @Autowired
    private SimpMessageSendingOperations messagingTemplate;

    @MessageMapping("/welcome")
    @SendTo("/topic/getResponse")
    public MessageModel sendMessage(@Payload MessageModel requestMessage, SimpMessageHeaderAccessor headerAccessor) {
        headerAccessor.getSessionAttributes().put("username", requestMessage.getName());
        MessageModel message = new MessageModel();
        message.setName(requestMessage.getName());
        return message;
    }

    @Scheduled(cron="* * * * * *" )
    @SendTo("/topic/getResponse")
    public Object callback() throws Exception {
        Date now = new Date();
        messagingTemplate.convertAndSend("/topic/getResponse", df.format(now));
        return "callback";
    }
}

前端测试

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script>
    <link rel="stylesheet" href="//unpkg.com/iview/dist/styles/iview.css">
    <script src="//unpkg.com/iview/dist/iview.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>
    <script  src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>
</head>
<body>
    <div id="app">
    </div>
    <script>
        new Vue({
            el: \'#app\',
            mounted () {
                
                var stompClient = null;

                var socket = new SockJS(\'http://localhost:9001/ws\');
                stompClient = Stomp.over(socket);
                stompClient.connect(
                    {}, 
                    function (frame) {
                        stompClient.subscribe(\'/topic/getResponse\', function (payload) {
                            console.log(payload.body)
                        })

                        stompClient.send(
                            "/app/welcome",
                            {},
                            JSON.stringify({name: "yejiawei"})
                        )
                    }, 
                    function(error) {
                        connectingElement.textContent = \'Could not connect to WebSocket server. Please refresh this page to try again!\';
                        connectingElement.style.color = \'red\';
                    }
                );

                setTimeout(function() {
                    stompClient.send(
                        "/app/welcome",
                        {},
                        JSON.stringify({name: "来自前端的请求"})
                    )
                }, 3000)
            }
            
        })
    </script>
</body>
</html>

以上是关于springboot成神之——websocket发送和请求消息的主要内容,如果未能解决你的问题,请参考以下文章

springboot成神之——监视器

springboot成神之——RestTemplate访问Rest

java成神之——文件IO

java成神之——HttpURLConnection访问api

java成神之——安全和密码

java成神之——Fork/Join基本使用