Skip to main content
Blog

Spring WebFlux annotation based

By 5 oktober 2017november 13th, 2017No Comments

The release of Spring Framework version 5 is just around the corner and it contains a lot of new features. One of those is the WebFlux framework. It adds support for reactive web programming on client and server side. Spring WebFlux uses Reactor to make it all possible. The server side supports two programming models:

  • Annotation based, using @Controller annotations.
  • Functional, using Java 8 lambdas for routing and request handling.

The annotation based model correlates most to what we have been doing for years using Spring MVC. We are able to use all the things we know, but in a reactive manner. On the outside there is little difference. The biggest change is on the inside. The underlying implemenation is based on a reactive implementation of HttpServletRequest and HttpServletResponse. This blog focuses on the annotation based model. A future blog will show the functional model.

Let’s have a look at a a simple application that serves the names of the planets in our solar system, optionally applying a filter, as plain text using a line for each planet. Using curl I would like to see the following:

$ curl http://localhost:8080/planets
Mercury
Venus
Earth
Mars
Jupiter
Saturn
Uranus
Neptune
$ curl http://localhost:8080/planets/s
Venus
Mars
Saturn
Uranus

Not too spectacular, but it will suit the purpose of this blog. A Spring MVC controller doing the job will look something like this:

@RestController
@AllArgsConstructor
public class PlanetController {

    private PlanetRepository planetRepository;

    @RequestMapping(path={"/planets/{substring}","/planets"})
    public String getMatchingPlanets(@PathVariable(name = "substring", required=false) Optional<String> substring) {
        return planetRepository.getPlanets()
                .filter( p -> p.toLowerCase().contains(substring.orElse("").toLowerCase()))
                .reduce("",  (l,r) -> l + r + "\n");
    }
}

Nothing strange here. We have a PlanetRepository that gives us a Stream<String> of planets. A controller with a @RequestMapping to handle the request and produce a suitable response. Switching to Spring WebFlux requires some changes. First change the dependency on Spring MVC to Spring WebFlux. If you are like me and use Spring Boot, you can swap spring-boot-starter-web for spring-boot-starter-webflux. Next we need to update the response type of the request mapping methods to either Flux<String> or Mono<String>. WebFlux requires the request handling methods to return on of these types. The updated controller looks like:

@RestController
@AllArgsConstructor
public class PlanetController {

    private PlanetRepository planetRepository;

    @RequestMapping(path={"/planets/{substring}","/planets"})
    public Flux<String> getMatchingPlanets(@PathVariable(name = "substring", required=false) Optional<String> substring) {
        return Flux.fromStream(planetRepository.getPlanets()
                .filter( p -> p.toLowerCase().contains(substring.orElse("").toLowerCase()))
                .map( p -> p + "\n"));
    }
}

As you can see we now return a response of Flux<String>. We could have used Mono<String> which is used for non collection types, but as we are showing one planet per line, we can treat it as a stream of planets. Therefore a Flux<String> is the better option.

As mentioned before, we are using a PlanetRepository that supplies us with a Stream<String> of planets and to convert it to a Flux<String> type, we use the static factory method Flux.fromStream(Stream<T>). As a flux is quite similar to a stream, we can make our code a bit cleaner by having the PlanetRepository return a Flux<String> instead of a Stream<String>. Our controller will then look like:

@RestController
@AllArgsConstructor
public class PlanetController {

    private PlanetRepository planetRepository;

    @RequestMapping(path={"/planets/{substring}","/planets"})
    public Flux<String> getMatchingPlanets(@PathVariable(name = "substring", required=false) Optional<String> substring) {
        return planetRepository.getPlanets()
                .filter( p -> p.toLowerCase().contains(substring.orElse("").toLowerCase()))
                .map( p -> p + "\n");
    }
}

There you go – a fully reactive web controller. The full source code for the project can be found on github.

This is a cross-post from my personal blog. Follow me on @acuriouscoder if you like what you’re reading or subscribe to my blog on https://acuriouscoder.net.