Pulling DB data

In the Setting up a connection in Java section, we set up a connection to the ecomp_sdk database. Now, we going to use our AngularJS controller (controller.js) and data service (data-service.js) to make an HTTP request to our Spring controller (MyAppController.java), wait for the results, and map them into a Google Chart.

AngularJS Promises

“Promises” are a core feature of AngularJS, and whether you fully understand them or not, you will be using them in your applications. Promises use AJAX (Asynchronous JavaScript and XML – you can also use JSON). When we make a call to a web server for some data, we don’t want our application to become unresponsive while we wait for an answer. Therefore, $http.get calls (more in a minute), return a Promise object rather than text from the web server. Then, we make sure that the Promise object does the right thing at the right time by assigning callback functions when the web server either returns results or fails to return a result. Something like this:

var p = $http.get("http://somedomain.com/some_request");

p.success(function(result) {
  console.log("The web server returned: " + result);
});

p.error(function(response, status) {
  console.log("The web server returned:\n\tStatus: " + status + "\n\tError: " + response);
});

Here, AJAX (via the AngularJS module $http) makes a request to somedomain.com/some_request. Our JavaScript engine immediately then moves to assign anonymous functions as callbacks for success and error conditions. Then, when the web server finally returns a result, the callbacks are run.

Data service

Our special function in data-service.js uses Promises. We make sure to execute code in the correct order by using the then Promise function.

Something like this:

$scope.myFunction = function() {
  dataService.getSomeData().then(function(rv) {
    // Do something here.
  });
}

Here, getSomeData returns a Promise object. The then function tells the JavaScript engine to execute the given anonymous function only after the request has completed.

Technically, the then function takes two functions as arguments. The first defines what to do upon success, and the second defines what to do upon failure. We omitted the failure argument above.

Here is our data-service.js code:

appDS2.factory('dataService', function ($http, $q, $log) {
  return {
    // Service to return chart data
    getChartData: function(direction) {
      return $http.get("get_chart_data/" + direction + "/").then(function(response) {
        if (typeof response.data === 'object' || typeof response.data === 'string') {
          return response.data;
        }
        else {
          return $q.reject(response.data);
        }
      }, function(response) {
        return $q.reject(response.data);
      })
    }
  };
});

The syntax of this function is not immediately obvious unless you are comfortable with JavaScript Promises and Deferreds. For a more complete explanation with examples, check out this blog post.

Essentially, our service definition is a super-concise JavaScript way to allow this from within our controller:

dataService.getChartData(direction).then(function(rv) {
  // Do something here
});

Behind the scenes, this makes an HTTP request that looks like this:

http://localhost:8080/epsdk-app-os/get_chart_data/<direction>/

where direction is either “upload” or “download” and returns the result back to our controller as JSON text, which we’ll convert into a JavaScript object for further processing.

Modifying our Spring controller

Let’s add a couple of functions to our Spring controller, MyAppController.java:

@RequestMapping(value = {"/get_chart_data/{direction}/"}, method = RequestMethod.GET)
public void getChartData(@PathVariable("direction") String direction, HttpServletRequest request, HttpServletResponse response){
  try {
    Object a = _getChartData(direction);
    response.getWriter().write(a.toString());
  } catch (IOException e) {
    // Probably should do something here ;-)
  }
}

private Object _getChartData(String direction) {
  ArrayList<JSONObject> allData = new ArrayList<JSONObject>();
  JdbcTemplate jdbcTempl = new JdbcTemplate(m_dataSources.get("myappdb"));

  // Check our parameter
  if (!direction.equals("download") && !direction.equals("upload"))
    direction = "download";
  }

  String query = "select data_date, speedmbps, direction from mock_data_avg_speed where direction='" + direction + "' order by data_date asc";

  List<Map<String,Object>> out = jdbcTempl.queryForList(query);
  for (Map<String,Object> row: out) {
    JSONObject jo = new JSONObject();
    jo.put("data_date", row.get("data_date"));
    jo.put("speedmbps", row.get("speedmbps"));
    jo.put("direction", row.get("direction"));
    allData.add(jo);
  }

  return allData;
}

Testing our changes

To test our database connection, first compile and install the war as in the Installing your app section. Next, login. Now try the following URL:

http://localhost:8080/epsdk-app-os/get_chart_data/download/

Note

Using the trailing ‘/’ character can prevent confusion with AngularJS routing. It might not always be necessary, but it is good practice to use it in this context to prevent headaches later on.

If everything went as planned, you should see:

[{"speedmbps":40,"data_date":"2017-08-01","direction":"download"}, {"speedmbps":18,"data_date":"2017-08-02","direction":"download"}, {"speedmbps":25,"data_date":"2017-08-03","direction":"download"}, {"speedmbps":48,"data_date":"2017-08-04","direction":"download"}, {"speedmbps":49,"data_date":"2017-08-05","direction":"download"}, {"speedmbps":46,"data_date":"2017-08-06","direction":"download"}, {"speedmbps":35,"data_date":"2017-08-07","direction":"download"}]

This is what makes JSON such a powerful tool. We’ll take that JSON output and convert it into JavaScript objects in order to build our chart.