我一直在关注一个使用Pivotal的Reactor框架API设置web套接字的教程。
这个例子需要在运行Spring Boot Reactive微服务后,启动Google Chrome浏览器并打开一个特定的URL(有端口),然后点击查看源,再点击控制台。
这应该会产生一条日志消息到Google Chrome的Console的stdout。
然而,没有任何输出...
项目结构。
rswebsockets
│
├── build.gradle
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
├── main
│ ├── java
│ │ └── com
│ │ └── reactive
│ │ ├── RsWebSocketsApplication.java
│ │ ├── config
│ │ │ └── WebSocketConfig.java
│ │ ├── model
│ │ │ ├── GreetingRequest.java
│ │ │ └── GreetingResponse.java
│ │ └── service
│ │ └── GreetingService.java
│ └── resources
│ ├── application.properties
│ └── static
│ └── ws.html
└── test
└── java
└── com
└── reactive
└── RsWebSocketsApplicationTests.java
build.gradle:
plugins {
id 'org.springframework.boot' version '2.2.6.RELEASE'
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
id 'java'
}
group = 'com.reactive'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '14'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-webflux'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
testImplementation 'io.projectreactor:reactor-test'
}
test {
useJUnitPlatform()
}
代码库:
rswebsocketssrcmainjavacomreactiveRsWebSocketsApplication.java。
package com.reactive;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class RsWebSocketsApplication {
public static void main(String[] args) {
SpringApplication.run(RsWebSocketsApplication.class, args);
}
}
rswebsocketssrcmainjavacomreactiveconfigWebSocketConfig.java。
package com.reactive.config;
import com.reactive.model.GreetingRequest;
import com.reactive.model.GreetingResponse;
import com.reactive.service.GreetingService;
import org.springframework.context.annotation.Bean;
import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping;
import org.springframework.web.reactive.socket.WebSocketHandler;
import org.springframework.web.reactive.socket.WebSocketMessage;
import org.springframework.web.reactive.socket.server.support.WebSocketHandlerAdapter;
import java.util.Map;
public class WebSocketConfig {
@Bean
SimpleUrlHandlerMapping simpleUrlHandlerMapping(WebSocketHandler wsh) {
return new SimpleUrlHandlerMapping(Map.of("/ws/greetings", wsh), 10);
}
@Bean
WebSocketHandler webSocketHandler(GreetingService greetingService) {
return session -> {
var receive = session
.receive()
.map(WebSocketMessage::getPayloadAsText)
.map(GreetingRequest::new)
.flatMap(greetingService::greet)
.map(GreetingResponse::getMessage)
.map(session::textMessage);
return session.send(receive);
};
}
@Bean
WebSocketHandlerAdapter webSockerHandlerAdapter() {
return new WebSocketHandlerAdapter();
}
}
rswebsocketssrcmainjavacomreactivemodelGreetingRequest.java。
package com.reactive.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class GreetingRequest {
String name;
}
rswebsocketssrcmainjavacomreactivemodelGreetingResponse.java。
package com.reactive.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class GreetingResponse {
String message;
}
rswebsocketssrcmainjavacomreactiveserviceGreetingService.java。
package com.reactive.service;
import com.reactive.model.GreetingRequest;
import com.reactive.model.GreetingResponse;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import java.time.Duration;
import java.time.Instant;
import java.util.stream.Stream;
@Service
public class GreetingService {
public Flux<GreetingResponse> greet(GreetingRequest request) {
return Flux.fromStream(
Stream.generate(() -> new GreetingResponse("Hello " + request.getName() + " @ " + Instant.now())))
.delayElements(Duration.ofSeconds(1));
}
}
rswebsocketssrcmainresourcesstaticws.html。
<html>
<body>
<script>
window.addEventListener('load', function (e) {
var ws = new WebSocket('ws://localhost:8080/ws/greetings')
ws.addEventListener('open', function (e) {
ws.send('Livelessons Fans')
});
ws.addEventListener('message', function (e) {
console.log(e.data);
});
})
</script>
</body>
</html>
在使用微服务运行后(启动时没有任何中断)。
gradle bootRun
输出。
Java HotSpot(TM) 64-Bit Server VM warning: Options -Xverify:none and -noverify were deprecated in JDK 13 and will likely be removed in a future release.
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.2.6.RELEASE)
2020-05-06 14:46:41.393 INFO 39122 --- [ main] com.reactive.RsWebSocketsApplication : Starting RsWebSocketsApplication on Porsche959.local with PID 39122 (/Users/pnwlover/rswebsockets/build/classes/java/main started by pnwlover in /Users/pnwlover/rswebsockets)
2020-05-06 14:46:41.395 INFO 39122 --- [ main] com.reactive.RsWebSocketsApplication : No active profile set, falling back to default profiles: default
2020-05-06 14:46:42.126 INFO 39122 --- [ main] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port(s): 8080
2020-05-06 14:46:42.129 INFO 39122 --- [ main] com.reactive.RsWebSocketsApplication : Started RsWebSocketsApplication in 0.941 seconds (JVM running for 1.579)
打开Google Chrome浏览器,启动以下网址。
http://localhost:8080/ws.html
打开谷歌浏览器开发者工具,进入查看页面源码,然后点击控制台标签。
Google Chome开发者工具--源标签。
我可能做错了什么?