Spring 4 MVC+AngularJS Routing Example using ngRoute

This post demonstrates integrating AngularJS with Spring MVC 4, focusing on routing using ngRoute module. We will discuss route configuration using $routeProvider, accessing route parameters using $routeParams, discuss route configuration details with template, templateUrl, controller, redirectTo & resolve keys. Let’s get going.


In our application, Client side is based on AngularJS, demonstrating route configuration and usage. Server side is based on Spring , serving HTML templates using velocity templates and content using Spring REST API. This is what our final Application will look like:

Spring4MVCAngularJSRoutingExample_img1
Spring4MVCAngularJSRoutingExample_img2

If you have any doubts on routing in AngularJS, please refer to AngularJS Routing Tutorial to know the in-depth details.

Let’s get started.

Following technologies being used:

  • Spring 4.2.0.RELEASE
  • AngularJS 1.4.4
  • Maven 3
  • JDK 1.7
  • Eclipse Mars.1 Release (4.5.1)

Project Structure

Spring4MVCAngularJSRoutingExample_img00
Spring4MVCAngularJSRoutingExample_img01

Provide Dependencies

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.websystique.springmvc</groupId>
	<artifactId>Spring4MVCAngularJSRoutingExample</artifactId>
	<packaging>war</packaging>
	<version>1.0.0</version>
	<name>Spring4MVCAngularJSRoutingExample Maven Webapp</name>
	<url>http://maven.apache.org</url>
	<properties>
		<springframework.version>4.2.0.RELEASE</springframework.version>
		<jackson.version>2.5.3</jackson.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${springframework.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context-support</artifactId>
			<version>${springframework.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${springframework.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.velocity</groupId>
			<artifactId>velocity</artifactId>
			<version>1.7</version>
		</dependency>

		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>${jackson.version}</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>3.1.0</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
			<version>3.4</version>
		</dependency>
	</dependencies>


	<build>
		<pluginManagement>
			<plugins>
				<plugin>
					<groupId>org.apache.maven.plugins</groupId>
					<artifactId>maven-compiler-plugin</artifactId>
					<version>3.2</version>
					<configuration>
						<source>1.7</source>
						<target>1.7</target>
					</configuration>
				</plugin>
				<plugin>
					<groupId>org.apache.maven.plugins</groupId>
					<artifactId>maven-war-plugin</artifactId>
					<version>2.4</version>
					<configuration>
						<warSourceDirectory>src/main/webapp</warSourceDirectory>
						<warName>Spring4MVCAngularJSRoutingExample</warName>
						<failOnMissingWebXml>false</failOnMissingWebXml>
					</configuration>
				</plugin>
			</plugins>
		</pluginManagement>
		<finalName>Spring4MVCAngularJSRoutingExample</finalName>
	</build>
</project>

1. Client Side

Client side of our Application is AngularJS based. If you would like to add AngularJs in your skill set, Detailed AngularJS Tutorial is available for you to deep dive in one of the most popular Javascript Meta framwework.

Route configuration:

Configure routes using AngularJS ngRoute module. Route configuration is done in AngularJS module’s config function, using $routeProvider service.
In our example, we have two types of routes : itemList routes & itemDetails routes.Both are shown below. Look specially at how the resolve is used to trigger service for communicating servers. And eventually the promise(named ‘async’ below) is passed into controllers to fetch the item lists and details. For more in depth details, please refer to AngularJS Routing Tutorial

app.js

'use strict';

var App = angular.module('myApp',['ngRoute']);

App.config(['$routeProvider', function($routeProvider) {
	$routeProvider
		.when('/items/computers', {
			templateUrl: 'items/computers',
			controller : "ItemListController as itemListCtrl",
			resolve: {
                async: ['ItemService', function(ItemService) {
                    return ItemService.fetchAllItems('computers');
               	}]
            }
		})
		.when('/items/phones', {
			templateUrl: 'items/phones',
			controller : "ItemListController as itemListCtrl",
			resolve: {
                async: ['ItemService', function(ItemService) {
                    return ItemService.fetchAllItems('phones');
               	}]
            }
		})
		.when('/items/printers', {
			templateUrl: 'items/printers',
			controller : "ItemListController as itemListCtrl",
			resolve: {
                async: ['ItemService', function(ItemService) {
                    return ItemService.fetchAllItems('printers');
               	}]
            }
		})
		.when('/items/computerdetails/:id', {
			templateUrl: 'items/computerdetails',
			controller : "ItemDetailsController as itemDetailsCtrl",
			resolve: {
                async: ['ItemService','$route', function(ItemService , $route) {
                    return ItemService.fetchSpecificItem('computers',$route.current.params.id);
               	}]
            }
		})
		.when('/items/phonedetails/:id', {
			templateUrl: 'items/phonedetails',
			controller : "ItemDetailsController as itemDetailsCtrl",
			resolve: {
                async: ['ItemService','$route', function(ItemService , $route) {
                    return ItemService.fetchSpecificItem('phones',$route.current.params.id);
               	}]
            }
		})
		.when('/items/printerdetails/:id', {
			templateUrl: 'items/printerdetails',
			controller : "ItemDetailsController as itemDetailsCtrl",
			resolve: {
                async: ['ItemService','$route', function(ItemService , $route) {
                    return ItemService.fetchSpecificItem('printers',$route.current.params.id);
               	}]
            }
		})
		
		.otherwise({redirectTo:'/items/computers'});		
}]);

Service Creation:

Configure Service which will eventually communicate with our Spring based server. For any doubts on service setup, please refer to AngularJS Services Tutorial.

ItemService.js


'use strict';

App.factory('ItemService', ['$http', '$q', function($http, $q){

	return {
		
			fetchAllItems: function(category) {
					return $http.get('http://localhost:8080/Spring4MVCAngularJSRoutingExample/item/'+category)
							.then(
									function(response){
										return response.data;
									}, 
									function(errResponse){
										console.error('Error while fetching Items');
										return $q.reject(errResponse);
									}
							);
			},
		    
			fetchSpecificItem: function(category,id) {
				return $http.get('http://localhost:8080/Spring4MVCAngularJSRoutingExample/item/'+category+'/'+id)
						.then(
								function(response){
									return response.data;
								}, 
								function(errResponse){
									console.error('Error while fetching specific Item');
									return $q.reject(errResponse);
								}
						);
			}
	};

}]);

Controller Creation:

Create controller for Item lists and details. For any doubts on service setup, please refer to AngularJS Controllers Tutorial.

Item List controller is shown below:
ItemListController.js

'use strict';

App.controller('ItemListController', ['async', function(async) {
          var self = this;
          self.items=async;
}]);

Item Details controller is shown below:
ItemDetailsController.js

'use strict';

App.controller('ItemDetailsController', ['async', function(async) {
          var self = this;
          self.item=async;
}]);

Configure Welcome Page:

Shown below is the main page, containings URL’s to routes for lists, and ng-viw component which will eventually be filled via select routes template.

index.html

<!doctype html>
<html lang="en" ng-app="myApp">
<head>

    <meta charset="utf-8">
    <title>Service App</title>
    <link rel="stylesheet" href="resources/css/bootstrap.css" />
    <link rel="stylesheet" href="resources/css/app.css" />
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular-route.js"></script>
    <script src="resources/js/app.js"></script>
    <script src="resources/js/service/ItemService.js"></script>
</head>
<body>
		
	<div class="generic-container">
		<h2>SellPoint - AngularJS Routing Application</h2>
		<div class="panel panel-default">
			<!-- Default panel contents -->
		    <div class="panel-heading"><span class="lead">All Items</span></div>
		    <div class="tablecontainer">
				<ul>
					<li><a href="#/items/computers">Computers</a></li>
					<li><a href="#/items/phones">Phones</a></li>
					<li><a href="#/items/printers">Printers</a></li>
					<li><a href="#/items/others">Others</a></li>
				</ul>
			</div>
		</div>
	</div>

	<div ng-view></div>
	

<script src="resources/js/controller/ItemListController.js"></script>
<script src="resources/js/controller/ItemDetailsController.js"></script>

</body>
</html>

This is the template for List page of specific item category:
item_computers.html

<div class="generic-container">
	<div class="panel panel-default">
		<!-- Default panel contents -->
	    <div class="panel-heading"><span class="lead">List of Computers</span></div>
	    <div class="tablecontainer">
	    	<table class="table table-hover">
	            <thead>
	                <tr>
	                    <th>ID</th>
	                    <th>Brand</th>
	                    <th>Model</th>
	                    <th>Price (EUR)</th>
	                </tr>
	            </thead>
	            <tbody>
	                <tr ng-repeat="item in itemListCtrl.items">
	                    <td>{{item.id}}</td>
	                    <td>{{item.brand}}</td>
	                    <td><a href="#/items/computerdetails/{{item.id}}">{{item.model}}</a></td>
	                    <td>{{item.price}}</td>
	                </tr>
	            </tbody>
			</table>
		</div>
	</div>
</div>

This is the template for Details page of specific item from specific item category:
item_computer_details.html

<div class="generic-container">
	<div class="panel panel-default">
		<!-- Default panel contents -->
	    <div class="panel-heading"><span class="lead">Computer Details</span></div>
	    <div class="tablecontainer">
	    	<table class="table table-hover">
				<tr>
                    <th>ID</th><td>{{itemDetailsCtrl.item.id}}</td>
                </tr>
                <tr>
                    <th>Brand</th><td>{{itemDetailsCtrl.item.brand}}</td>
                </tr>
                <tr>
                    <th>Model</th><td>{{itemDetailsCtrl.item.model}}</td>
                </tr>
                <tr>
                    <th>State</th><td>{{itemDetailsCtrl.item.state}}</td>
                </tr>
                <tr>
                    <th>Price (EUR)</th><td>{{itemDetailsCtrl.item.price}}</td>
                </tr>
                <tr>
                    <th>Processor (GHZ)</th><td>{{itemDetailsCtrl.item.processorSpeed}}</td>
                </tr>
                <tr>
                    <th>RAM (GB)</th><td>{{itemDetailsCtrl.item.ram}}</td>
                </tr>
                <tr>
                    <th>Disk Capacity</th><td>{{itemDetailsCtrl.item.diskCapacity}}</td>
				</tr>
			</table>
		</div>
	</div>
</div>

item_phones.html

<div class="generic-container">
	<div class="panel panel-default">
		<!-- Default panel contents -->
	    <div class="panel-heading"><span class="lead">List of Phones</span></div>
	    <div class="tablecontainer">
	    	<table class="table table-hover">
	            <thead>
	                <tr>
	                    <th>ID</th>
	                    <th>Brand</th>
	                    <th>Model</th>
	                    <th>Price (EUR)</th>
	                </tr>
	            </thead>
	            <tbody>
	                <tr ng-repeat="item in itemListCtrl.items">
	                    <td>{{item.id}}</td>
	                    <td>{{item.brand}}</td>
	                    <td><a href="#/items/phonedetails/{{item.id}}">{{item.model}}</a></td>
	                    <td>{{item.price}}</td>
	                </tr>
	            </tbody>
			</table>
		</div>
	</div>
</div>

item_phone_details.html

<div class="generic-container">
	<div class="panel panel-default">
		<!-- Default panel contents -->
	    <div class="panel-heading"><span class="lead">Phone Details</span></div>
	    <div class="tablecontainer">
	    	<table class="table table-hover">
				<tr>
                    <th>ID</th><td>{{itemDetailsCtrl.item.id}}</td>
                </tr>
                <tr>
                    <th>Brand</th><td>{{itemDetailsCtrl.item.brand}}</td>
                </tr>
                <tr>
                    <th>Model</th><td>{{itemDetailsCtrl.item.model}}</td>
                </tr>
                <tr>
                    <th>State</th><td>{{itemDetailsCtrl.item.state}}</td>
                </tr>
                <tr>
                    <th>Price (EUR)</th><td>{{itemDetailsCtrl.item.price}}</td>
                </tr>
                <tr>
                    <th>Size</th><td>{{itemDetailsCtrl.item.size}}</td>
                </tr>
                <tr>
                    <th>Camera (MB)</th><td>{{itemDetailsCtrl.item.camera}}</td>
                </tr>
                <tr>
                    <th>SD Card (GB)</th><td>{{itemDetailsCtrl.item.sdCard}}</td>
                </tr>
                <tr>
                    <th>Replaceable Battery</th><td>{{itemDetailsCtrl.item.replacableBattery}}</td>
				</tr>
			</table>
		</div>
	</div>
</div>

item_printers.html

<div class="generic-container">
	<div class="panel panel-default">
		<!-- Default panel contents -->
	    <div class="panel-heading"><span class="lead">List of Printers</span></div>
	    <div class="tablecontainer">
	    	<table class="table table-hover">
	            <thead>
	                <tr>
	                    <th>ID</th>
	                    <th>Brand</th>
	                    <th>Model</th>
	                    <th>Price (EUR)</th>
	                </tr>
	            </thead>
	            <tbody>
	                <tr ng-repeat="item in itemListCtrl.items">
	                    <td>{{item.id}}</td>
	                    <td>{{item.brand}}</td>
	                    <td><a href="#/items/printerdetails/{{item.id}}">{{item.model}}</a></td>
	                    <td>{{item.price}}</td>
	                </tr>
	            </tbody>
			</table>
		</div>
	</div>
</div>

item_printer_details.html

<div class="generic-container">
	<div class="panel panel-default">
		<!-- Default panel contents -->
	    <div class="panel-heading"><span class="lead">Printer Details</span></div>
	    <div class="tablecontainer">
	    	<table class="table table-hover">
				<tr>
                    <th>ID</th><td>{{itemDetailsCtrl.item.id}}</td>
                </tr>
                <tr>
                    <th>Brand</th><td>{{itemDetailsCtrl.item.brand}}</td>
                </tr>
                <tr>
                    <th>Model</th><td>{{itemDetailsCtrl.item.model}}</td>
                </tr>
                <tr>
                    <th>State</th><td>{{itemDetailsCtrl.item.state}}</td>
                </tr>
                <tr>
                    <th>Price (EUR)</th><td>{{itemDetailsCtrl.item.price}}</td>
                </tr>
                <tr>
                    <th>Technology</th><td>{{itemDetailsCtrl.item.technologie}}</td>
                </tr>
                <tr>
                    <th>Paper Format</th><td>{{itemDetailsCtrl.item.paperFormat}}</td>
                </tr>
                <tr>
                    <th>PPM</th><td>{{itemDetailsCtrl.item.pagesPerMinute}}</td>
				</tr>
			</table>
		</div>
	</div>
</div>

2. Server Side

Spring Configuration Class:

HelloWorldConfiguration.java

package com.websystique.springmvc.configuration;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.velocity.VelocityConfigurer;
import org.springframework.web.servlet.view.velocity.VelocityView;
import org.springframework.web.servlet.view.velocity.VelocityViewResolver;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.websystique.springmvc")
public class HelloWorldConfiguration extends WebMvcConfigurerAdapter{
	
	
	@Bean
	public VelocityConfigurer velocityConfig() {
	    VelocityConfigurer velocityConfigurer = new VelocityConfigurer();
	    velocityConfigurer.setResourceLoaderPath("/WEB-INF/velocity/");
	    return velocityConfigurer;
	}
	
	@Override
	public void configureViewResolvers(ViewResolverRegistry registry) {
		VelocityViewResolver viewResolver = new VelocityViewResolver();
		
		viewResolver.setViewClass(VelocityView.class);
		viewResolver.setCache(true);
		viewResolver.setPrefix("");
		viewResolver.setSuffix(".html");
		viewResolver.setExposeSpringMacroHelpers(true);

		registry.viewResolver(viewResolver);
	}

	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
	}

}

Create WelcomePage controller

IndexController.java

package com.websystique.springmvc.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping("/")
public class IndexController {//Serves main index.html

	  	@RequestMapping(method = RequestMethod.GET)
	    public String getIndexPage() {
	        return "index";
	    }
	  
	  	
}

Create Template Controller handling the requests for templates:

MainTemplateController.java

package com.websystique.springmvc.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/items")
public class MainTemplateController {
	
    @RequestMapping(value="/computers")
    public String getComputersTemplate() {
    	return "template/item_computers";	
    }

    @RequestMapping(value="/phones")
    public String getPhonesTemplate() {
    	return "template/item_phones";	
    }

    @RequestMapping(value="/printers")
    public String getPrintersTemplate() {
    	return "template/item_printers";	
    }

    @RequestMapping(value="/computerdetails")
    public String getComputerDetailsTemplate() {
    	return "template/item_computer_details";	
    }

    @RequestMapping(value="/phonedetails")
    public String getPhoneDetailsTemplate() {
    	return "template/item_phone_details";	
    }

    @RequestMapping(value="/printerdetails")
    public String getPrinterDetailsTemplate() {
    	return "template/item_printer_details";	
    }

}

Create REST Controller handling the requests for list and detail of items:

ItemController.java

package com.websystique.springmvc.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import com.websystique.springmvc.service.ItemService;

@Controller
@RequestMapping("/item")
public class ItemController {

    @Autowired
    ItemService itemService;  //Service which will do all data retrieval/manipulation work
 
	@RequestMapping(value="/computers")
    public ResponseEntity<List> listAllComputers() {
		System.out.println("*************************************ListAllComputers");
    	List items = 	itemService.findItemsByCategory("computers");
        if(items.isEmpty()){
            return new ResponseEntity<List>(HttpStatus.NO_CONTENT);//You many decide to return HttpStatus.NOT_FOUND
        }
        return new ResponseEntity<List>(items, HttpStatus.OK);
    }

	@RequestMapping(value="/computers/{id}")
    public ResponseEntity<Object> findSpecificComputer(@PathVariable("id") long id) {
		System.out.println("*************************************findSpecificComputer");
    	Object item = 	itemService.findItemById(id, "computers");
        if(item == null){
            return new ResponseEntity<Object>(HttpStatus.NO_CONTENT);//You many decide to return HttpStatus.NOT_FOUND
        }
        return new ResponseEntity<Object>(item, HttpStatus.OK);
    }

	
	@RequestMapping(value="/phones")
    public ResponseEntity<List> listAllPhones() {
		System.out.println("*************************************ListAllPhones");
    	List items = 	itemService.findItemsByCategory("phones");
        if(items.isEmpty()){
            return new ResponseEntity<List>(HttpStatus.NO_CONTENT);//You many decide to return HttpStatus.NOT_FOUND
        }
        return new ResponseEntity<List>(items, HttpStatus.OK);
    }

	@RequestMapping(value="/phones/{id}")
    public ResponseEntity<Object> findSpecificPhone(@PathVariable("id") long id) {
		System.out.println("*************************************findSpecificPhone");
    	Object item = 	itemService.findItemById(id, "phones");
        if(item == null){
            return new ResponseEntity<Object>(HttpStatus.NO_CONTENT);//You many decide to return HttpStatus.NOT_FOUND
        }
        return new ResponseEntity<Object>(item, HttpStatus.OK);
    }

	@RequestMapping(value="/printers")
    public ResponseEntity<List> listAllPrinters() {
		System.out.println("*************************************ListAllPrinters");
    	List items = 	itemService.findItemsByCategory("printers");
        if(items.isEmpty()){
            return new ResponseEntity<List>(HttpStatus.NO_CONTENT);//You many decide to return HttpStatus.NOT_FOUND
        }
        return new ResponseEntity<List>(items, HttpStatus.OK);
    }

	@RequestMapping(value="/printers/{id}")
    public ResponseEntity<Object> findSpecificPrinter(@PathVariable("id") long id) {
		System.out.println("*************************************findSpecificPrinter");
    	Object item = 	itemService.findItemById(id, "printers");
        if(item == null){
            return new ResponseEntity<Object>(HttpStatus.NO_CONTENT);//You many decide to return HttpStatus.NOT_FOUND
        }
        return new ResponseEntity<Object>(item, HttpStatus.OK);
    }

}

Services for providing dummy data for item lists and details:

ItemService.java/ItemServiceImpl.java

package com.websystique.springmvc.service;

import java.util.List;

public interface ItemService {
	List findItemsByCategory(String category);
	Object findItemById(long id, String category);
}

package com.websystique.springmvc.service;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import com.websystique.springmvc.model.Computer;
import com.websystique.springmvc.model.Phone;
import com.websystique.springmvc.model.Printer;
import com.websystique.springmvc.model.State;

@Service("itemService")
public class ItemServiceImpl implements ItemService{
	
	private static final AtomicLong counter = new AtomicLong();

	private static List<Computer> computers;
	
	private static List<Phone> phones;
	
	private static List<Printer> printers;
	
	
	static{
		computers= populateDummyComputers();
		phones= populateDummyPhones();
		printers= populateDummyPrinters();
		
	}
	
	public List findItemsByCategory(String category) {

		if(StringUtils.equalsIgnoreCase(category, "computers")){
				return computers;
		} else if(StringUtils.equalsIgnoreCase(category, "phones")){
			return phones;
		} else if(StringUtils.equalsIgnoreCase(category, "printers")){
			return printers;
		}
		return computers;
	}

	public Object findItemById(long id, String category) {
		if(category.equalsIgnoreCase("computers")){
			for(Computer computer : computers){
				if(computer.getId() == id){
					return computer;
				}
			}
		}else if(category.equalsIgnoreCase("phones")){
			for(Phone phone : phones){
				if(phone.getId() == id){
					return phone;
				}
			}
		} if(category.equalsIgnoreCase("printers")){
			for(Printer printer : printers){
				if(printer.getId() == id){
					return printer;
				}
			}
			
		}
		return null;
	}
	
	
	private static List<Computer> populateDummyComputers(){
		List<Computer> computers = new ArrayList<Computer>();
		
		computers.add(new Computer(counter.incrementAndGet(),"Lenovo", "T420", State.NEW, 500, 2.4, 8, 1000));
		computers.add(new Computer(counter.incrementAndGet(),"Lenovo", "T640", State.NEW, 2000, 3.6, 32, 2000));
		computers.add(new Computer(counter.incrementAndGet(),"Apple", "IMAC21.5", State.NEW, 1400, 2.6, 8, 1000));
		computers.add(new Computer(counter.incrementAndGet(),"HP", "Pavilion", State.NEW, 900, 2.4, 8, 1000));
		computers.add(new Computer(counter.incrementAndGet(),"Dell", "E6510", State.NEW, 500, 2.3, 8, 500));
		return computers;
	}

	private static List<Phone> populateDummyPhones(){
		List<Phone> phones = new ArrayList<Phone>();
		
		phones.add(new Phone(counter.incrementAndGet(),"Apple", "IPhone6s", State.NEW, 800, 5.2, false,false,15));
		phones.add(new Phone(counter.incrementAndGet(),"Huwawi", "Nexus6P", State.NEW, 700, 5.7, false,false,13));
		phones.add(new Phone(counter.incrementAndGet(),"Samsung", "Note5", State.NEW, 600, 5.7, false,false,14));
		phones.add(new Phone(counter.incrementAndGet(),"HTC", "M9", State.NEW, 580, 5.5, true,true,16));
		phones.add(new Phone(counter.incrementAndGet(),"LG", "G4", State.NEW, 550, 5.7, true,true,15));
		return phones;
	}


	private static List<Printer> populateDummyPrinters(){
		List<Printer> printers = new ArrayList<Printer>();
		
		printers.add(new Printer(counter.incrementAndGet(),"HP", "OfficeJet 7500A", State.NEW, 200, "A4", "InkJet",15));
		printers.add(new Printer(counter.incrementAndGet(),"Brother", "J6520dw", State.NEW, 180, "A4", "InkJet",12));
		printers.add(new Printer(counter.incrementAndGet(),"EPSON", "XP-820", State.NEW, 210, "A4", "InkJet",14));
		return printers;
	}

}

Model Classes:

package com.websystique.springmvc.model;

public class Computer{

	private long id;
	
	private String brand;
	
	private String model;
	
	private State state;
	
	private double price;

	private double processorSpeed;
	
	private int ram;
	
	private int diskCapacity;


	public Computer(long id,String brand, String model, State state, double price, 
			double processorSpeed, int ram, int diskCapacity){
		this.id = id;
		this.brand = brand;
		this.model = model;
		this.state = state;
		this.price = price;
		this.processorSpeed = processorSpeed;
		this.ram =ram;
		this.diskCapacity = diskCapacity;
	}
	
	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getBrand() {
		return brand;
	}

	public void setBrand(String brand) {
		this.brand = brand;
	}

	public String getModel() {
		return model;
	}

	public void setModel(String model) {
		this.model = model;
	}

	public State getState() {
		return state;
	}

	public void setState(State state) {
		this.state = state;
	}

	public double getPrice() {
		return price;
	}

	public void setPrice(double price) {
		this.price = price;
	}

	
	public double getProcessorSpeed() {
		return processorSpeed;
	}

	public void setProcessorSpeed(double processorSpeed) {
		this.processorSpeed = processorSpeed;
	}

	public int getRam() {
		return ram;
	}

	public void setRam(int ram) {
		this.ram = ram;
	}

	public int getDiskCapacity() {
		return diskCapacity;
	}

	public void setDiskCapacity(int diskCapacity) {
		this.diskCapacity = diskCapacity;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + (int) (id ^ (id >>> 32));
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Computer other = (Computer) obj;
		if (id != other.id)
			return false;
		return true;
	}

	@Override
	public String toString() {
		return "Computer [id=" + id + ", brand=" + brand + ", model=" + model + ", state=" + state + ", price=" + price
				+ ", processorSpeed=" + processorSpeed + ", ram=" + ram + ", diskCapacity=" + diskCapacity + "]";
	}

	
	
}
package com.websystique.springmvc.model;

public class Phone{
	
	private long id;
	
	private String brand;
	
	private String model;
	
	private State state;
	
	private double price;

	private double size;
	
	private boolean sdCard;
	
	private boolean replacableBattery;
	
	private int camera;
	
	public Phone(long id,String brand, String model, State state, double price, 
			double size, boolean sdCard, boolean replacableBattery,int camera){
		this.id = id;
		this.brand = brand;
		this.model = model;
		this.state = state;
		this.price = price;
		this.size = size;
		this.sdCard =sdCard;
		this.replacableBattery = replacableBattery;
		this.camera = camera;
	}

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getBrand() {
		return brand;
	}

	public void setBrand(String brand) {
		this.brand = brand;
	}

	public String getModel() {
		return model;
	}

	public void setModel(String model) {
		this.model = model;
	}

	public State getState() {
		return state;
	}

	public void setState(State state) {
		this.state = state;
	}

	public double getPrice() {
		return price;
	}

	public void setPrice(double price) {
		this.price = price;
	}

	public double getSize() {
		return size;
	}

	public void setSize(double size) {
		this.size = size;
	}

	public boolean isSdCard() {
		return sdCard;
	}

	public void setSdCard(boolean sdCard) {
		this.sdCard = sdCard;
	}

	public boolean isReplacableBattery() {
		return replacableBattery;
	}

	public void setReplacableBattery(boolean replacableBattery) {
		this.replacableBattery = replacableBattery;
	}

	public int getCamera() {
		return camera;
	}

	public void setCamera(int camera) {
		this.camera = camera;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + (int) (id ^ (id >>> 32));
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Phone other = (Phone) obj;
		if (id != other.id)
			return false;
		return true;
	}

	@Override
	public String toString() {
		return "Phone [id=" + id + ", brand=" + brand + ", model=" + model + ", state=" + state + ", price=" + price
				+ ", size=" + size + ", sdCard=" + sdCard + ", replacableBattery=" + replacableBattery + ", camera="
				+ camera + "]";
	}

	
	
}
package com.websystique.springmvc.model;

public class Printer{
	
	private long id;
	
	private String brand;
	
	private String model;
	
	private State state;
	
	private double price;

	private String paperFormat;
	
	private String technologie;
	
	private int pagesPerMinute;
	
	public Printer(long id,String brand, String model, State state, double price, 
			String paperFormat, String technologie, int pagesPerMinute){
		this.id = id;
		this.brand = brand;
		this.model = model;
		this.state = state;
		this.price = price;
		this.paperFormat = paperFormat;
		this.technologie =technologie;
		this.pagesPerMinute = pagesPerMinute;
	}

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getBrand() {
		return brand;
	}

	public void setBrand(String brand) {
		this.brand = brand;
	}

	public String getModel() {
		return model;
	}

	public void setModel(String model) {
		this.model = model;
	}

	public State getState() {
		return state;
	}

	public void setState(State state) {
		this.state = state;
	}

	public double getPrice() {
		return price;
	}

	public void setPrice(double price) {
		this.price = price;
	}

	public String getPaperFormat() {
		return paperFormat;
	}

	public void setPaperFormat(String paperFormat) {
		this.paperFormat = paperFormat;
	}

	public String getTechnologie() {
		return technologie;
	}

	public void setTechnologie(String technologie) {
		this.technologie = technologie;
	}

	public int getPagesPerMinute() {
		return pagesPerMinute;
	}

	public void setPagesPerMinute(int pagesPerMinute) {
		this.pagesPerMinute = pagesPerMinute;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + (int) (id ^ (id >>> 32));
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Printer other = (Printer) obj;
		if (id != other.id)
			return false;
		return true;
	}

	@Override
	public String toString() {
		return "Printer [id=" + id + ", brand=" + brand + ", model=" + model + ", state=" + state + ", price=" + price
				+ ", paperFormat=" + paperFormat + ", technologie=" + technologie + ", pagesPerMinute=" + pagesPerMinute
				+ "]";
	}
	
}

package com.websystique.springmvc.model;

public enum State {
	NEW,USED;
}

CORS Filter: Creating Filter to handle Same Origin Policy related issues


package com.websystique.springmvc.configuration;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;


public class CORSFilter implements Filter {

	public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
		HttpServletResponse response = (HttpServletResponse) res;
		response.setHeader("Access-Control-Allow-Origin", "*");
		response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
		response.setHeader("Access-Control-Max-Age", "3600");
		response.setHeader("Access-Control-Allow-Headers", "x-requested-with, Content-Type");
		chain.doFilter(req, res);
	}

	public void init(FilterConfig filterConfig) {}

	public void destroy() {}

}

Create Spring Initializer class

Look at how we are registering CORS filter with Spring configuration, which will help us to get away with Same Origin Policy issues.

package com.websystique.springmvc.configuration;

import javax.servlet.Filter;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class HelloWorldInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
 
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[] { HelloWorldConfiguration.class };
    }
  
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return null;
    }
  
    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }
    
    @Override
    protected Filter[] getServletFilters() {
    	Filter [] singleton = { new CORSFilter() };
    	return singleton;
	}
 
}

Deploy & Run

Now build the war (either by eclipse as was mentioned in previous tutorials) or via maven command line( mvn clean install). Deploy the war to a Servlet 3.0 container . Since here i am using Tomcat, i will simply put this war file into tomcat webapps folder and click on startup.bat inside tomcat/bin directory.

Open browser and browse at http://localhost:8080/Spring4MVCAngularJSRoutingExample/. it will be redirected to /item/computes [look at ‘otherwise’ part in $routeProvider config]. Check the URL in browser.

Spring4MVCAngularJSRoutingExample_img1

You can also open the developer tools in chrome and check the request sent for each operation to server and response received.

Now click on printers link, you should see all printers list in bottom panel.

Spring4MVCAngularJSRoutingExample_img3

Now click on specific printer link [in Model column], you should see the details of that specific printer in bottom panel.Also check the URL in browser.

Spring4MVCAngularJSRoutingExample_img4

That’s it.

Download Source Code


References