Introduction

Ladies and gentlemen, let’s move on from our previous example, AngularJS application with Spring MVC Rest server. Today, we will modify an existing application to support both database data sources, as well as a new one: a MongoDB data source.

The goal

The goal is to build the exact same screens as in our base example, with the only difference being that on each page, at the page header, we will have drop down menu, where we can switch between two data sources: Database / MongoDB, and the second difference is that initially, on page load we will have ‘Mode choose’ screen, where we initially pick the one of the 2 modes. All the other screens are exactly the same as in the previous base application. The mode selection screen looks like the one below:
select_mode

Client side

As in our previous application, we have very similar screens structure. As noted before our app.js file is our configuration application file.  It looks like this in the new version:
var usersModule = angular.module("usersApp", ["ngRoute", "ngResource",
    "usersApp.controllers", "usersApp.services", "usersApp.constants"]);
usersModule.config(function ($routeProvider, $httpProvider) {
    $httpProvider.defaults.useXDomain = true;
    delete $httpProvider.defaults.headers.common['X-Requested-With'];

    $routeProvider.when('/modes', {
        templateUrl: 'res/partials/modes.html',
        controller: 'ModesController'
    }).when('/users', {
        templateUrl: 'res/partials/users.html',
        controller: 'UsersController'
    }).when('/users/new', {
        templateUrl: 'res/partials/new_user.html',
        controller: 'NewUserController'
    }).when('/users/:userId', {
        templateUrl: 'res/partials/user.html',
        controller: 'UserController'
    }).when('/mongo/users', {
        templateUrl: 'res/partials/mongo/users.html',
        controller: 'MongoUsersController'
    }).when('/mongo/users/new', {
        templateUrl: 'res/partials/mongo/new_user.html',
        controller: 'MongoNewUserController'
    }).when('/mongo/users/:userId', {
        templateUrl: 'res/partials/mongo/user.html',
        controller: 'MongoUserController'
    }).otherwise({
        redirectTo: '/modes'
    });
});
usersModule.run(function ($rootScope, $location) {
    $rootScope.title = 'Application modes';
    $rootScope.modes = [{
        label: "Database",
        href: "users"
    }, {
        label: "MongoDB",
        href: "mongo/users"
    }];
    $rootScope.showUsers = function (mode) {
        if (mode) {
            $location.path(mode.href);
        }
    };
});</pre>
<pre>
We can see that, on page load, page will be redirected to the url:
…/index.html#/modes

…due to the fact that $httpProvider is provided to modify address line to #/modes initially, on page load. This path is configured to be handled by this code area, taken from below snippet:$routeProvider.when(‘/modes’, { templateUrl : ‘res/partials/modes.html’, controller : ‘ModesController’ })

This basically says that once browser address URL changes to #/modes, there will be an AJAX call fired to change main application view container  (DIV with attribute data-ng-view=””) content with the one coming fromres/partials/modes.html. Once new markup is injected into shell page container, ModesController Angular component is in charge of taking care of getting data for it, and handles user interaction with UI elements inside that area (DIV). As compared with the previous application, the new one has additional URLs. Let’s show all of them:

  • …index.html#/modes – choose application mode (Database vs MongoDB)
  • ..index.html#/users – show all the users coming from Database data storage
  • ..index.html#/users/:userId – display user detail from user coming from Database data storage
  • ..index.html#/users/new – display new user form to save against Database data storage
  • ..index.html#/mongo/users – show all the users coming from MongoDB data storage
  • ..index.html#/mongo/users/:userId – display user detail from user coming from MongoDB data storage
  • ..index.html#/mongo/users/new – display new user form to save against MongoDB data storage

For each of those paths, we have configured templateUrl and controller. This is standard way to configure mapping of URL paths to templates and Angular controllers. Once we have configured those, we’re calling run() method of our main application module: usersModule. This method is called only once. For those coming from Java world, this can be compared to public static void main() method. Here we’re setting $rootScope.modes array, which is bound to HTML select element on main, shell page: index.html. This select element is above that changeable part of page. So, any dynamic view that is displayed also has drop-down with modes inside, so that we can change to other view on any application page.  There’s nothing very special here.

We added a few AngularJS controller components that will handle newly created views. Basically, each template will have it’s own controller. Additionally, we added services that will get data from the new MongoDB data source. We can compare the services.js file in new application version to the previous application services.js file. Basically, there’s nothing special there – perhaps only the fact that, for MongoDB data, we’re calling rest server PATH “/mongo/users” compared to “/users” when getting users from Database data storage.

Server side

We haven’t modified any code part related to Spring MVC controller providing Database users to our AngularJS client. We introduced new controller. We created UsersMongoController, which handles server side of REST communication with AngularJS client. Controller methods are producing JSON output, since they’re annotated with @ResponseBody. Due to the fact that method is configured in such a way, as well as having produces attribute in @RequestMapping annotation that has ‘application/json’ value, we just need to add the following dependency to pom.xml of our RestAPI project, in order to have complete support for JSON output of Controller methods:
</div>
<pre>&lt;dependency&gt;
    &lt;groupId&gt;org.codehaus.jackson&lt;/groupId&gt;
    &lt;artifactId&gt;jackson-mapper-asl&lt;/artifactId&gt;
    &lt;version&gt;1.9.13&lt;/version&gt;
&lt;/dependency&gt;</pre>
Controller code:
</pre>
<pre>package rs.odalinho.demo.beans.controllers.mongo.controllers;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import rs.odalinho.demo.beans.controllers.mongo.model.User;
import rs.odalinho.demo.beans.controllers.mongo.services.MongoUsersService;

import java.util.List;

/**
 * Handles requests for the application home page.
 */
@RequestMapping("/mongo/users")
@Controller
public class UsersMongoController {
    @Autowired
    private MongoUsersService usersService;

    @RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    public @ResponseBody User getUserById(@PathVariable Integer id) {
        return usersService.getById(id);
    }

    @RequestMapping(value = "", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    public @ResponseBody List&lt;User&gt; getAll() {
        return usersService.getAll();
    }

    @ResponseStatus(HttpStatus.CREATED)
    @RequestMapping(method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
    public @ResponseBody User create(@RequestBody User user) {
        return usersService.createNewUser(user);
    }

    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE, produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void delete(@PathVariable Integer id) {
        usersService.delete(id);
    }

    @RequestMapping(value = "/{id}", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_VALUE, 
            consumes = MediaType.APPLICATION_JSON_VALUE)
    public @ResponseBody User update(@RequestBody User user) {
        return usersService.update(user);
    }
}
We can see that this controller is registered to react upon any http request requiring paths like “/mongo/users” (you can see @RequestMapping defined at controller level). This controller has autowired MongoUsersService which has autowired MongoUsersRepository. This MongoUsersRepository is interesting one:
</pre>
<pre>package rs.odalinho.demo.beans.controllers.mongo.repo;

import org.springframework.data.mongodb.repository.MongoRepository;
import rs.odalinho.demo.beans.controllers.mongo.model.User;

public interface MongoUsersRepository extends MongoRepository&lt;User, Integer&gt; {
    User findById(Integer id);
}
It extends MongoRepository coming from spring-data-mongodb maven dependency we have listed in pom.xml spring-mvc project file. This MongoUsersRepository is configured to support mongo User object, via:public interface MongoUsersRepository extends MongoRepository<User, Integer>User object is mapped to users mongo collection, via @Document spring-data-mongodb annotation.
MongoUserRepository has  generic methods for getting all documents from collection, for example, fetching a particular one, removing it from the collection, updating existing documents…
MongoRepository is typed interface, and we configure it with User, which tells it what is the class of object to populate once it queries mongo database. User class has the same fields (objectId, id, name, surname, country) as mongo db documents (we can see that on the screenshot showing Robomongo tool). If mongodb document field has different name to the Java class property, we can annotate Java property with @Field(value = “<mongo_db_column_name_here>”). MongoDB has really fantastic documentation, which you can look at in more depth by visiting their website. MongoDB installation is pretty trivial, and all the required steps are well documented. Here’s User.java model class code:
</pre>
</div>
<pre>package rs.odalinho.demo.beans.controllers.mongo.model;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

@Document(collection = "users")
public class User {
    @Id
    private String objectId;
    private Long id;
    private String name;
    private String surname;
    private String country;

    public User(String id, String name, String country) {
        this.setObjectId(id);
        this.name = name;
        this.country = country;
    }

    public User() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

    public String getSurname() {
        return surname;
    }

    public void setSurname(String surname) {
        this.surname = surname;
    }

    public String getObjectId() {
        return objectId;
    }

    public void setObjectId(String objectId) {
        this.objectId = objectId;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
}</pre>
<pre>

Mongo Spring XML configuration

Spring MVC main configuration file is: servlet-context.xml. In there, we import other XML spring config file, via:<beans:import resource=”spring-mongo.xml” />In spring-mongo.xml, there’s a complete mongo datasource configuration. There’s many examples on how to configure mongo part in spring config files.
You can use command line tool while playing in mongo. Also, I found Robomongo tool very useful.
robomongo
In this demo, we’re using users database, with users collection (that is configured in spring mongo xml config file.
You can find project code attached here: download