spring boot websocket stomp 實現廣播通訊和一對一通訊聊天

1、前言javascript

玩.net的時候,在asp.net下有一個叫 SignalR 的框架,能夠在ASP .NET的Web項目中實現實時通訊。剛接觸java尋找相關替代品,發現 java 體系中有一套基於stomp協議的websocket通訊的框架,websocket是什麼能夠參考阮老大的《WebSocket 教程》,這篇文章不討論理論知識,這裏只講應用,把websocket的廣播模式與一對一模式一塊兒整理一個demo給你們分享一下。css

2、項目結構html

由於一對一私聊模式 使用principal的name做爲目的地標識。發給消息來源的那個用戶,該操做是認爲用戶登陸而且受權認證,因此這裏使用Spring Security來控制身份認證,項目結構以下:java

1.WebSecurityConfig: Spring Security安全控制類jquery

2.WebSocketConfig: web socket 控制類web

3. DefaultController:mvc控制器spring

4.ChatMessage: 消息實體對象數據庫

5.chat.html : 聊天消息發送接收html客戶端頁面跨域

6.login.html:登陸頁瀏覽器

pom.xml依賴以下:

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

3、代碼實現

1.web服務器安全配置

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    //注入密碼加密解密方式,由於這裏使用明文不加密
    @Bean
    public static NoOpPasswordEncoder passwordEncoder() {
        return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .inMemoryAuthentication()
                //在內存中分別配置兩個用戶user1 user2和密碼 ,角色是user,持久化到數據庫中的本身配置不在本文知識範圍內
                .withUser("user1").password("123").roles("user")
                .and()
                .withUser("user2").password("123").roles("user");

    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        ///resources/static/ 目錄下的靜態資源,spring security不攔截
        web.ignoring().antMatchers("/resources/static/**","/resources/templates/**");
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                //設置spring security對 /  和  /login  路徑不攔截
                .antMatchers("/", "/login").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                //設置spring security的登陸頁面訪問路徑爲 /login
                .loginPage("/login")
                //登錄成功後轉向 /chat 路徑
                .defaultSuccessUrl("/chat.html")
                .permitAll()
                .and()
                .logout()
                .permitAll();

    }
}

2.WebSocket 配置類

/**
 * WebSocket 配置類
 * Created by ejiyuan on 2018-7-11.
 */
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        //容許客戶端使用socketJs方式訪問,訪問點爲ws,容許跨域
        registry.addEndpoint("/ws").setAllowedOrigins("*").withSockJS();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {

        //訂閱廣播 Broker(消息代理)名稱
        registry.enableSimpleBroker("/topic"); // Enables a simple in-memory broker
        //全局使用的訂閱前綴(客戶端訂閱路徑上會體現出來)
        registry.setApplicationDestinationPrefixes("/app/");
        //點對點使用的訂閱前綴(客戶端訂閱路徑上會體現出來),不設置的話,默認也是/user/
        registry.setUserDestinationPrefix("/user/");
    }
}

3.控制器

@Controller
public class DefaultController {

    @GetMapping("/")
    @ResponseBody
    public String helloWord() {
        return "helloWord";
    }
    @GetMapping("/login")
    public String login() {
        return "login";
    }
    //注入SimpMessagingTemplate 用於點對點消息發送
    @Autowired
   private SimpMessagingTemplate messagingTemplate;

    @MessageMapping("/sendPublicMessage") //這裏是客戶端發送消息對應的路徑,等於configureMessageBroker中配置的setApplicationDestinationPrefixes + 這路徑即 /app/sendPublicMessage
    @SendTo("/topic/public") //也可使用 messagingTemplate.convertAndSend(); 推送
    public ChatMessage sendPublicMessage(@Payload ChatMessage chatMessage) {
        return chatMessage;
    }


    @MessageMapping("/sendPrivateMessage") //這裏是客戶端發送消息對應的路徑,等於configureMessageBroker中配置的setApplicationDestinationPrefixes + 這路徑即 /app/sendPrivateMessage
    public void sendPrivateMessage(@Payload  ChatMessage msg,Principal principal) {
        msg.setSender(principal.getName());
        //將消息推送到指定路徑上
        messagingTemplate.convertAndSendToUser(msg.getReceiver(), "topic/chat", msg);
    }

    /*
    註釋方式推不過去這裏沒調通,有大神的話慢慢研究吧
    @SendToUser(value = "/topic/chat",broadcast=false)
    public ChatMessage sendPrivateMessage(@Payload  ChatMessage msg,Principal principal) {
        msg.setSender(principal.getName());
        return msg;
    }*/

}

4.消息載體:pojo對象

/**
 * 消息載體
 * Created by ejiyuan on 2018-7-11
 */
@JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY)
public class ChatMessage {

    private String content;
    private String sender;
    private String receiver;

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public String getSender() {
        return sender;
    }

    public void setSender(String sender) {
        this.sender = sender;
    }
    public String getReceiver() {
        return receiver;
    }

    public void setReceiver(String receiver) {
        this.receiver = receiver;
    }


}

5.客戶端聊天html頁面

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<meta charset="UTF-8"/>
<head>
    <title>聊天框</title>
    <script src="https://cdn.bootcss.com/sockjs-client/1.1.4/sockjs.min.js"></script>
    <script src="https://cdn.bootcss.com/stomp.js/2.3.3/stomp.min.js"></script>
    <script src=" https://code.jquery.com/jquery-3.3.1.min.js"></script>
    <script type="text/javascript">
        //ws /ws 的endpoint
        var sock = new SockJS('/ws'); //跟你的WebSocketConfig中配置要一致
        var stomp = Stomp.over(sock);
        //創建鏈接監聽
        stomp.connect({}, function (frame) {
            stomp.subscribe('/topic/public', function (response) {
                $("#output").append('<b>公共消息:' + response.body + '</b><br/>');
            });
            //訂閱 /user/topic/chat 發送的消息,這裏與
            //在控制器的messagingTemplate.convertAndSendToUser中定義的訂閱地址保持一致
            //這裏多了 /user ,而且這個 /user是必須的,使用了 /user 纔會將消息發送到指定用戶
            stomp.subscribe("/user/topic/chat", function handleNotification(message) {
                console.log("msg" + message);
                $("#output").append('<b>' + message.body + '</b><br/>');
            });
        });
        //發送私有消息指定的人能收到
        function sendPrivateMsg() {
            stomp.send("/app/sendPrivateMessage", {}, JSON.stringify({
                'content': $("#text").val(),         //消息內容
                'receiver': $("#receiver").val()    //接收人
            }));
        }
        //發送公共消息 誰都能收到,本身也能收到
        function sendPublicMsg() {
            stomp.send("/app/sendPublicMessage", {}, JSON.stringify({
                'content': $("#text").val(),         //消息內容
            }));
        }
        //斷開鏈接
       function stop() {
            sock.close();
        }
    </script>
</head>
<body>
<div>
    <textarea rows="4" cols="60" name="text" id="text"> </textarea> <br/>
    接收人:
    <input id="receiver" value=""/> <br/>
    <input type="button" value="私有消息" onclick="sendPrivateMsg()"/>
    <input type="button" value="公共消息" onclick="sendPublicMsg()"/>
    <input id="stop" type="button" onclick="stop()" value="斷開"/>

</div>
<div id="output"></div>
</body>
</html>

3、測試:

1,分別在兩個瀏覽器中打開,登陸user1與user2

2,發消息測試

3.斷開測試:斷開後不管公共消息私有消息都沒法再接收

5、源代碼:https://download.csdn.net/download/ejiyuan/10536333

6、參考文檔

1.WebSocket 教程:http://www.ruanyifeng.com/blog/2017/05/websocket.html

2.玩轉spring boot——websocket:https://www.cnblogs.com/GoodHelper/p/7078381.html

3.Spring Boot 開發私有即時通訊系統(WebSocket):https://www.jianshu.com/p/0f498adb3820

相關文章
相關標籤/搜索