2013-11-18

Today for my 30 day challenge, I decided to develop a single page web application using the Spring framework, MongoDB, and AngularJS. I have a good understanding of Spring and MongoDB but I have never used AngularJS with the Spring framework. So, in today's blog post we will develop a social bookmarking application like the one we developed with EmberJS a few days ago. I have already covered AngularJS basics on day 2 so please refer to my blog for more information. This blog will cover the latest version of the Spring framework i.e. 3.2.5.RELEASE and will use no XML approach(not even web.xml). We will configure everything using Spring annotation support. The Spring MVC(along with Spring framework) will be used to create the RESTful backend. AngularJS will be used as the client side MVC framework to develop the frond-end of the application.

Application Usecase

In this blog post, we will develop a social bookmarking application which allows users to post and share links. You can view the live application running on OpenShift here. The application can do the following:

When a user goes to the '/' url of the application, then the user will see a list of stories sorted in the application database. Behind the curtain, AngularJS makes a REST(/api/v1/stories) call to fetch all the stories.



When a user clicks on any story i.e. http://getbookmarks-shekhargulati.rhcloud.com/#/stories/528b9a8ce4b0da0473622359, the user can view the content of the story like who submitted the story, when the story was submitted, and an excerpt of the story. AngularJS will make a RESTful GET request(/api/v1/stories/528b9a8ce4b0da0473622359) to fetch the full story.



Finally, a user can submit a new story by navigating to http://getbookmarks-shekhargulati.rhcloud.com/#/stories/new. This will make a POST call to the RESTful backend and save the story in the MongoDB datastore. The user is only required to enter the url of the story. The application will fetch the title, main image, and excerpt of the story using Goose Extractor RESTful API developed on day 16.



Prerequisite

Basic Java knowledge is required. Install the latest Java Development Kit (JDK) on your operating system. You can either install OpenJDK 7 or Oracle JDK 7. OpenShift support OpenJDK 6 and 7.

Basic Spring Knowledge is required.

Sign up for an OpenShift Account. It is completely free and Red Hat gives every user three free Gears on which to run your applications. At the time of this writing, the combined resources allocated for each user is 1.5 GB of memory and 3 GB of disk space.

Install the rhc client tool on your machine. RHC is a ruby gem so you need to have ruby 1.8.7 or above on your machine. To install rhc, just typesudo gem install rhc
If you already have one, make sure it is the latest one. To update your rhc, execute the command shown below.sudo gem update rhc
For additional assistance setting up the rhc command-line tool, see the following page: https://openshift.redhat.com/community/developers/rhc-client-tools-install

Setup your OpenShift account using rhc setup command. This command will help you create a namespace and upload your ssh keys to OpenShift server.

Github Repository

The code for today's demo application is available on github: day22-spring-angularjs-demo-app.

Step 1 : Create a Tomcat 7 application

We will start by creating a new application with a Tomcat 7 and a MongoDB cartridge.

This will create an application container for us, called a gear, and setup all of the required SELinux policies and cgroup configuration. OpenShift will also setup a private git repository for you and clone the repository to your local system. Finally, OpenShift will propagate the DNS to outside world. The application will be accessible at http://getbookmarks-{domain-name}.rhcloud.com/. Replace the {domain-name} with your own unique OpenShift domain name (also sometimes called a namespace).

Step 2 : Delete the template code

Next we will delete the template code created by OpenShift.

Please note that we also deleted web.xml.

Step 3 : Update the pom.xml

Next, update the application pom.xml with the one shown below.

In the pom.xml shown above

We added Maven dependencies for spring-webmvc, spring-mongodb, jackson, and latest servlet api.

We updated the project to use JDK 7 instead of JDK 6.

We updated the project to use latest version of Maven war plugin and added a configuration to avoid build failure when web.xml does not exist.

After making this change, make sure to update the maven project by Right Click > Maven > Update Project.

Step 4 : Write WebMvcConfig and AppConfig class

Create a new package com.getbookmarks.config and create a new class WebMvcConfig. Update the code with the shown below. The class shown below will enable the Spring Web MVC framework.

Next we will write another configuration class AppConfig. Spring MongoDB has concept of repositories where in you implement interface and Spring will generate a proxy class with the implementation. This makes it very easy to write repository classes and removes lots of boiler plate code. The Spring MongoDB allows us to declaratively enable Mongo repositories by specifying @EnableMongoRepositories annotation.

The proxy repository classes internally use MongoTemplate to perform operations. We defined a MongoTemplate bean which uses OpenShift MongoDB credentials.

The code shown enables Spring MVC support in the application using @EnableWebMvc annotation.

Step 5: Write GetBookmarksWebApplicationInitializer class

With Servlet 3.0, the web.xml is optional. Normally, we configure Spring WebMVC dispatcher servlet in web.xml but now we can programmatically configure it using WebApplicationInitializer. From Spring 3.1, Spring provides an implementation of the ServletContainerInitializer interface called SpringServletContainerInitializer. TThe SpringServletContainerInitializer class delegates to an implementation of
org.springframework.web.WebApplicationInitializer that you provide. There is just one method that you need to implement: WebApplicationInitializer#onStartup(ServletContext). You are handed the ServletContext that you need to initialize.

Step 6 : Create Story domain class

In this application, we only have one domain class called Story.

Important things in the code snippet above are :

@Document annotation identifies a domain object to be persisted in MongoDB. The stories specify the name of collection which will be created in MongoDB.

@Id annotation marks this field as Id field which will be auto generated by MongoDB.

Step 7 : Create StoryRepository

As mentioned above, Spring MongoDB has concept of repositories wherein developer write an interface and Spring generates a proxy implementation class.Let us create the StoryRepository as shown below.

The important things in the code snippet shown above are :

StoryRepository interface extends CrudRepository interface which defines CRUD methods and finder methods. So, the proxy generated by Spring will have all those methods.

@Repository annotation is a specialization of @Component annotation which indicates that class is a repository or DAO class. A class annotated with @Repository is eligible for Spring DataAccessException translation when used in conjunction with a PersistenceExceptionTranslationPostProcessor.

Step 8 : Write StoryResource

Next, we will write the REST JSON web service for performing create and read operations on Story. To do that, we will create a Spring MVC controller with methods shown below.

Step 9 : Setup AngularJS and Twitter Bootstrap

Download the latest copy of AngularJS and Bootstrap from their respective official websites, or you can copy the resources from this project github repository.

Step 10: Create Index.html

Now we will write the view of the application.

In the html shown above

We imported all the required libraries. Our application code is in app.js.

In Angular, you define the scope of the project using ng-app directive. We used ng-app on the html element but we can use it with any other element as well. Using the ng-app directive with html element means that AngularJS is available on the whole index.html. The ng-app directive can take a name. This name is the module name. I used getbookmarks as this application module name.

The last interesting thing in the index.html is the use of ng-view directive. The ngView directive renders the template corresponding to the current route inside index.html. So, everytime you navigate to a route only the ng-view portion changes.

Step 10: Write AngularJS code

The app.js houses all the application specific JavaScript. All the application routes are defined inside it. In the code shown below, we have defined three routes and each has a corresponding Angular controller.

Step 11 : Deploy the code

Finally, commit the code and push it to application gear.

That's it for today. Keep giving feedback.

What's Next

Sign up for OpenShift Online

Get your own private Platform As a Service (PaaS) by evaluating OpenShift Enterprise

Need Help? Ask the OpenShift Community your questions in the forums

Showcase your awesome app in the OpenShift Developer Spotlight. Get in the OpenShift Application Gallery today.

Show more