MVC

Spring MVC Functional Programming Example

1. Spring MVC Functional Programming – Introduction

In this post, we feature a comprehensive article on Spring MVC Functional Programming. With the advent of Java 8, there were drastic changes in the way Java programming was done. Java 8 brought into picture functional interfaces. Functional interfaces are Java interfaces containing one and only one abstract method. The functional interfaces became popular for use as arguments to the functions. The functional interfaces can be passed in the form of callback actions to any function.

Spring MVC embraced this concept of functional interface in its Spring Webflux Framework. Spring Webflux is a reactive programming based framework that allows you to create fully non-blocking code using all the core features of Spring MVC framework. In this article, we discuss in detail about Spring MVC functional programming with an example. The article should help you get started with the reactive programming using Spring Webflux.

2. Reactive Programming

Before we get into understanding how to leverage the Spring Functional programming features, it is important to understand what is Reactive Programming. Reactive Programming is a method of asynchronous programming where the data is processed using event driven and non-blocking code. Reactive programming helps in modelling the data in the form of reactive streams that are observable for changes. These observable streams are then consumed to perform action or send a response.

Reactive programming relies on the Reactive Streams API that was introduced in Java 9. They work on the concept of publish and subscribe of data. These APIs and their usage will be discussed in the next section.

3. Reactive Stream APIs

The Reactive Stream APIs were introduced as a feature in Java 9 to allow the users to develop code that is absolutely non-blocking. A non-blocking code allows the users to get a reactive UI which automatically changes its data as the data is published. Reactivity is the concept first introduced in Angular & Meteor JS frontend framework. In Angular, the reactive nature is used to make asynchronous API calls while allow the user to interact with the UI. However, the API call still remains stuck in the backend due to blocking nature of the API calls in Java.

The Reactive stream APIs solve this problem in a similar way. The reactive stream APIs allows the frontend to Subscribe to the changes for a particular framework and later get the changes as and when it is published. The reactive stream APIs defines four major interfaces.

public interface Publisher
{
    public void subscribe(Subscriber s);
}

The Publisher interface provides a method to subscribe to the data. It takes the Subscriber object as input and understands what data to fetch.

The second interface is the Subscriber interface which allows the frontend to subscribe to the publisher. The interface has the below shown signature.

public interface Subscriber
{
    public void onSubscribe(Subscription s);
    public void onNext(T t);
    public void onError(Throwable t);
    public void onComplete();
}

The application on subscribing to an object state gets a subscription object. Subscription objects are all implementations of the Subscription interface. The subscription interface is similar to the one shown below:

public interface Subscription
{
    public void request(long n);
    public void cancel();
}

The final interface is the interface that clubs all these interfaces together. The processing interface called the Processor. It looks like the one shown below

public interface Processor extends Subscriber, Publisher
{
}

3. Spring Webflux

Finally, coming to Spring Webflux. Spring Webflux is the reactive implementation in Spring Web MVC framework. It allows to make the calls asynchronous using the interfaces discussed above. Let us now understand Spring webflux with some practical example. To start with Spring Webflux, create a Spring Project with guidelines provided in this tutorial. Once you have the Spring MVC project running, add the below Maven dependency to the Spring MVC project.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
    <version>2.0.3.RELEASE</version>
</dependency>

This will add Spring Webflux to your project. Now, let us understand the two major components of Spring Webflux – The Routers and Handler functions.

3.1 Handler Functions

The Handlers functions are functions that generate the response as per the requests from the Router. HandlerFunction is a functional interface for this purpose. Its code is as shown below.

@FunctionalInterface
public interface HandlerFunction {
    Mono handle(ServerRequest request);
}

The above functional interface takes a server response object as its templating class and handle the request. The handle function here provides mandates the implementation of handling the response creation. The response is normally sent in two forms. It could either be a single object which is signified by Mono or a multi-object response called the Flux. These are discussed in more detail in following sections.

Now that we have a basic understanding about the Handler, let us dive into the Router function and understand how it really functions.

3.2 Router Functions

RouterFunction, as the name suggests, takes care of routing the request to the right function. It essentially replaces the @RequestMapping annotation in the Spring MVC code. A RouterFunction functional interface provides single method named route. This method allows to route a user request to a HandlerFunction implementation. This interface has the signature as shown below.

@FunctionalInterface
public interface RouterFunction {
    Mono<HandlerFunction> route(ServerRequest request);
    // ...
}

As a best practice, we do not always continue implementing the interface repeatedly. Instead, Spring Webflux provides a helper implementation called RouterFunctions.route() with the signature as shown below.

public static  RouterFunction route(
  RequestPredicate predicate,
  HandlerFunction handlerFunction)

3.3 Publisher Types

There are two major types of publishers being used by Spring Webflux. It utilises the publishers to publish the data as per the request. The publishers are:

3.3.1 Mono Publisher

Mono mono = Mono.just(new Object());
Mono mono = Mono.empty();

A mono publisher is shown above. A mono publisher is used to publish either a single object or an empty object to the subscribers. This is useful for services that try to get the data for a specific ID. A mono publisher has a templated interface that allows you to pass any desired type of object and publish it. Mono is essentially a functional interface with a single method that takes an object as an input.

3.3.2 Flux Publisher

Flux flux = Flux.just(new Object(), new Object(), new Object());
Flux flux = Flux.fromArray(new Object[]{new Object(), new Object(), new Object()});
//Subscribing to flux 
flux.subscribe();

A flux publisher is used to publish a list of objects at the same time. The code level implementation of flux is shown above. The functions are quite similar to the Mono publisher we saw above. Flux is also a templated interface just like Mono.

4. Spring Webflux Example

Now we have the basic idea about webflux interfaces and implementation, let us proceed with an example of Spring Webflux. To begin with, modify your dependency file as shown below.

4.1 Configuring Spring Boot Reactive Application

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
 
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.1.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
 
    <groupId>com.javacodegeeks</groupId>
    <artifactId>spring-functional-programming-example</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
 
    <name>spring-functional-programming-example</name>
    <url>http://maven.apache.org</url>
 
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>
 
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-test</artifactId>
            <scope>test</scope>
        </dependency>
 
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
 
</project>

Notice here that we are using Spring Boot as the base to get all the relevant dependencies for MVC and Webflux in place with a single dependency. For the Webflux dependencies, we directly chose the Spring webflux artifact which downloads the required dependencies.

The next step is to create a configuration file for Spring Boot with Webflux enabled in it. To do so, create the below file

SpringWebFluxConfig.java

package com.javacodegeeks.demo.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.config.EnableWebFlux;
import org.springframework.web.reactive.config.WebFluxConfigurer;

@Configuration
@EnableWebFlux
public class SpringWebFluxConfig implements WebFluxConfigurer
{  
}

The above file contains the required annotations to auto configure Spring Webflux for the project. This is the major benefit of using Spring boot as the base. It prevents any need for additional configurations whatsoever. Note here that we are using MongoDB database for the data exchange and the project as a whole. Let us now configure MongoDB for reactive data exchange. This is done as shown below.

DatabaseConfig.java

package com.javacodegeeks.demo.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.config.AbstractReactiveMongoConfiguration;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
import org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories;
 
import com.mongodb.reactivestreams.client.MongoClient;
import com.mongodb.reactivestreams.client.MongoClients;
 
@Configuration
@EnableReactiveMongoRepositories(basePackages = "com.javacodegeeks.demo.dao")
public class DatabaseConfig extends AbstractReactiveMongoConfiguration
{  
    @Value("${port}")
    private String port;
     
    @Value("${dbname}")
    private String dbName;
 
    @Override
    public MongoClient reactiveMongoClient() {
        return MongoClients.create();
    }
 
    @Override
    protected String getDatabaseName() {
        return dbName;
    }
 
    @Bean
    public ReactiveMongoTemplate reactiveMongoTemplate() {
        return new ReactiveMongoTemplate(reactiveMongoClient(), getDatabaseName());
    }
}

There are a bunch of things that we need to note in the above file. Let us start from the beginning of the file. The first annotation @Configuration indicates that the class provides configuration for the Spring boot application. The next annotation @EnableReactiveMongoRepositories hints at enabling reactive repositories features for the MongoDB. Notice here that the Abstract class to enable reactive programming is available only for MongoDB out of the box. For the relational databases, we would require custom drivers to enable reactive programming. Thus, we configure and enable reactive repositories for the application by passing in the base package location of the DAO objects.

Further, it proceed with a few properties declaration to enable connecting of the database with the application. This includes configuration port and the database name. Rest of the code contains a getter for the database name, an overriding function to get the database client and a Mongo templating bean which provides reactive database template for transaction.

Finally, we can configure the application class that would configure the Spring boot application properties. The code for the class is as provided below.

ApplicationConfig.java

package com.javacodegeeks.demo.config;

import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
 
@Configuration
public class ApplicationConfig
{
    @Bean
    public static PropertyPlaceholderConfigurer getPropertyPlaceholderConfigurer()
    {
        PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
        ppc.setLocation(new ClassPathResource("application.properties"));
        ppc.setIgnoreUnresolvablePlaceholders(true);
        return ppc;
    }
}

The annotations above are pretty much the same as the ones using in the previous class. This class loads the application properties file which contains the required configuration parameters used in the previous class. This properties file looks like the one shown below

application.properties

port=27017
dbname=reactivetutorial

You need to make sure that you have this database created and ready for use. You can certainly use a different database if you want to. All you need to do is change the database name in the above file.

Now, let us create the final application file containing the main function to kick off the Spring boot application. Create the file as shown below:

SpringWebfluxTutorial.java

package com.javacodegeeks.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
 
@SpringBootApplication
public class SpringWebfluxTutorial {
 
    public static void main(String[] args) {
        SpringApplication.run(SpringWebfluxTutorial.class, args);
    }
}

This is the class that will take care of starting Spring Boot application and loading all the dependencies into the memory. Finally, we have our skeleton of code ready to add some controllers, service layers and DAO layers to practically understand reactive programming. Before we get into that, let us do something really important.

For a better understanding of the application, let us configure logging into the application using the Logback dependency.

logback.xml

<configuration>
 
    <appender name="STDOUT"
        class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{5} - %msg%n
            </pattern>
        </encoder>
    </appender>
 
    <logger name="org.springframework" level="DEBUG"
        additivity="false">
        <appender-ref ref="STDOUT" />
    </logger>
 
    <root level="ERROR">
        <appender-ref ref="STDOUT" />
    </root>
 
</configuration>

The logback library is already included as a dependency for our Spring boot application. This configuration would provide us the basic logs for the application initialisation. Let us now run the application and see what the configuration did for us.

You would see a bunch of logs mentioning that some classes were not found and the matching failed. These logs are indicating what Spring Boot does in the background for auto configuration.

4.2 Creating Repository Layers and Controllers

Now, let us proceed with the implementation of controller and service layers. Create the below files.

EmployeeController.java

package com.javacodegeeks.demo.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
 
import com.javacodegeeks.demo.model.Employee;
import com.javacodegeeks.demo.service.EmployeeService;
 
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
 
@RestController
public class EmployeeController {
    @Autowired
    private EmployeeService employeeService;
 
    @RequestMapping(value = { "/create", "/" }, method = RequestMethod.POST)
    @ResponseStatus(HttpStatus.CREATED)
    @ResponseBody
    public void create(@RequestBody Employee e) {
        employeeService.create(e);
    }
 
    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    @ResponseBody
    public ResponseEntity<Mono> findById(@PathVariable("id") Integer id) {
        Mono e = employeeService.findById(id);
        HttpStatus status = e != null ? HttpStatus.OK : HttpStatus.NOT_FOUND;
        return new ResponseEntity<Mono>(e, status);
    }
 
    @RequestMapping(value = "/name/{name}", method = RequestMethod.GET)
    @ResponseBody
    public Flux findByName(@PathVariable("name") String name) {
        return employeeService.findByName(name);
    }
 
    @RequestMapping(method = RequestMethod.GET, produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    @ResponseBody
    public Flux findAll() {
        Flux emps = employeeService.findAll();
        return emps;
    }
 
    @RequestMapping(value = "/update", method = RequestMethod.PUT)
    @ResponseStatus(HttpStatus.OK)
    public Mono update(@RequestBody Employee e) {
        return employeeService.update(e);
    }
 
    @RequestMapping(value = "/delete/{id}", method = RequestMethod.DELETE)
    @ResponseStatus(HttpStatus.OK)
    public void delete(@PathVariable("id") Integer id) {
        employeeService.delete(id).subscribe();
    }
 
}

The above file is the REST controllers that provides the required APIs for the Employee CRUD. Next, let us create the object that is required in the above controller

Employee.java

package com.javacodegeeks.demo.model;

import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
 
@Scope(scopeName = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
@Document
public class Employee {
 
    @Id
    int id;
    String name;
    long salary;
 
    //Getters and setters
 
    @Override
    public String toString() {
        return "Employee [id=" + id + ", name=" + name + ", salary=" + salary + "]";
    }
}

The above model contains two attributes related to employee. This is kept simpler to avoid any complexity in the tutorial.

IEmployeeService.java

package com.javacodegeeks.demo.service;

import com.javacodegeeks.demo.model.Employee;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
 
public interface IEmployeeService
{
    void create(Employee e);
     
    Mono findById(Integer id);
 
    Flux findByName(String name);
 
    Flux findAll();
 
    Mono update(Employee e);
 
    Mono delete(Integer id);
}

EmployeeService.java

package com.javacodegeeks.demo.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
 
import com.javacodegeeks.demo.dao.EmployeeRepository;
import com.javacodegeeks.demo.model.Employee;
 
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
 
@Service
public class EmployeeService implements IEmployeeService {
     
    @Autowired
    EmployeeRepository employeeRepo;
 
    public void create(Employee e) {
        employeeRepo.save(e).subscribe();
    }
 
    public Mono findById(Integer id) {
        return employeeRepo.findById(id);
    }
 
    public Flux findByName(String name) {
        return employeeRepo.findByName(name);
    }
 
    public Flux findAll() {
        return employeeRepo.findAll();
    }
 
    public Mono update(Employee e) {
        return employeeRepo.save(e);
    }
 
    public Mono delete(Integer id) {
        return employeeRepo.deleteById(id);
    }
 
}

The above two files create the interface for the Employee CRUD services and implement the functionality using a Service implementation class

EmployeeRepository.java

package com.javacodegeeks.demo.dao;

import org.springframework.data.mongodb.repository.Query;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;

import com.javacodegeeks.demo.model.Employee;

import reactor.core.publisher.Flux;
 
public interface EmployeeRepository extends ReactiveMongoRepository {
    @Query("{ 'name': ?0 }")
    Flux findByName(final String name);
}

Finally, the above class is the DAO layer that inherits most of the data transaction function and provides one function implementation to pass a query parameter to the function. You created the below list of files above:

  • Rest Controller
  • Model Object
  • Service layer
  • DAO (repository) layer

These files altogether provide REST service to perform CRUD operations for employees. To test this, let us execute the project. Once the project runs, you can test the APIs just like normal CRUD operations using Postman.

5. Download the Source Code

You can download the project for the Spring MVC Functional Programming Example from the link below.

Download
You can download the full source code of this example here: Spring MVC Functional Programming Example

Abhishek Kothari

Abhishek is a Web Developer with diverse skills across multiple Web development technologies. During his professional career, he has worked on numerous enterprise level applications and understood the technological architecture and complexities involved in making an exceptional project. His passion to share knowledge among the community through various mediums has led him towards being a Professional Online Trainer, Youtuber as well as Technical Content Writer.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button