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:
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:
<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>
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>
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() {} }
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; } }
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.
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.
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.
That’s it.
References
If you like tutorials on this site, why not take a step further and connect me on Facebook , Google Plus & Twitter as well? I would love to hear your thoughts on these articles, it will help improve further our learning process.
In this post we will be developing a full-blown CRUD application using Spring Boot, AngularJS, Spring Data, JPA/Hibernate and MySQL,…
Spring Boot complements Spring REST support by providing default dependencies/converters out of the box. Writing RESTful services in Spring Boot…
Being able to start the application as standalone jar is great, but sometimes it might not be possible to run…
Spring framework has taken the software development industry by storm. Dependency Injection, rock solid MVC framework, Transaction management, messaging support,…
Let's secure our Spring REST API using OAuth2 this time, a simple guide showing what is required to secure a…
This post shows how an AngularJS application can consume a REST API which is secured with Basic authentication using Spring…
View Comments
how I can integrate spring security with ngrout ?
Hello Sir can you help me Master + Details form insertion in database where more than 10 or 15 rows will insert into database. I cordially respect you. Please see the attachment form.
If someone help me I will pleased you forever .............. https://uploads.disquscdn.com/images/7cf019291390ad334515531b5dc96ea85d3214c89675e7e4d45087bfd9446c34.png
If Possible please help me someone............ I am the ending point of my Job(Please Help me )
I look for this solution on online but can't see any solution ....... If you may know any solution please give me hints how to over come this problem..........
I am also having the same question, what is the alternative for Velocity ?
this one was the best ever site to learn Spring, I'm really thanks full to you, I've a question, would you please tell me, VelocityConfigurer is deprecated in Spring 4.3.6.RELEASE version, so, what is alternate,??
Hello Jeevan, you may want to use Freemarker in this case. Have a look at this post for more help on freemarker.
Great collection of tutorials!!Just what I was looking for..thank you!!
Hi websystique
I see that you used 2 different URL: 1 for template, 1 for Rest Service.
Can I make Spring always return 1 page?
Example: When I open
http://app/ -> return index.html
http://app/items?id=%5Bid%5D -> return index.html
And them in the angular app, I can call Rest to http://app/items?id=%5Bid%5D
Hi, For that, you can override default handler mapping, mapping all your requests to one controller. Have a look at this link.
Your web.xml file?
what url-pattern you gave to your dispatcher??
It's annotation based.For mapping, look at HelloWorldInitializer. It is "/".
Ok but then tell me one thing / means it will applied to all files right then how your resources files like js and CSS are directly served by container?
Hopefully m clear enough to ask dis question! Actually I am new to spring so it can be silly .
Nice example but has too many problems after importing to eclipse.
Harshit C., create the project from the command line using something like this
mvn -B archetype:generate -DgroupId=com.websystique.springmvc -DartifactId=Spring4MVCAngularJSRoutingExample -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-webapp -DarchetypeVersion=1.0 -DinteractiveMode=false
And then convert it to eclipse project using the command mvn eclipse:eclipse. Finally, import it in eclipse as an existing maven project. No errors :-), all the best!
Remember to delete the index.jsp and web.xml file in your project structure
Great job. Thank you for this. When I click any of the links nothing happens. I put breakpoints in the angular code and it appears the angular code is not being invoked.
?????
Ok. There are inconsistencies in the way it works. There are several sample apps that can be googled up that show, like yours does, the tag as.... (uses a slash after the hash), while there are others that show the same tag to be coded as.... (no slash after the hash). This second way worked for me. Your style did not. I don't get it. Kinda sucks that it took me a full day to figure this out. Anyway, thanks again for a great sample project.
the other port is not working
If you meant using another port, you can change in the URL provided inside $http calls in service.
server: pivotal tc
What I was trying to say was that when I used this in my html code: a href="#/items..." (with the forward slash) it did not work. Click on a link defined that way did not run the angular code. What worked was a href="#items (with no forward slash). Clicking on a link defined this way did run the angular code and everything worked fine.
Hi Gary,
I just tried the URL http://localhost:8080/Spring4MVCAngularJSRoutingExample/#/items/computers and it worked. If you want to remove # altogether from the URL itself, you can do so with $locationProvider in App.config :
App.config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {
.....
$locationProvider.html5Mode(true);
}
and adding in section of index.html.