leftso 3460 0 2018-07-02 10:15:39

文章位置:左搜> 编程技术> 正文

一、概要

    在本教程中,我们将讨论如何创建Spring Boot应用程序,以使用WebSocket协议来实现客户端和服务器之间的通信。显然,服务器将是基于Spring框架的应用程序,客户端将是一个角度js应用程序。因此,本文将将spring boot web socket应用程序与角度应用程序集成,这两个应用程序之间的通信将通过WebSocket协议。这里使用的角度版本是Angular 5。
 

    在服务器端配置中,我们将使用AbstractWebSocketMessageBrokerConfigurer配置我们的websocket协议来使用STOMP作为消息代理和常见注释,例如由@MessageMapping@SendTo@MessageExceptionHandler提供spring-boot-starter-websocket。此示例使用STOMP作为消息代理,但它是可选的,这是一个spring boot websocket的示例,不使用STOMP。

在客户端,我们将有一个角色应用程序运行并通过websocket协议连接到服务器。为了与websocket集成,我们将使用stompjs库sockJs库。您可以轻松扩展此示例应用程序以创建聊天应用程序。

二、Websocket定义

与http一样,websocket也是一种通信协议,它提供了服务器和客户端之间的双向全双工通信通道。一旦在客户端和服务器之间建立了websocket连接,双方就可以无休止地交换信息,直到连接完成由任何一方关闭,这是为什么websocket优于HTTP的主要原因,因为客户端和服务器需要以高频率和低延迟交换信息,因为一旦服务器提供请求,HTTP连接就会关闭,一个时间限制来再次打开HTTP连接。

此外,websocket协议是双向的,即客户端可以订阅某个事件,并且服务器可以基于服务器中事件的可用性将事件发布到客户端。


三、Spring Boot 2.0 Websocket配置

我们将WebSocketConfig.java拥有所有websocket和sockJS相关配置。
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

	@Override
	public void configureMessageBroker(MessageBrokerRegistry config) {
		config.enableSimpleBroker("/topic/", "/queue/");
		config.setApplicationDestinationPrefixes("/app");
	}

	@Override
	public void registerStompEndpoints(StompEndpointRegistry registry) {
		registry.addEndpoint("/greeting")
				.setAllowedOrigins("*");
				//.withSockJS();
	}

}

@EnableWebSocketMessageBroker启用消息代理,默认情况下spring使用STOMP作为消息代理。因此,此应用程序将使用STOMP作为websocket通信的消息代理,但您可以自由使用其他消息传递协议,如RabbitMQActiveMQ

 

同样,该方法configureMessageBroker() 使简单的基于内存的消息代理能够将消息带回以“/ topic”和“/ queue”为前缀的客户端。因此,从我们的服务器端websocket响应将发送到以这些端点为前缀的端点,并且角客户端将订阅以这些前缀开头的url,例如“/ topic / reply”

类似地,registerStompEndpoints()启用STOMP支持,并在“/greeting"处注册stomp结果。这样,所有websocket消息将通过STOMP进行信道化,这也为websocket端点增加了额外的安全层。请记住,在从javascipt创建websocket连接时,我们将使用这个特定的stomp端点,即让socket = new WebSocket(“ws:// localhost:8080 / greeting”); 只要。

现在让我们定义我们的控制器来映射要通过websocket协议接收的消息。

import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageExceptionHandler;
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.SimpMessageSendingOperations;
import org.springframework.stereotype.Controller;

import com.google.gson.Gson;

@Controller
public class WebSocketController {

	@Autowired
	private SimpMessageSendingOperations messagingTemplate;

	@MessageMapping("/message")
    @SendTo("/topic/reply")
	public String processMessageFromClient(@Payload String message) throws Exception {
		String name = new Gson().fromJson(message, Map.class).get("name").toString();
		return name;
	}
	
	@MessageExceptionHandler
    public String handleException(Throwable exception) {
        messagingTemplate.convertAndSend("/errors", exception.getMessage());
	    return exception.getMessage();
    }

}

@MessageMapping:这是映射消息的URL /消息。因此,客户端应该按照我们的/ app / message发送消息WebSocketCOnfig.java

同样,@SendTo用于广播消息。因此,返回的对象processMessageFromClient()将被广播到这个主题。为了发送这个消息给特定的用户,Spring提供了@SendToUser

四、Angular JS Project Generation

让我们首先使用角度cli生成我们的angular 5项目。确保你的机器上安装了Node JS在这里可以找到关于Angular的一步一步的配置和教程。

ng new angular-websocket
cd angular-websocket
ng serve
现在您可以在任何IDE中导入项目。项目结构应如下所示

现在让我们首先使用NPM 安装stompjssocksjs库。
npm install stompjs --save
npm install sockjs-client --save
这将增加依赖关系package.json。现在,让我们定义我们的html代码。我们拥有的html有两个用于连接和断开websocket连接的按钮。同样,发送按钮将通过websocket协议以JSON格式将名称发送给服务器,服务器将从中提取名称并发送回客户端订阅的主题。
<div id="main-content" class="container">
  <div class="row">
    <div class="col-md-6">
      <form class="form-inline">
        <div class="form-group">
          <label for="connect">WebSocket connection:</label>
          <button id="connect" class="btn btn-default" type="button" [disabled]="disabled" (click)="connect()">Connect</button>
          <button id="disconnect" class="btn btn-default" type="button" [disabled]="!disabled" (click)="disconnect()">Disconnect
          </button>
        </div>
      </form>
    </div>
    <div class="col-md-6">
      <form class="form-inline" name="test-form">
        <div class="form-group">
          <label for="name">What is your name?</label>
          <input type="text" id="name" name="name" class="form-control" placeholder="Your name here..." [(ngModel)]="name">
        </div>
        <button id="send" class="btn btn-default" type="button" (click)="sendName()">Send</button>
      </form>
    </div>
  </div>
  <div class="row">
    <div class="col-md-12" *ngIf="showConversation">
      <table id="conversation" class="table table-striped">
        <thead>
        <tr>
          <th>Greetings</th>
        </tr>
        </thead>
        <tbody *ngFor="let greeting of greetings" >
          <tr><td> </td></tr>
        </tbody>
      </table>
    </div>
  </div>

</div>

同样,我们有以下打字稿代码。

connect()将创建一个web套接字连接。请记住我们在WebSocketConfig.java类中为/ greeting做的映射。

showGreeting()将只显示服务器广播收到的消息。

send()函数将构造一个JSON消息并将消息发送到服务器。

app.component.ts:
 

import { Component } from '@angular/core';
import * as Stomp from 'stompjs';
import * as SockJS from 'sockjs-client';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app';

  greetings: string[] = [];
  showConversation: boolean = false;
  ws: any;
  name: string;
  disabled: boolean;

  constructor(){}

  connect() {
    //connect to stomp where stomp endpoint is exposed
    //let ws = new SockJS(http://localhost:8080/greeting);
    let socket = new WebSocket("ws://localhost:8080/greeting");
    this.ws = Stomp.over(socket);
    let that = this;
    this.ws.connect({}, function(frame) {
      that.ws.subscribe("/errors", function(message) {
        alert("Error " + message.body);
      });
      that.ws.subscribe("/topic/reply", function(message) {
        console.log(message)
        that.showGreeting(message.body);
      });
      that.disabled = true;
    }, function(error) {
      alert("STOMP error " + error);
    });
  }

  disconnect() {
    if (this.ws != null) {
      this.ws.ws.close();
    }
    this.setConnected(false);
    console.log("Disconnected");
  }

  sendName() {
    let data = JSON.stringify({
      'name' : this.name
    })
    this.ws.send("/app/message", {}, data);
  }

  showGreeting(message) {
    this.showConversation = true;
    this.greetings.push(message)
  }

  setConnected(connected) {
    this.disabled = connected;
    this.showConversation = connected;
    this.greetings = [];
  }
}

五、Websocket SockJS配置

要在客户端代码中使用SockJS,您需要在html中包含sockjs.js.SockJS在websocket连接失败或不可用时提供最佳的备用选项。以下是在从客户端建立websocket连接时使用它的示例代码。服务器端取消注释 .withSockJS()
var socket = new SockJS('ws://localhost:8080/greeting');
ws = Stomp.over(socket);
//rest of the code as usual as above
 

六、测试Websocket应用程序

运行Application.java作为Java应用程序,并在控制台输入命令,ng serve然后点击http:// localhost:4200

七、总结

在本文中,我们讨论了将spring引导websocket与angular js集成在一起。我们使用STOMP作为消息传递协议,并使用sockJS提供回退选项。