JAVA-14288 Rename spring-5-reactive-modules to spring-reactive-modules (#12659)

* JAVA-14288 Rename spring-5-reactive-modules to spring-reactive-modules

* JAVA-14288 Remove failing module

* JAVA-14288 Revert commenting spring-cloud-openfeign-2 module
This commit is contained in:
anuragkumawat
2022-09-02 21:50:42 +05:30
committed by GitHub
parent 18f456b179
commit d429f0f064
303 changed files with 12 additions and 12 deletions

View File

@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Baeldung: Static Content in Spring WebFlux</title>
</head>
<body>
Example Spring Web Flux and web resources configuration
</body>
</html>

View File

@@ -0,0 +1,23 @@
package com.baeldung.functional;
class Actor {
private String firstname;
private String lastname;
public Actor() {
}
public Actor(String firstname, String lastname) {
this.firstname = firstname;
this.lastname = lastname;
}
public String getFirstname() {
return firstname;
}
public String getLastname() {
return lastname;
}
}

View File

@@ -0,0 +1,40 @@
package com.baeldung.functional;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import static org.springframework.web.reactive.function.BodyExtractors.toDataBuffers;
import static org.springframework.web.reactive.function.BodyExtractors.toFormData;
import static org.springframework.web.reactive.function.BodyInserters.fromValue;
import static org.springframework.web.reactive.function.server.ServerResponse.ok;
public class FormHandler {
Mono<ServerResponse> handleLogin(ServerRequest request) {
return request.body(toFormData())
.map(MultiValueMap::toSingleValueMap)
.filter(formData -> "baeldung".equals(formData.get("user")))
.filter(formData -> "you_know_what_to_do".equals(formData.get("token")))
.flatMap(formData -> ok().body(Mono.just("welcome back!"), String.class))
.switchIfEmpty(ServerResponse.badRequest()
.build());
}
Mono<ServerResponse> handleUpload(ServerRequest request) {
return request.body(toDataBuffers())
.collectList()
.flatMap(dataBuffers -> ok().body(fromValue(extractData(dataBuffers).toString())));
}
private AtomicLong extractData(List<DataBuffer> dataBuffers) {
AtomicLong atomicLong = new AtomicLong(0);
dataBuffers.forEach(d -> atomicLong.addAndGet(d.readableByteCount()));
return atomicLong;
}
}

View File

@@ -0,0 +1,72 @@
package com.baeldung.functional;
import static org.springframework.web.reactive.function.BodyInserters.fromValue;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RequestPredicates.POST;
import static org.springframework.web.reactive.function.server.RequestPredicates.path;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
import static org.springframework.web.reactive.function.server.RouterFunctions.toHttpHandler;
import static org.springframework.web.reactive.function.server.ServerResponse.ok;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.WebHandler;
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
import reactor.core.publisher.Flux;
@SpringBootApplication
@ComponentScan(basePackages = { "com.baeldung.functional" })
public class FunctionalSpringBootApplication {
private static final Actor BRAD_PITT = new Actor("Brad", "Pitt");
private static final Actor TOM_HANKS = new Actor("Tom", "Hanks");
private static final List<Actor> actors = new CopyOnWriteArrayList<>(Arrays.asList(BRAD_PITT, TOM_HANKS));
private RouterFunction<ServerResponse> routingFunction() {
FormHandler formHandler = new FormHandler();
RouterFunction<ServerResponse> restfulRouter = route(GET("/"),
serverRequest -> ok().body(Flux.fromIterable(actors), Actor.class)).andRoute(POST("/"),
serverRequest -> serverRequest.bodyToMono(Actor.class)
.doOnNext(actors::add)
.then(ok().build()));
return route(GET("/test"), serverRequest -> ok().body(fromValue("helloworld")))
.andRoute(POST("/login"), formHandler::handleLogin)
.andRoute(POST("/upload"), formHandler::handleUpload)
.and(RouterFunctions.resources("/files/**", new ClassPathResource("files/")))
.andNest(path("/actor"), restfulRouter)
.filter((request, next) -> {
System.out.println("Before handler invocation: " + request.path());
return next.handle(request);
});
}
@Bean
public ServletRegistrationBean servletRegistrationBean() throws Exception {
HttpHandler httpHandler = WebHttpHandlerBuilder.webHandler((WebHandler) toHttpHandler(routingFunction()))
.filter(new IndexRewriteFilter())
.build();
ServletRegistrationBean registrationBean = new ServletRegistrationBean<>(new RootServlet(httpHandler), "/");
registrationBean.setLoadOnStartup(1);
registrationBean.setAsyncSupported(true);
return registrationBean;
}
public static void main(String[] args) {
SpringApplication.run(FunctionalSpringBootApplication.class, args);
}
}

View File

@@ -0,0 +1,83 @@
package com.baeldung.functional;
import static org.springframework.web.reactive.function.BodyInserters.fromValue;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RequestPredicates.POST;
import static org.springframework.web.reactive.function.server.RequestPredicates.accept;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
import static org.springframework.web.reactive.function.server.RouterFunctions.toHttpHandler;
import static org.springframework.web.reactive.function.server.ServerResponse.ok;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import org.apache.catalina.Context;
import org.apache.catalina.Wrapper;
import org.apache.catalina.startup.Tomcat;
import org.springframework.boot.web.embedded.tomcat.TomcatWebServer;
import org.springframework.boot.web.server.WebServer;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.http.server.reactive.ServletHttpHandlerAdapter;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.WebHandler;
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
import reactor.core.publisher.Flux;
public class FunctionalWebApplication {
private static final Actor BRAD_PITT = new Actor("Brad", "Pitt");
private static final Actor TOM_HANKS = new Actor("Tom", "Hanks");
private static final List<Actor> actors = new CopyOnWriteArrayList<>(Arrays.asList(BRAD_PITT, TOM_HANKS));
private RouterFunction<ServerResponse> routingFunction() {
FormHandler formHandler = new FormHandler();
RouterFunction<ServerResponse> restfulRouter = route(GET("/actor"), serverRequest -> ok().body(Flux.fromIterable(actors), Actor.class)).andRoute(POST("/actor"), serverRequest -> serverRequest.bodyToMono(Actor.class)
.doOnNext(actors::add)
.then(ok().build()));
return route(GET("/test"), serverRequest -> ok().body(fromValue("helloworld"))).andRoute(POST("/login"), formHandler::handleLogin)
.andRoute(POST("/upload"), formHandler::handleUpload)
.and(RouterFunctions.resources("/files/**", new ClassPathResource("files/")))
.andNest(accept(MediaType.APPLICATION_JSON), restfulRouter)
.filter((request, next) -> {
System.out.println("Before handler invocation: " + request.path());
return next.handle(request);
});
}
WebServer start() throws Exception {
WebHandler webHandler = (WebHandler) toHttpHandler(routingFunction());
HttpHandler httpHandler = WebHttpHandlerBuilder.webHandler(webHandler)
.filter(new IndexRewriteFilter())
.build();
Tomcat tomcat = new Tomcat();
tomcat.setHostname("localhost");
tomcat.setPort(9090);
Context rootContext = tomcat.addContext("", System.getProperty("java.io.tmpdir"));
ServletHttpHandlerAdapter servlet = new ServletHttpHandlerAdapter(httpHandler);
Wrapper servletWrapper = Tomcat.addServlet(rootContext, "httpHandlerServlet", servlet);
servletWrapper.setAsyncSupported(true);
rootContext.addServletMappingDecoded("/", "httpHandlerServlet");
TomcatWebServer server = new TomcatWebServer(tomcat);
server.start();
return server;
}
public static void main(String[] args) {
try {
new FunctionalWebApplication().start();
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,25 @@
package com.baeldung.functional;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
class IndexRewriteFilter implements WebFilter {
@Override
public Mono<Void> filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) {
ServerHttpRequest request = serverWebExchange.getRequest();
if (request.getURI()
.getPath()
.equals("/")) {
return webFilterChain.filter(serverWebExchange.mutate()
.request(builder -> builder.method(request.getMethod())
.path("/test"))
.build());
}
return webFilterChain.filter(serverWebExchange);
}
}

View File

@@ -0,0 +1,82 @@
package com.baeldung.functional;
import static org.springframework.web.reactive.function.BodyExtractors.toDataBuffers;
import static org.springframework.web.reactive.function.BodyExtractors.toFormData;
import static org.springframework.web.reactive.function.BodyInserters.fromValue;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RequestPredicates.POST;
import static org.springframework.web.reactive.function.server.RequestPredicates.path;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
import static org.springframework.web.reactive.function.server.RouterFunctions.toHttpHandler;
import static org.springframework.web.reactive.function.server.ServerResponse.ok;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.http.server.reactive.ServletHttpHandlerAdapter;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.WebHandler;
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
public class RootServlet extends ServletHttpHandlerAdapter {
public RootServlet() {
this(WebHttpHandlerBuilder.webHandler((WebHandler) toHttpHandler(routingFunction()))
.filter(new IndexRewriteFilter())
.build());
}
RootServlet(HttpHandler httpHandler) {
super(httpHandler);
}
private static final Actor BRAD_PITT = new Actor("Brad", "Pitt");
private static final Actor TOM_HANKS = new Actor("Tom", "Hanks");
private static final List<Actor> actors = new CopyOnWriteArrayList<>(Arrays.asList(BRAD_PITT, TOM_HANKS));
private static RouterFunction<?> routingFunction() {
return route(GET("/test"), serverRequest -> ok().body(fromValue("helloworld"))).andRoute(POST("/login"), serverRequest -> serverRequest.body(toFormData())
.map(MultiValueMap::toSingleValueMap)
.map(formData -> {
System.out.println("form data: " + formData.toString());
if ("baeldung".equals(formData.get("user")) && "you_know_what_to_do".equals(formData.get("token"))) {
return ok().body(Mono.just("welcome back!"), String.class)
.block();
}
return ServerResponse.badRequest()
.build()
.block();
}))
.andRoute(POST("/upload"), serverRequest -> serverRequest.body(toDataBuffers())
.collectList()
.map(dataBuffers -> {
AtomicLong atomicLong = new AtomicLong(0);
dataBuffers.forEach(d -> atomicLong.addAndGet(d.asByteBuffer()
.array().length));
System.out.println("data length:" + atomicLong.get());
return ok().body(fromValue(atomicLong.toString()))
.block();
}))
.and(RouterFunctions.resources("/files/**", new ClassPathResource("files/")))
.andNest(path("/actor"), route(GET("/"), serverRequest -> ok().body(Flux.fromIterable(actors), Actor.class)).andRoute(POST("/"), serverRequest -> serverRequest.bodyToMono(Actor.class)
.doOnNext(actors::add)
.then(ok().build())))
.filter((request, next) -> {
System.out.println("Before handler invocation: " + request.path());
return next.handle(request);
});
}
}

View File

@@ -0,0 +1,13 @@
package com.baeldung.reactive;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Spring5ReactiveApplication{
public static void main(String[] args) {
SpringApplication.run(Spring5ReactiveApplication.class, args);
}
}

View File

@@ -0,0 +1,46 @@
package com.baeldung.reactive.controller;
import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
import java.time.Duration;
import java.util.Random;
import java.util.stream.Stream;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import com.baeldung.reactive.model.Foo;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.util.function.Tuple2;
@RestController
public class FooReactiveController {
@GetMapping("/foos/{id}")
public Mono<Foo> getFoo(@PathVariable("id") long id) {
return Mono.just(new Foo(id, randomAlphabetic(6)));
}
@GetMapping(produces = MediaType.TEXT_EVENT_STREAM_VALUE, value = "/foos")
public Flux<Foo> getAllFoos2() {
final Flux<Foo> foosFlux = Flux.fromStream(Stream.generate(() -> new Foo(new Random().nextLong(), randomAlphabetic(6))));
final Flux<Long> emmitFlux = Flux.interval(Duration.ofSeconds(1));
return Flux.zip(foosFlux, emmitFlux).map(Tuple2::getT1);
}
@GetMapping(produces = MediaType.TEXT_EVENT_STREAM_VALUE, value = "/foos2")
public Flux<Foo> getAllFoos() {
final Flux<Foo> flux = Flux.<Foo> create(fluxSink -> {
while (true) {
fluxSink.next(new Foo(new Random().nextLong(), randomAlphabetic(6)));
}
}).sample(Duration.ofSeconds(1)).log();
return flux;
}
}

View File

@@ -0,0 +1,39 @@
package com.baeldung.reactive.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class PathPatternController {
@GetMapping("/spring5/{*id}")
public String URIVariableHandler(@PathVariable String id) {
return id;
}
@GetMapping("/s?ring5")
public String wildcardTakingExactlyOneChar() {
return "/s?ring5";
}
@GetMapping("/spring5/*id")
public String wildcardTakingZeroOrMoreChar() {
return "/spring5/*id";
}
@GetMapping("/resources/**")
public String wildcardTakingZeroOrMorePathSegments() {
return "/resources/**";
}
@GetMapping("/{baeldung:[a-z]+}")
public String regexInPathVariable(@PathVariable String baeldung) {
return baeldung;
}
@GetMapping("/{var1}_{var2}")
public String multiplePathVariablesInSameSegment(@PathVariable String var1, @PathVariable String var2) {
return "Two variables are var1=" + var1 + " and var2=" + var2;
}
}

View File

@@ -0,0 +1,22 @@
package com.baeldung.reactive.filters;
import org.springframework.web.reactive.function.server.HandlerFilterFunction;
import org.springframework.web.reactive.function.server.HandlerFunction;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
import static org.springframework.http.HttpStatus.FORBIDDEN;
public class ExampleHandlerFilterFunction implements HandlerFilterFunction<ServerResponse, ServerResponse> {
@Override
public Mono<ServerResponse> filter(ServerRequest serverRequest, HandlerFunction<ServerResponse> handlerFunction) {
if (serverRequest.pathVariable("name").equalsIgnoreCase("test")) {
return ServerResponse.status(FORBIDDEN).build();
}
return handlerFunction.handle(serverRequest);
}
}

View File

@@ -0,0 +1,17 @@
package com.baeldung.reactive.filters;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
@Component
public class ExampleWebFilter implements WebFilter {
@Override
public Mono<Void> filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) {
serverWebExchange.getResponse().getHeaders().add("web-filter", "web-filter-test");
return webFilterChain.filter(serverWebExchange);
}
}

View File

@@ -0,0 +1,17 @@
package com.baeldung.reactive.filters;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
import static org.springframework.web.reactive.function.server.ServerResponse.ok;
@Component
class PlayerHandler {
Mono<ServerResponse> getName(ServerRequest request) {
Mono<String> name = Mono.just(request.pathVariable("name"));
return ok().body(name, String.class);
}
}

View File

@@ -0,0 +1,20 @@
package com.baeldung.reactive.filters;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
@Configuration
public class PlayerRouter {
@Bean
public RouterFunction<ServerResponse> route(PlayerHandler playerHandler) {
return RouterFunctions
.route(GET("/players/{name}"), playerHandler::getName)
.filter(new ExampleHandlerFilterFunction());
}
}

View File

@@ -0,0 +1,15 @@
package com.baeldung.reactive.filters;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
@RestController
public class UserController {
@GetMapping(path = "/users/{name}")
public Mono<String> getName(@PathVariable String name) {
return Mono.just(name);
}
}

View File

@@ -0,0 +1,13 @@
package com.baeldung.reactive.model;
import lombok.AllArgsConstructor;
import lombok.Data;
@AllArgsConstructor
@Data
public class Foo {
private long id;
private String name;
}

View File

@@ -0,0 +1,35 @@
package com.baeldung.reactive.responseheaders.controllers;
import org.springframework.http.ResponseEntity;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/response-header")
public class ResponseHeaderController {
@GetMapping("/response-entity")
public Mono<ResponseEntity<String>> usingResponseEntityBuilder() {
String responseHeaderKey = "Baeldung-Example-Header";
String responseHeaderValue = "Value-ResponseEntityBuilder";
String responseBody = "Response with header using ResponseEntity (builder)";
return Mono.just(ResponseEntity.ok()
.header(responseHeaderKey, responseHeaderValue)
.body(responseBody));
}
@GetMapping("/server-http-response")
public Mono<String> usingServerHttpResponse(ServerHttpResponse response) {
String responseHeaderKey = "Baeldung-Example-Header";
String responseHeaderValue = "Value-ServerHttpResponse";
String responseBody = "Response with header using ServerHttpResponse";
response.getHeaders().add(responseHeaderKey, responseHeaderValue);
return Mono.just(responseBody);
}
}

View File

@@ -0,0 +1,20 @@
package com.baeldung.reactive.responseheaders.filter;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
@Component
public class AddResponseHeaderWebFilter implements WebFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
exchange.getResponse()
.getHeaders()
.add("Baeldung-Example-Filter-Header", "Value-Filter");
return chain.filter(exchange);
}
}

View File

@@ -0,0 +1,21 @@
package com.baeldung.reactive.responseheaders.functional.handlers;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
@Component
public class ResponseHeaderHandler {
public Mono<ServerResponse> useHandler(final ServerRequest request) {
String responseHeaderKey = "Baeldung-Example-Header";
String responseHeaderValue = "Value-Handler";
String responseBody = "Response with header using Handler";
return ServerResponse.ok()
.header(responseHeaderKey, responseHeaderValue)
.body(Mono.just(responseBody),String.class);
}
}

View File

@@ -0,0 +1,20 @@
package com.baeldung.reactive.responseheaders.functional.routers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import com.baeldung.reactive.responseheaders.functional.handlers.ResponseHeaderHandler;
@Configuration
public class ResponseHeadersRouterFunctions {
@Bean
public RouterFunction<ServerResponse> responseHeaderRoute(@Autowired ResponseHeaderHandler handler) {
return RouterFunctions.route(RequestPredicates.GET("/functional-response-header/single-handler"), handler::useHandler);
}
}

View File

@@ -0,0 +1,23 @@
package com.baeldung.reactive.urlmatch;
class Actor {
private String firstname;
private String lastname;
public Actor() {
}
public Actor(String firstname, String lastname) {
this.firstname = firstname;
this.lastname = lastname;
}
public String getFirstname() {
return firstname;
}
public String getLastname() {
return lastname;
}
}

View File

@@ -0,0 +1,64 @@
package com.baeldung.reactive.urlmatch;
import static org.springframework.web.reactive.function.BodyInserters.fromValue;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
import static org.springframework.web.reactive.function.server.RouterFunctions.toHttpHandler;
import static org.springframework.web.reactive.function.server.ServerResponse.ok;
import org.apache.catalina.Context;
import org.apache.catalina.Wrapper;
import org.apache.catalina.startup.Tomcat;
import org.springframework.boot.web.embedded.tomcat.TomcatWebServer;
import org.springframework.boot.web.server.WebServer;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.http.server.reactive.ServletHttpHandlerAdapter;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.WebHandler;
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
public class ExploreSpring5URLPatternUsingRouterFunctions {
private RouterFunction<ServerResponse> routingFunction() {
return route(GET("/t?st"), serverRequest -> ok().body(fromValue("Path /t?st is accessed"))).andRoute(GET("/test/{*id}"), serverRequest -> ok().body(fromValue(serverRequest.pathVariable("id"))))
.andRoute(GET("/baeldung/*Id"), serverRequest -> ok().body(fromValue("/baeldung/*Id path was accessed")))
.andRoute(GET("/{var1}_{var2}"), serverRequest -> ok().body(fromValue(serverRequest.pathVariable("var1") + " , " + serverRequest.pathVariable("var2"))))
.andRoute(GET("/{baeldung:[a-z]+}"), serverRequest -> ok().body(fromValue("/{baeldung:[a-z]+} was accessed and baeldung=" + serverRequest.pathVariable("baeldung"))))
.and(RouterFunctions.resources("/files/{*filepaths}", new ClassPathResource("files/")))
.and(RouterFunctions.resources("/resources/**", new ClassPathResource("resources/")));
}
WebServer start() throws Exception {
WebHandler webHandler = (WebHandler) toHttpHandler(routingFunction());
HttpHandler httpHandler = WebHttpHandlerBuilder.webHandler(webHandler)
.filter(new IndexRewriteFilter())
.build();
Tomcat tomcat = new Tomcat();
tomcat.setHostname("localhost");
tomcat.setPort(9090);
Context rootContext = tomcat.addContext("", System.getProperty("java.io.tmpdir"));
ServletHttpHandlerAdapter servlet = new ServletHttpHandlerAdapter(httpHandler);
Wrapper servletWrapper = Tomcat.addServlet(rootContext, "httpHandlerServlet", servlet);
servletWrapper.setAsyncSupported(true);
rootContext.addServletMappingDecoded("/", "httpHandlerServlet");
TomcatWebServer server = new TomcatWebServer(tomcat);
server.start();
return server;
}
public static void main(String[] args) {
try {
new FunctionalWebApplication().start();
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,41 @@
package com.baeldung.reactive.urlmatch;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import static org.springframework.web.reactive.function.BodyExtractors.toDataBuffers;
import static org.springframework.web.reactive.function.BodyExtractors.toFormData;
import static org.springframework.web.reactive.function.BodyInserters.fromValue;
import static org.springframework.web.reactive.function.server.ServerResponse.ok;
public class FormHandler {
Mono<ServerResponse> handleLogin(ServerRequest request) {
return request.body(toFormData())
.map(MultiValueMap::toSingleValueMap)
.filter(formData -> "baeldung".equals(formData.get("user")))
.filter(formData -> "you_know_what_to_do".equals(formData.get("token")))
.flatMap(formData -> ok().body(Mono.just("welcome back!"), String.class))
.switchIfEmpty(ServerResponse.badRequest()
.build());
}
Mono<ServerResponse> handleUpload(ServerRequest request) {
return request.body(toDataBuffers())
.collectList()
.flatMap(dataBuffers -> ok().body(fromValue(extractData(dataBuffers).toString())));
}
private AtomicLong extractData(List<DataBuffer> dataBuffers) {
AtomicLong atomicLong = new AtomicLong(0);
dataBuffers.forEach(d -> atomicLong.addAndGet(d.asByteBuffer()
.array().length));
return atomicLong;
}
}

View File

@@ -0,0 +1,80 @@
package com.baeldung.reactive.urlmatch;
import static org.springframework.web.reactive.function.BodyInserters.fromValue;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RequestPredicates.POST;
import static org.springframework.web.reactive.function.server.RequestPredicates.path;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
import static org.springframework.web.reactive.function.server.RouterFunctions.toHttpHandler;
import static org.springframework.web.reactive.function.server.ServerResponse.ok;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import org.apache.catalina.Context;
import org.apache.catalina.startup.Tomcat;
import org.springframework.boot.web.embedded.tomcat.TomcatWebServer;
import org.springframework.boot.web.server.WebServer;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.http.server.reactive.ServletHttpHandlerAdapter;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.WebHandler;
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
import reactor.core.publisher.Flux;
public class FunctionalWebApplication {
private static final Actor BRAD_PITT = new Actor("Brad", "Pitt");
private static final Actor TOM_HANKS = new Actor("Tom", "Hanks");
private static final List<Actor> actors = new CopyOnWriteArrayList<>(Arrays.asList(BRAD_PITT, TOM_HANKS));
private RouterFunction<ServerResponse> routingFunction() {
FormHandler formHandler = new FormHandler();
RouterFunction<ServerResponse> restfulRouter = route(GET("/"), serverRequest -> ok().body(Flux.fromIterable(actors), Actor.class)).andRoute(POST("/"), serverRequest -> serverRequest.bodyToMono(Actor.class)
.doOnNext(actors::add)
.then(ok().build()));
return route(GET("/test"), serverRequest -> ok().body(fromValue("helloworld"))).andRoute(POST("/login"), formHandler::handleLogin)
.andRoute(POST("/upload"), formHandler::handleUpload)
.and(RouterFunctions.resources("/files/**", new ClassPathResource("files/")))
.andNest(path("/actor"), restfulRouter)
.filter((request, next) -> {
System.out.println("Before handler invocation: " + request.path());
return next.handle(request);
});
}
WebServer start() throws Exception {
WebHandler webHandler = (WebHandler) toHttpHandler(routingFunction());
HttpHandler httpHandler = WebHttpHandlerBuilder.webHandler(webHandler)
.filter(new IndexRewriteFilter())
.build();
Tomcat tomcat = new Tomcat();
tomcat.setHostname("localhost");
tomcat.setPort(9090);
Context rootContext = tomcat.addContext("", System.getProperty("java.io.tmpdir"));
ServletHttpHandlerAdapter servlet = new ServletHttpHandlerAdapter(httpHandler);
Tomcat.addServlet(rootContext, "httpHandlerServlet", servlet);
rootContext.addServletMappingDecoded("/", "httpHandlerServlet");
TomcatWebServer server = new TomcatWebServer(tomcat);
server.start();
return server;
}
public static void main(String[] args) {
try {
new FunctionalWebApplication().start();
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,27 @@
package com.baeldung.reactive.urlmatch;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
class IndexRewriteFilter implements WebFilter {
@Override
public Mono<Void> filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) {
ServerHttpRequest request = serverWebExchange.getRequest();
if (request.getURI()
.getPath()
.equals("/")) {
return webFilterChain.filter(serverWebExchange.mutate()
.request(builder -> builder.method(request.getMethod())
.contextPath(request.getPath()
.toString())
.path("/test"))
.build());
}
return webFilterChain.filter(serverWebExchange);
}
}

View File

@@ -0,0 +1,15 @@
package com.baeldung.reactive.util;
import com.sun.management.OperatingSystemMXBean;
import java.lang.management.ManagementFactory;
public class CpuUtils {
private static OperatingSystemMXBean operatingSystemMXBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
static Double getUsage() {
return (operatingSystemMXBean.getSystemCpuLoad() / operatingSystemMXBean.getAvailableProcessors()) * 100;
}
}

View File

@@ -0,0 +1,15 @@
package com.baeldung.websession;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan(basePackages = {"com.baeldung"})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

View File

@@ -0,0 +1,17 @@
package com.baeldung.websession.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.session.data.redis.config.annotation.web.server.EnableRedisWebSession;
@Configuration
//@EnableRedisWebSession
public class RedisConfig {
/**
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory();
}
*/
}

View File

@@ -0,0 +1,20 @@
package com.baeldung.websession.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.session.ReactiveMapSessionRepository;
import org.springframework.session.ReactiveSessionRepository;
import org.springframework.session.config.annotation.web.server.EnableSpringWebSession;
import java.util.concurrent.ConcurrentHashMap;
@Configuration
@EnableSpringWebSession
public class SessionConfig {
@Bean
public ReactiveSessionRepository reactiveSessionRepository() {
return new ReactiveMapSessionRepository(new ConcurrentHashMap<>());
}
}

View File

@@ -0,0 +1,20 @@
package com.baeldung.websession.configuration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.config.EnableWebFlux;
import org.springframework.web.reactive.config.ResourceHandlerRegistry;
import org.springframework.web.reactive.config.WebFluxConfigurer;
@Configuration
@EnableWebFlux
public class WebFluxConfig implements ApplicationContextAware, WebFluxConfigurer {
private ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext context) {
this.context = context;
}
}

View File

@@ -0,0 +1,56 @@
package com.baeldung.websession.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.core.userdetails.MapReactiveUserDetailsService;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.context.WebSessionServerSecurityContextRepository;
@Configuration
@EnableWebFluxSecurity
public class WebFluxSecurityConfig {
@Bean
public MapReactiveUserDetailsService userDetailsService() {
UserDetails admin = User
.withUsername("admin")
.password(encoder().encode("password"))
.roles("ADMIN")
.build();
UserDetails user = User
.withUsername("user")
.password(encoder().encode("password"))
.roles("USER")
.build();
return new MapReactiveUserDetailsService(admin, user);
}
@Bean
public SecurityWebFilterChain webSessionSpringSecurityFilterChain(ServerHttpSecurity http) {
http.authorizeExchange()
.anyExchange().authenticated()
.and()
.httpBasic()
.securityContextRepository(new WebSessionServerSecurityContextRepository())
.and()
.formLogin();
http.csrf().disable();
return http.build();
}
@Bean
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
}

View File

@@ -0,0 +1,42 @@
package com.baeldung.websession.controller;
import com.baeldung.websession.transfer.CustomResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.WebSession;
import reactor.core.publisher.Mono;
@RestController
public class SessionController {
@GetMapping("/websession/test")
public Mono<CustomResponse> testWebSessionByParam(
@RequestParam(value = "id") int id,
@RequestParam(value = "note") String note,
WebSession session) {
session.getAttributes().put("id", id);
session.getAttributes().put("note", note);
CustomResponse r = new CustomResponse();
r.setId((int) session.getAttributes().get("id"));
r.setNote((String) session.getAttributes().get("note"));
return Mono.just(r);
}
@GetMapping("/websession")
public Mono<CustomResponse> getSession(WebSession session) {
session.getAttributes().putIfAbsent("id", 0);
session.getAttributes().putIfAbsent("note", "Howdy Cosmic Spheroid!");
CustomResponse r = new CustomResponse();
r.setId((int) session.getAttributes().get("id"));
r.setNote((String) session.getAttributes().get("note"));
return Mono.just(r);
}
}

View File

@@ -0,0 +1,31 @@
package com.baeldung.websession.transfer;
public class CustomResponse {
private int id;
private String note;
public CustomResponse() {}
public CustomResponse(int id, String note) {
this.id = id;
this.note = note;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
}

View File

@@ -0,0 +1,11 @@
package com.baeldung.websocket;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class Event {
private String eventId;
private String eventDt;
}

View File

@@ -0,0 +1,26 @@
package com.baeldung.websocket;
import java.net.URI;
import java.time.Duration;
import org.springframework.web.reactive.socket.WebSocketMessage;
import org.springframework.web.reactive.socket.client.ReactorNettyWebSocketClient;
import org.springframework.web.reactive.socket.client.WebSocketClient;
import reactor.core.publisher.Mono;
public class ReactiveJavaClientWebSocket {
public static void main(String[] args) throws InterruptedException {
WebSocketClient client = new ReactorNettyWebSocketClient();
client.execute(
URI.create("ws://localhost:8080/event-emitter"),
session -> session.send(
Mono.just(session.textMessage("event-spring-reactive-client-websocket")))
.thenMany(session.receive()
.map(WebSocketMessage::getPayloadAsText)
.log())
.then())
.block(Duration.ofSeconds(10L));
}
}

View File

@@ -0,0 +1,11 @@
package com.baeldung.websocket;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ReactiveWebSocketApplication {
public static void main(String[] args) {
SpringApplication.run(ReactiveWebSocketApplication.class, args);
}
}

View File

@@ -0,0 +1,37 @@
package com.baeldung.websocket;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.HandlerMapping;
import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping;
import org.springframework.web.reactive.socket.WebSocketHandler;
import org.springframework.web.reactive.socket.server.support.WebSocketHandlerAdapter;
@Configuration
public class ReactiveWebSocketConfiguration {
@Autowired
@Qualifier("ReactiveWebSocketHandler")
private WebSocketHandler webSocketHandler;
@Bean
public HandlerMapping webSocketHandlerMapping() {
Map<String, WebSocketHandler> map = new HashMap<>();
map.put("/event-emitter", webSocketHandler);
SimpleUrlHandlerMapping handlerMapping = new SimpleUrlHandlerMapping();
handlerMapping.setOrder(1);
handlerMapping.setUrlMap(map);
return handlerMapping;
}
@Bean
public WebSocketHandlerAdapter handlerAdapter() {
return new WebSocketHandlerAdapter();
}
}

View File

@@ -0,0 +1,41 @@
package com.baeldung.websocket;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.socket.WebSocketHandler;
import org.springframework.web.reactive.socket.WebSocketMessage;
import org.springframework.web.reactive.socket.WebSocketSession;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.Duration;
import static java.time.LocalDateTime.now;
import static java.util.UUID.randomUUID;
@Component("ReactiveWebSocketHandler")
public class ReactiveWebSocketHandler implements WebSocketHandler {
private static final ObjectMapper json = new ObjectMapper();
private Flux<String> eventFlux = Flux.generate(sink -> {
Event event = new Event(randomUUID().toString(), now().toString());
try {
sink.next(json.writeValueAsString(event));
} catch (JsonProcessingException e) {
sink.error(e);
}
});
private Flux<String> intervalFlux = Flux.interval(Duration.ofMillis(1000L))
.zipWith(eventFlux, (time, event) -> event);
@Override
public Mono<Void> handle(WebSocketSession webSocketSession) {
return webSocketSession.send(intervalFlux
.map(webSocketSession::textMessage))
.and(webSocketSession.receive()
.map(WebSocketMessage::getPayloadAsText).log());
}
}

View File

@@ -0,0 +1 @@
logging.level.root=INFO

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Baeldung: Spring 5 Reactive Client WebSocket (Browser)</title>
</head>
<body>
<div class="events"></div>
<script>
var clientWebSocket = new WebSocket("ws://localhost:8080/event-emitter");
clientWebSocket.onopen = function() {
console.log("clientWebSocket.onopen", clientWebSocket);
console.log("clientWebSocket.readyState", "websocketstatus");
clientWebSocket.send("event-me-from-browser");
}
clientWebSocket.onclose = function(error) {
console.log("clientWebSocket.onclose", clientWebSocket, error);
events("Closing connection");
}
clientWebSocket.onerror = function(error) {
console.log("clientWebSocket.onerror", clientWebSocket, error);
events("An error occured");
}
clientWebSocket.onmessage = function(error) {
console.log("clientWebSocket.onmessage", clientWebSocket, error);
events(error.data);
}
function events(responseEvent) {
document.querySelector(".events").innerHTML += responseEvent + "<br>";
}
</script>
</body>
</html>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<display-name>Spring Functional Application</display-name>
<servlet>
<servlet-name>functional</servlet-name>
<servlet-class>com.baeldung.functional.RootServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>functional</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>

View File

@@ -0,0 +1,17 @@
package com.baeldung;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import com.baeldung.reactive.Spring5ReactiveApplication;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Spring5ReactiveApplication.class)
public class SpringContextTest {
@Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
}
}

View File

@@ -0,0 +1,141 @@
package com.baeldung.functional;
import static org.springframework.web.reactive.function.BodyInserters.fromValue;
import static org.springframework.web.reactive.function.BodyInserters.fromResource;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.boot.web.server.WebServer;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.BodyInserters;
public class FunctionalWebApplicationIntegrationTest {
private static WebTestClient client;
private static WebServer server;
@BeforeClass
public static void setup() throws Exception {
server = new FunctionalWebApplication().start();
client = WebTestClient.bindToServer()
.baseUrl("http://localhost:" + server.getPort())
.build();
}
@AfterClass
public static void destroy() {
server.stop();
}
@Test
public void givenRouter_whenGetTest_thenGotHelloWorld() throws Exception {
client.get()
.uri("/test")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("helloworld");
}
@Test
public void givenIndexFilter_whenRequestRoot_thenRewrittenToTest() throws Exception {
client.get()
.uri("/")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("helloworld");
}
@Test
public void givenLoginForm_whenPostValidToken_thenSuccess() throws Exception {
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>(1);
formData.add("user", "baeldung");
formData.add("token", "you_know_what_to_do");
client.post()
.uri("/login")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.body(BodyInserters.fromFormData(formData))
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("welcome back!");
}
@Test
public void givenLoginForm_whenRequestWithInvalidToken_thenFail() throws Exception {
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>(2);
formData.add("user", "baeldung");
formData.add("token", "try_again");
client.post()
.uri("/login")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.body(BodyInserters.fromFormData(formData))
.exchange()
.expectStatus()
.isBadRequest();
}
@Test
public void givenUploadForm_whenRequestWithMultipartData_thenSuccess() throws Exception {
Resource resource = new ClassPathResource("/baeldung-weekly.png");
client.post()
.uri("/upload")
.contentType(MediaType.MULTIPART_FORM_DATA)
.body(fromResource(resource))
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo(String.valueOf(resource.contentLength()));
}
@Test
public void givenActors_whenAddActor_thenAdded() throws Exception {
client.get()
.uri("/actor")
.exchange()
.expectStatus()
.isOk()
.expectBodyList(Actor.class)
.hasSize(2);
client.post()
.uri("/actor")
.body(fromValue(new Actor("Clint", "Eastwood")))
.exchange()
.expectStatus()
.isOk();
client.get()
.uri("/actor")
.exchange()
.expectStatus()
.isOk()
.expectBodyList(Actor.class)
.hasSize(3);
}
@Test
public void givenResources_whenAccess_thenGot() throws Exception {
client.get()
.uri("/files/hello.txt")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("hello");
}
}

View File

@@ -0,0 +1,32 @@
package com.baeldung.reactive;
import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
import static org.junit.Assert.assertNotNull;
import java.time.Duration;
import java.util.Random;
import org.junit.jupiter.api.Test;
import com.baeldung.reactive.model.Foo;
import reactor.core.publisher.Flux;
public class FluxUnitTest {
public static final Random RANDOM = new Random();
@Test
public void whenFluxIsConstructed_thenCorrect() {
final Flux<Foo> flux = Flux.<Foo> create(fluxSink -> {
for (int i = 0 ; i < 100 ; i++) {
fluxSink.next(new Foo(RANDOM.nextLong(), randomAlphabetic(6)));
}
}).sample(Duration.ofSeconds(1)).log();
flux.subscribe();
assertNotNull(flux);
}
}

View File

@@ -0,0 +1,43 @@
package com.baeldung.reactive.filters;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.EntityExchangeResult;
import org.springframework.test.web.reactive.server.WebTestClient;
import static org.junit.Assert.assertEquals;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@WithMockUser
@AutoConfigureWebTestClient(timeout = "10000")
public class PlayerHandlerIntegrationTest {
@Autowired
private WebTestClient webTestClient;
@Test
public void whenPlayerNameIsBaeldung_thenWebFilterIsApplied() {
EntityExchangeResult<String> result = webTestClient.get().uri("/players/baeldung")
.exchange()
.expectStatus().isOk()
.expectBody(String.class)
.returnResult();
assertEquals(result.getResponseBody(), "baeldung");
assertEquals(result.getResponseHeaders().getFirst("web-filter"), "web-filter-test");
}
@Test
public void whenPlayerNameIsTest_thenHandlerFilterFunctionIsApplied() {
webTestClient.get().uri("/players/test")
.exchange()
.expectStatus().isForbidden();
}
}

View File

@@ -0,0 +1,40 @@
package com.baeldung.reactive.filters;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.EntityExchangeResult;
import org.springframework.test.web.reactive.server.WebTestClient;
import static org.junit.Assert.assertEquals;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@WithMockUser
public class UserControllerIntegrationTest {
@Autowired
private WebTestClient webTestClient;
@Test
public void whenUserNameIsBaeldung_thenWebFilterIsApplied() {
EntityExchangeResult<String> result = webTestClient.get().uri("/users/baeldung")
.exchange()
.expectStatus().isOk()
.expectBody(String.class)
.returnResult();
assertEquals(result.getResponseBody(), "baeldung");
assertEquals(result.getResponseHeaders().getFirst("web-filter"), "web-filter-test");
}
@Test
public void whenUserNameIsTest_thenHandlerFilterFunctionIsNotApplied() {
webTestClient.get().uri("/users/test")
.exchange()
.expectStatus().isOk();
}
}

View File

@@ -0,0 +1,60 @@
package com.baeldung.reactive.responseheaders;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.test.web.reactive.server.WebTestClient.ResponseSpec;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class ResponseHeaderLiveTest {
private static final String BASE_URL = "http://localhost:8080";
private static final String ANNOTATION_BASE_URL = BASE_URL + "/response-header";
private static final String FUNCTIONAL_BASE_URL = BASE_URL + "/functional-response-header";
private static final String SERVICE_SINGLE_RESPONSE_HEADER = "Baeldung-Example-Header";
private static final String SERVICE_FILTER_RESPONSE_HEADER = "Baeldung-Example-Filter-Header";
private static final String SERVICE_FILTER_RESPONSE_HEADER_VALUE = "Value-Filter";
private static WebTestClient client;
@BeforeAll
public static void setup() {
client = WebTestClient.bindToServer()
.baseUrl(BASE_URL)
.build();
}
@Test
public void whenUsingResponseEntityBuilderRequest_thenObtainResponseWithCorrectHeaders() {
client = WebTestClient.bindToServer()
.baseUrl(BASE_URL)
.build();
ResponseSpec response = client.get()
.uri(ANNOTATION_BASE_URL + "/response-entity")
.exchange();
response.expectHeader().valueEquals(SERVICE_SINGLE_RESPONSE_HEADER, "Value-ResponseEntityBuilder")
.expectHeader().valueEquals(SERVICE_FILTER_RESPONSE_HEADER, SERVICE_FILTER_RESPONSE_HEADER_VALUE);
}
@Test
public void whenUsingServerHttpResponseRequest_thenObtainResponseWithCorrectHeaders() {
ResponseSpec response = client.get()
.uri(ANNOTATION_BASE_URL + "/server-http-response")
.exchange();
response.expectHeader().valueEquals(SERVICE_SINGLE_RESPONSE_HEADER, "Value-ServerHttpResponse")
.expectHeader().valueEquals(SERVICE_FILTER_RESPONSE_HEADER, SERVICE_FILTER_RESPONSE_HEADER_VALUE);
}
@Test
public void whenUsingFunctionalHandlerRequest_thenObtainResponseWithCorrectHeaders() {
ResponseSpec response = client.get()
.uri(FUNCTIONAL_BASE_URL + "/single-handler")
.exchange();
response.expectHeader().valueEquals(SERVICE_SINGLE_RESPONSE_HEADER, "Value-Handler")
.expectHeader().valueEquals(SERVICE_FILTER_RESPONSE_HEADER, SERVICE_FILTER_RESPONSE_HEADER_VALUE);
}
}

View File

@@ -0,0 +1,120 @@
package com.baeldung.reactive.urlmatch;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.boot.web.server.WebServer;
import org.springframework.test.web.reactive.server.WebTestClient;
public class ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest {
private static WebTestClient client;
private static WebServer server;
@BeforeClass
public static void setup() throws Exception {
server = new ExploreSpring5URLPatternUsingRouterFunctions().start();
client = WebTestClient.bindToServer()
.baseUrl("http://localhost:" + server.getPort())
.build();
}
@AfterClass
public static void destroy() {
server.stop();
}
@Test
public void givenRouter_whenGetPathWithSingleCharWildcard_thenGotPathPattern() throws Exception {
client.get()
.uri("/test")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("Path /t?st is accessed");
}
@Test
public void givenRouter_whenMultipleURIVariablePattern_thenGotPathVariable() throws Exception {
client.get()
.uri("/test/ab/cd")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("/ab/cd");
}
@Test
public void givenRouter_whenGetMultipleCharWildcard_thenGotPathPattern() throws Exception {
client.get()
.uri("/baeldung/tutorialId")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("/baeldung/*Id path was accessed");
}
@Test
public void givenRouter_whenGetMultiplePathVaribleInSameSegment_thenGotPathVariables() throws Exception {
client.get()
.uri("/baeldung_tutorial")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("baeldung , tutorial");
}
@Test
public void givenRouter_whenGetRegexInPathVarible_thenGotPathVariable() throws Exception {
client.get()
.uri("/abcd")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("/{baeldung:[a-z]+} was accessed and baeldung=abcd");
client.get()
.uri("/1234")
.exchange()
.expectStatus()
.is4xxClientError();
}
@Test
public void givenResources_whenAccess_thenGot() throws Exception {
client.get()
.uri("/files/test/test.txt")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("test");
client.get()
.uri("/files/hello.txt")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("hello");
}
@Test
public void givenRouter_whenAccess_thenGot() throws Exception {
client.get()
.uri("/resources/test/test.txt")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("test");
}
}

View File

@@ -0,0 +1,113 @@
package com.baeldung.reactive.urlmatch;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;
import com.baeldung.reactive.Spring5ReactiveApplication;
import com.baeldung.reactive.controller.PathPatternController;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Spring5ReactiveApplication.class)
@WithMockUser
public class PathPatternsUsingHandlerMethodIntegrationTest {
private static WebTestClient client;
@BeforeClass
public static void setUp() {
client = WebTestClient.bindToController(new PathPatternController())
.build();
}
@Test
public void givenHandlerMethod_whenMultipleURIVariablePattern_then200() {
client.get()
.uri("/spring5/baeldung/tutorial")
.exchange()
.expectStatus()
.is2xxSuccessful()
.expectBody()
.equals("/baeldung/tutorial");
client.get()
.uri("/spring5/baeldung")
.exchange()
.expectStatus()
.is2xxSuccessful()
.expectBody()
.equals("/baeldung");
}
@Test
public void givenHandlerMethod_whenURLWithWildcardTakingZeroOrMoreChar_then200() {
client.get()
.uri("/spring5/userid")
.exchange()
.expectStatus()
.is2xxSuccessful()
.expectBody()
.equals("/spring5/*id");
}
@Test
public void givenHandlerMethod_whenURLWithWildcardTakingExactlyOneChar_then200() {
client.get()
.uri("/string5")
.exchange()
.expectStatus()
.is2xxSuccessful()
.expectBody()
.equals("/s?ring5");
}
@Test
public void givenHandlerMethod_whenURLWithWildcardTakingZeroOrMorePathSegments_then200() {
client.get()
.uri("/resources/baeldung")
.exchange()
.expectStatus()
.is2xxSuccessful()
.expectBody()
.equals("/resources/**");
}
@Test
public void givenHandlerMethod_whenURLWithRegexInPathVariable_thenExpectedOutput() {
client.get()
.uri("/abc")
.exchange()
.expectStatus()
.is2xxSuccessful()
.expectBody()
.equals("abc");
client.get()
.uri("/123")
.exchange()
.expectStatus()
.is4xxClientError();
}
@Test
public void givenHandlerMethod_whenURLWithMultiplePathVariablesInSameSegment_then200() {
client.get()
.uri("/baeldung_tutorial")
.exchange()
.expectStatus()
.is2xxSuccessful()
.expectBody()
.equals("Two variables are var1=baeldung and var2=tutorial");
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB