navigation

Real Time Reporting with Highcharts, AngularJS and Spring Boot

Real Time Reporting with Highcharts, AngularJS and Spring Boot

by
December 8, 2016

The intention of the article is to show you the capabilities of the chosen software technology stack when developing a real time reporting application. The term “Real Time Reporting” used in the header of this paper refers to activity of dynamically populating chart from Highcharts with data retrieved from a REST Controller provided by Spring Boot. AngularJS will help us easily accomplish this functionality through dependency injection and built-in services.

How to Complete this Guide

You can start from scratch and create the described classes and resources independently or you can clone the project with:

Let’s begin!

Building the Back-end of the Real Time Reporting

The easiest way to create Spring Boot project is to go to http://start.spring.io/ and generate one. For the scope of this project you must include web and web-services as dependencies.

When you have finished and downloaded the generated .zip file import the project in your favourite IDE as a Maven project.

Once you have imported the project let’s continue with the implementation of the back-end part and more specifically the Data Transfer Object and REST Controller.

Our REST Controller will handle GET request at /real-time-data/data URL and will return 200 OK response with JSON in the body that represents DTO object used later in the chart visualisation. The response looks like this :

{

"xAxis": 1480352400568,

"yAxis": 18

}

The xAxis field represents long value from which we will create Javascript Date object later. The yAxis contains value which will be set as relevant chart axis member.

Create the following Data Transfer Object class:

src/main/java/eu/dreamix/dto/ChartDataDTO.java

 


package eu.dreamix.dto;

/**
* Data transfer object which holds values transferred to the chart
* @author Boyko Dimitrov on 11/28/16.
*/
public class ChartDataDTO {

   private Long xAxis;
   private Integer yAxis;

   public ChartDataDTO(Long xAxis, Integer yAxis) {
       this.xAxis = xAxis;
       this.yAxis = yAxis;
   }

   public Long getxAxis() {
       return xAxis;
   }

   public Integer getyAxis() {
       return yAxis;
   }
}

For the purpose of the paper we will generate random data and populate DTO object which will be returned from the REST Controller.

Create the following REST Controller class:

src/main/java/eu/dreamix/RealTimeDataResource.java

 


package eu.dreamix.rest;

import eu.dreamix.dto.ChartDataDTO;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.Random;

/**
* REST Controller which retrieves data used in the chart.
* @author Boyko Dimitrov on 11/28/16.
*/
@RestController
@RequestMapping("/real-time-data")
public class RealTimeDataResource {

   @RequestMapping(value = "/data", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
   public ResponseEntity<Object> getData() {
       return ResponseEntity.ok(new ChartDataDTO(System.currentTimeMillis(), new Random().nextInt(100)));
   }
}

Run the application and go see the result at http://localhost:8080/real-time-data/data

Building the Front-end of The Real Time Reporting tool

Now when we have the data, we need to visualize it.

Create the following file:

src/main/resources/static/index.html

 

<html lang="en" ng-app="RealTimeReporting">
<head>
   <meta charset="UTF-8">
   <title>Title</title>
   <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
   <script src="https://code.highcharts.com/highcharts.js"></script>
   <script src="/app.js"></script>
   <script src="/rest.service.js"></script>
   <script src="/chart.service.js"></script>
</head>
<body>

<div ng-controller="RealTimeReportingController">

<div id="realTimeDataBarChart"></div>

  </div>

</body>
</html>

The ng-app attribute is called directive and tells AngularJS that this is the root element of the AngularJS application. The ng-controller directive adds a controller to your application.

In the controller you can write functions and variables, which will be parts of an object, available inside the current HTML element. For more information about these components, check https://angularjs.org/

The AngularJS application is defined in app.js and contains the RealTimeReportingController definition.(It is a good practice to separate the controller logic from the application definition, but since our application has demo purpose we can keep it that way)

The rest.service.js holds the mechanism of calling the previously created Spring Boot REST Controller.

The chart.service.js is responsible for drawing the chart into the div with id realTimeDataBarChart

Create the app.js

src/main/resources/static/app.js

 


(function() {
   'use strict';

   var app = angular.module('RealTimeReporting', []);

   app.controller('RealTimeReportingController', RealTimeReportingController);

   RealTimeReportingController.$inject = [ 'RealTimeReportingChartService' ];

   function RealTimeReportingController(RealTimeReportingChartService) {
       RealTimeReportingChartService.populateStackedBarChart();
   }

})();

Here you can see that our AngularJS application defines the RealTimeReportingController which injects another component from the application – RealTimeReportingChartService(in this case we keep the best practice of separating the components :). RealTimeReportingChartService has only one method which as I wrote is responsible for the drawing of the chart.

src/main/resources/static/chart.service.js

 

(function() {
'use strict';

angular.module('RealTimeReporting').factory('RealTimeReportingChartService',
RealTimeReportingChartService);

RealTimeReportingChartService.$inject = [ 'RealTimeDataResource' ];

function RealTimeReportingChartService(RealTimeDataResource) {
var service = {};

service.populateStackedBarChart = function() {
var chart = new Highcharts.Chart({
chart: {
type: 'column',
renderTo : 'realTimeDataBarChart',
events : {
load : function() {
setInterval(function() {
var firstSeries = chart.series[0];
var secondSeries = chart.series[1];
var categories = chart.xAxis[0].categories;
var categoriesLength = categories.length;
var yAxisValue;

RealTimeDataResource.getData().then(function(response) {
var data = response.data;
yAxisValue = data.yAxis;

firstSeries.addPoint([categoriesLength, yAxisValue], false, true);
secondSeries.addPoint([categoriesLength, yAxisValue + 10], false, true);

var dateNow = new Date(data.xAxis);

categories.push(dateNow.getHours() + ':'
+ (dateNow.getMinutes() &lt;= 9 ? '0' +dateNow.getMinutes() : dateNow.getMinutes())
+ ':' +dateNow.getSeconds());
chart.xAxis[0].setCategories(categories, false);

chart.redraw();
});

}, 5000);
}
}
},
title: {
text : 'Real Time Data'
},
xAxis: {
categories: ['11:33:40', '11:33:41', '11:33:42', '11:33:43', '11:33:44',
'11:33:45', '11:33:46', '11:33:47', '11:33:48', '11:33:49'],
},
yAxis : {
title : {
text : 'Requests per 5 seconds',
},
},
plotOptions: {
column: {
stacking: 'normal',
}
},
series: [{
data: [29, 71, 116, 60, 44, 17, 38, 51, 66, 100]
}, {
data: [15, 29, 21, 11, 33, 56, 12, 44, 89, 22]
}]
})
}

return service;
}
})();

The definition of the RealTimeReportingChartService again has $inject service. This time the component includes as dependency RealTimeDataResource which calls the REST controller and retrieves the ChartDataDTO object. The setInterval function in the Highcharts load event will execute every 5 seconds REST call using the included RealTimeDataResource. The xAxis value from the DTO object is converted to javascript Date object and added as category in the categories array. Since we are implementing Stacked Bar Chart, we have two series arrays to which we are adding the xAxis value from the DTO for the first serie and for the second one we just increase the value with 10(Don’t judge me this is only a demo :) The rest of the code is just a standart Highchart template with hardcoded values which can be found on http://www.highcharts.com/demo

The last AngularJS component which we need to build is the service responsible for the REST call to the back end. It is pretty simple and the only thing I will mention here is the AngularJS service $http. It is a core Angular service that facilitates communication with the remote HTTP servers via the browser’s XMLHttpRequest object or via JSONP.

src/main/resources/static/rest.service.js

 

(function() {
   'use strict'

   var app = angular.module("RealTimeReporting");

   app.factory("RealTimeDataResource", RealTimeDataResource);

   RealTimeDataResource.$inject = ['$http'];

   function RealTimeDataResource($http) {

       var service = {};

       service.getData = function() {
           return $http({
               method : 'GET',
               url : '/real-time-data/data'
           });
       }

       return service;
   }

})();

Well, run the application and see how the bars are stacking every 5 seconds. Thank you for your time and don’t hesitate to ask questions, give me feedback or share your real time reporting application. 

Boyko Dimitrov

Java Developer at Dreamix

More Posts - Website

Follow Me:
TwitterLinkedInGoogle Plus

Do you want more great blogs like this?

Subscribe for Dreamix Blog now!