{{announcement.body}}
{{announcement.title}}

Tutorial: Reactive Spring Boot, Part 6: Displaying Reactive Data

DZone 's Guide to

Tutorial: Reactive Spring Boot, Part 6: Displaying Reactive Data

Learn more about displaying reactive data within your reactive Spring Boot apps.

· Java Zone ·
Free Resource

coffee cup next to laptop with code on screen

Learn more about displaying reactive data within your reactive Spring Boot apps.

This is the sixth part of our tutorial showing how to build a reactive application using Spring Boot, Kotlin, Java, and JavaFX. The original inspiration was a 70-minute live demo.

Here is everything you've missed so far:

Tutorial: Reactive Spring Boot, Part 1: Building a Kotlin REST Service

Tutorial: Reactive Spring Boot, Part 2: A REST Client for Reactive Streams

Tutorial: Reactive Spring Boot, Part 3: A JavaFX Spring Boot Application

Tutorial: Reactive Spring Boot, Part 4: A JavaFX Line Chart

Tutorial: Reactive Spring Boot, Part 5: Auto-Configuration for Shared Beans

In this lesson, we look at connecting our JavaFX chart to our Kotlin Spring Boot service to display real-time prices. This blog post contains a video showing the process step-by-step and a textual walk-through (adapted from the transcript of the video) for those who prefer a written format.


This tutorial is a series of steps during which we will build a full Spring Boot application featuring a Kotlin back-end, a Java client, and a JavaFX user interface.

In part four, we created a JavaFX Spring Boot application that shows an empty line chart. In the last installment (part five), we wired in a WebClientStockClient to connect to the price service. In this installment, we’re going get the line chart to show the prices coming from our Kotlin Spring Boot service in real-time.

Setting Up the Chart Data

  1. In ChartController from the stock-ui module, create an initialize method, which is called once any FXML fields have been populated. This initialize method will set up where the chart data is going to come from.
  2. Call setData on the chart and create a local variable called data for the List of Series that needs to be passed into this method.
  3. Create a Series to add to the data list and pass in seriesData.
  4. Create seriesData as a field which is an empty list, using FXCollections.observableArrayList().
public class ChartController {
    @FXML
    private LineChart<String, Double> chart;
    private WebClientStockClient webClientStockClient;
    private ObservableList<Data<String, Double>> seriesData = FXCollections.observableArrayList();

    public ChartController(WebClientStockClient webClientStockClient) {
        this.webClientStockClient = webClientStockClient;
    }

    @FXML
    public void initialize() {
        ObservableList<XYChart.Series<String, Double>> data = FXCollections.observableArrayList();
        data.add(new XYChart.Series<>(seriesData));
        chart.setData(data);
    }
}


Subscribe to the Price Data

We need to get the data for our chart from somewhere. This is what we added the webClientStockClient for.

  1. Inside the initialize method call pricesFor on webClientStockClient and pass in a symbol to get the prices for. For now, we can hard-code this value as “SYMBOL”.
  2. We need to subscribe something to the Flux that is returned from this call. The simplest thing to do here is to call subscribe and pass in this.
  3. Make the ChartController implement java.util.function.Consumer, and have it consume StockPrice.
  4. Implement the accept method from Consumer.
  5. (Tip: We can get IntelliJ IDEA to implement the methods required to fulfill this interface by pressing Alt+Enter on the red class declaration text and selecting “Implement methods“.)
public class ChartController implements Consumer<StockPrice> {

    // fields and constructor here...

    @FXML
    public void initialize() {
        ObservableList<XYChart.Series<String, Double>> data = FXCollections.observableArrayList();
        data.add(new XYChart.Series<>(seriesData));
        chart.setData(data);

        webClientStockClient.pricesFor("SYMBOL").subscribe(this);
    }

    @Override
    public void accept(StockPrice stockPrice) {

    }
}


Display the Price Data

We need to decide what to do with a StockPrice when we receive one. We need to add the right values from the stock price to the chart’s seriesData.

  1. Inside accept, call seriesData.add with a new instance of Data.
  2. For the y value of Data, we can get the time from the stock price and get the value of “second”. This is an int, and needs to be a String, so wrap it in a String.valueOf call.
  3. (Tip: We can use the postfix completion “arg” to automatically wrap an expression in a method call to simplify calling String.valueOf when we’ve already typed the expression)
  4. For the x value, we use the price value from the stock price.
public void accept(StockPrice stockPrice) {
    seriesData.add(new XYChart.Data<>(String.valueOf(stockPrice.getTime().getSecond()),
                                      stockPrice.getPrice()));
}


This seems fine as it is, but there’s another thing to consider with this programming model. Changing the series data will be reflected by an update in the user interface, which will be drawn by the UI thread. This accept method is running on a different thread, listening to events from the back-end service. So, we need to tell the UI thread to run this piece of code when it gets a chance.

  1. Call Platform.runLater, passing in a lambda expression of the code to run on the UI thread.
public void accept(StockPrice stockPrice) {
    Platform.runLater(() -> 
        seriesData.add(new XYChart.Data<>(String.valueOf(stockPrice.getTime().getSecond()),
                                          stockPrice.getPrice()))
    );
}


Running the Chart Application

  1. Make sure the back-end Kotlin Spring Boot service (StockServiceApplication) is running.
  2. Go back to the UI module and run our JavaFX application, StockUiApplication.
  3. You should see a JavaFX line chart that updates automatically from the prices (see 3:20 into the video for an example).

Displaying the Symbol Name

  1. Extract the hard-coded symbol into a local variable, we want to use it in more than one place.
  2. (Tip: We can use IntelliJ IDEA’s Extract Variable (documentation) (video overview) to easily do this)
  3. We can give the series a label by passing the symbol into the Series constructor.
public void initialize() {
    String symbol = "SYMBOL";
    ObservableList<XYChart.Series<String, Double>> data = FXCollections.observableArrayList();
    data.add(new XYChart.Series<>(symbol, seriesData));
    chart.setData(data);

    webClientStockClient.pricesFor(symbol).subscribe(this);
}


Now, when we re-run the application, we see the symbol’s name on the label for the series.

Code Tidy-Up

This code is a little bit unwieldy with all the type information, so let’s simplify. We can use Alt+Enter on many of the class names mentioned here to have IntelliJ IDEA suggest making these changes automatically.

  1. Import Series itself to remove the unnecessary XYChart prefix.
  2. Add a static import for observableArrayList, so we don’t need to repeat FXCollections everywhere.
  3. Add an import for valueOf, to make the line that sets the chart data a little shorter
  4. Import the Data class to remove another repetition of XYChart.
@Component
public class ChartController implements Consumer<StockPrice> {
    @FXML
    private LineChart<String, Double> chart;
    private WebClientStockClient webClientStockClient;
    private ObservableList<Data<String, Double>> seriesData = observableArrayList();

    public ChartController(WebClientStockClient webClientStockClient) {
        this.webClientStockClient = webClientStockClient;
    }

    @FXML
    public void initialize() {
        String symbol = "SYMBOL";
        ObservableList<Series<String, Double>> data = observableArrayList();
        data.add(new Series<>(symbol, seriesData));
        chart.setData(data);

        webClientStockClient.pricesFor(symbol).subscribe(this);
    }

    @Override
    public void accept(StockPrice stockPrice) {
        Platform.runLater(() ->
            seriesData.add(new Data<>(valueOf(stockPrice.getTime().getSecond()),
                                      stockPrice.getPrice()))
        );
    }
}


This refactoring shouldn’t have changed the behavior of the code, so when we re-run, we’ll see everything working the same way as before.

Conclusion

With these very few lines of code, we’ve created a JavaFX application that uses Spring’s WebClient to connect to a Spring Boot service, subscribes to the reactive stream of prices, and draws the prices on a line chart in real-time.

The full code is available on GitHub.

Further Reading

Streaming Live Updates From a Reactive Spring Data Repository 

Reactive REST API Using Spring Boot and RxJava

Topics:
spring boot ,java ,tutorial ,intellij idea ,reactive ,javafx ,reactive data

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}