我正在使用Spring Boot v1.5.1来实现前端的websocket后端和Angular 2。基本上,后端(Spring)轮询数据库以查找更改(如果有),将更改推送到前端(Angular)。
如果第一个用户A
访问该网站,则会看到所有更改。只要其他用户B
访问该网站,她就会看到更改,但用户A
不再进行更改。通过打开2个浏览器(一个接一个;后者将看到更改,但前者将停止),可以在同一台计算机上复制此行为。
在后端,我的websocket处理程序如下所示。
package demo.web;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
@Component
public class TimestampWsHandler extends TextWebSocketHandler {
private WebSocketSession session;
@Override
public void afterConnectionEstablished(WebSocketSession session) {
this.session = session;
start();
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
String payload = message.getPayload();
if ("CLOSE".equalsIgnoreCase(payload)) {
session.close();
return;
}
}
void push() {
if (null != session && session.isOpen()) {
String s = IntStream.range(0, 10)
.mapToObj(i -> System.currentTimeMillis())
.map(i -> i.toString())
.collect(Collectors.joining(","));
try {
session.sendMessage(new TextMessage(s));
} catch (Exception e) {
e.printStackTrace();
}
}
}
void start() {
new Thread(() -> {
while (true) {
push();
try {
Thread.sleep(500L);
} catch (Exception e) { }
}
}).start();
}
}
My Spring Boot应用程序入口点如下所示。
package demo;
import demo.web.TimestampWsHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@SpringBootApplication
@EnableScheduling
@EnableWebSocket
@EnableAutoConfiguration(exclude = {org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration.class})
public class App implements WebSocketConfigurer {
@Autowired
private TimestampWsHandler timestampWsHandler;
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(timestampWsHandler, "/api/ws/topic/timestamp").setAllowedOrigins("*");
}
}
在前端(使用ng cli
创建项目后),我的app.component.ts
已修改为如下所示。
import { Component, OnInit, OnDestroy, AfterViewInit } from '@angular/core';
import { Observable } from 'rxjs/Rx';
import { Subject } from 'rxjs/Subject';
import { Subscription } from 'rxjs/Subscription';
import { IntervalObservable } from 'rxjs/observable/IntervalObservable';
import { $WebSocket, WebSocketSendMode } from 'angular2-websocket/angular2-websocket';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app works!';
data: Array<String>;
ws: $WebSocket;
wsSubscription: Subscription;
ngOnInit() {
}
ngAfterViewInit() {
this.initWebSocket();
}
ngOnDestroy() {
this.destroyWebSocket();
}
private initWebSocket(): void {
this.ws = new $WebSocket('ws://localhost:8080/api/ws/topic/timestamp');
this.wsSubscription = this.ws.getDataStream().subscribe(
msgEvent => {
this.data = msgEvent.data.split(',');
},
err => {
console.error(err);
}
);
}
private destroyWebSocket(): void {
if (this.wsSubscription) {
try {
this.wsSubscription.unsubscribe();
this.wsSubscription = null;
} catch (err) { }
}
if (this.ws) {
try {
this.ws.close(true);
this.ws = null;
} catch (err) { }
}
}
}
相应的HTML,app.component.html
如下所示。
<h1>
{{title}}
</h1>
<table *ngIf="data">
<thead>
<tr>
<th>timestamp</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let t of data">
<td>{{t}}</td>
</tr>
</tbody>
</table>
请注意,在我创建Angular应用程序后,我必须安装angular2-websocket:npm install angular2-websocket --save
关于我做错的任何想法?
我确实看到以下IllegalStateException
一遍又一遍地重复。我不确定这些问题是否相关。
java.lang.IllegalStateException: The remote endpoint was in state [TEXT_PARTIAL_WRITING] which is an invalid state for called method at org.apache.tomcat.websocket.WsRemoteEndpointImplBase$StateMachine.checkState(WsRemoteEndpointImplBase.java:1224) at org.apache.tomcat.websocket.WsRemoteEndpointImplBase$StateMachine.textPartialStart(WsRemoteEndpointImplBase.java:1182) at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.sendPartialString(WsRemoteEndpointImplBase.java:222) at org.apache.tomcat.websocket.WsRemoteEndpointBasic.sendText(WsRemoteEndpointBasic.java:49) at org.springframework.web.socket.adapter.standard.StandardWebSocketSession.sendTextMessage(StandardWebSocketSession.java:203) at org.springframework.web.socket.adapter.AbstractWebSocketSession.sendMessage(AbstractWebSocketSession.java:101) at demo.web.TimestampWsHandler.push(TimestampWsHandler.java:37) at demo.web.TimestampWsHandler.lambda$start$2(TimestampWsHandler.java:47) at java.lang.Thread.run(Thread.java:745)
感谢任何帮助。