Build a new Web Application from scratch using Spring boot, Thymeleaf, AngularJS – Part 3
In the previous blogs we built the landing page using Thymeleaf, Bower and Bootstrap and deployed it to Heroku.
In this blog we will introduce some functionality with AngularJS for front end and Spring Boot Webservices at backend.
We will begin with Login/Logout section. Lets begin with installing AngularJS in our application using bower.
Introducing AngularJS
$ bower install angular --save
This will add angular dependencies inside the bower_components folder. In order to have angular injected into our HTML page we would need to do 2 things
1)Add the path of angular.min.js in our html file
<script src="./bower_components/angular/angular.min.js" type="text/javascript"></script>
2. Mark the body as ng-app=”myModule” ,which means we need to define a JavaScript module that Angular will recognise as an application called “myModule”. Angular module is like a container for the different parts of your app – controllers, services, filters, directives, etc.
<body ng-app="myModule">
Now we would need to define this module “myModule” in a JS file, we can call this file as app.js with constituents :
angular.module('myModule', []) .controller('home', function($http) { var self = this; $http.get('/resource/').then(function(response) { self.message = response.data; }) });
Here, we see that we are defining a controller named “home” in ‘myModule’, this controller will be used to pass values into HTML via data binding, the model here is “message”.
The data would be retrieved via HTTP GET making a REST call to our spring back end.
So, lets see how to create Spring Rest Controller :
Spring Rest Controller
We already have added the dependency "spring-boot-starter-web"
so we dont need any more spring boot dependency at this moment to build our Rest Controllers.
We will create a LoginController
@RestController public class LoginController { @RequestMapping("/resource") public Map<String,Object> home() { Map<String,Object> model = new HashMap<String,Object>(); model.put("id", UUID.randomUUID().toString()); model.put("content", "Hello World"); return model; }
Now if you place this piece of code in your index.html in a separate div, you can see that this div is now loading data dynamically from backend.
To see the data in the HTML, we need to do this :
<div ng-controller="home as home"> <p>The ID is {{home.message.id}}</p> <p>The content is {{home.message.content}}</p> </div>
Upto this point we are just able to use angularJS in our static page and retrieve some information from backend Rest Controller and render it using AngularJS.
Building Login/Logout
Now that we have got angularJS module inside our index page, lets implement the login/logout feature using Spring Security.
To build login/logout feature, we need to make 3 HTML pages.
1) index.html – this will be the landing page, where we will add navigation to login and logout. (this we already have)
2) home.html – this will be the page which will be redirected to after a user logs in.
3) login.html – this will be the page with username and password field to enter the credentials to login.
For routing between these pages, we will use ng-route
. The ngRoute module provides routing and deeplinking services and directives for angular apps. To install ngRoute using bower we will execute the following command :
bower install angular-route@X.Y.Z
Then include this in your index.html :
<script src="path/to/angular.js"></script> <script src="path/to/angular-route.js"></script>
Step 1 : Add a navigation in index.html
In order to add a navigation we need to add this block of code under body.
<div ng-controller="navigation as nav" class="container"> <ul class="nav nav-pills" role="tablist"> <li class="active"><a href="#/">home</a></li> <li><a href="#/login">login</a></li> <li ng-show="authenticated"><a href="" ng-click="nav.logout()">logout</a></li> </ul> </div> <div ng-view class="container"></div>
The “ng-view” section is going to display the “login.html” partial page.
Change the app.js file to define routes :
angular.module('myModule', [ 'ngRoute' ]) .config(function($routeProvider, $httpProvider) { $routeProvider.when('/', { templateUrl : 'home.html', controller : 'home', controllerAs: 'controller' }).when('/login', { templateUrl : 'login.html', controller : 'navigation', controllerAs: 'controller' }).otherwise('/'); }) .controller('home', function($http) { var self = this; $http.get('/resource/').then(function(response) { self.message = response.data; }) }) .controller('navigation', function($rootScope, $http, $location) { var self = this var authenticate = function(credentials, callback){ var headers = credentials ? {authentication : "Basic " + btoa(credentials.username + ":"+credentials.password) } : {}; $http.get('user', {headers : headers}).then(function(response) { if (response.data.name) { $rootScope.authenticated = true; } else { $rootScope.authenticated = false; } callback && callback(); }, function() { $rootScope.authenticated = false; callback && callback(); }); } authenticate(); self.credentials = {}; self.login = function() { authenticate(self.credentials, function() { if ($rootScope.authenticated) { $location.path("/"); self.error = false; } else { $location.path("/login"); self.error = true; } }); }; self.logout = function() { $http.post('logout', {}).finally(function() { $rootScope.authenticated = false; $location.path("/"); }); } });
Here we have defined 2 controllers and 1 config and few functions which will be used by the controllers. “Config” is used to define the paths and routing using ng-route. The controller “navigation” is used to call functions login, logout and authenticate as defined. The controller “home” is used to send greeting on home page.
The authenticated
variable is defined to provide access to authenticated user on the pages.
Step 2 : Add login.html partial page
Here we will make a partial page login.html which will be rendered inside the div which is tagged by ng-view.
Login.html
<div class="alert alert-danger" ng-show="controller.error"> There was a problem logging in. Please try again. </div> <form role="form" ng-submit="controller.login()"> <div class="form-group"> <label for="username">Username:</label> <input type="text" class="form-control" id="username" name="username" ng-model="controller.credentials.username"/> </div> <div class="form-group"> <label for="password">Password:</label> <input type="password" class="form-control" id="password" name="password" ng-model="controller.credentials.password"/> </div> <button type="submit" class="btn btn-primary">Submit</button> </form>
Then we need RestControllers for authenticating using Spring Security. We will use default authentication user of spring security. We will make a UserController with the following method :
@RequestMapping("/user") public Principal user(Principal user) { return user; }
For Spring Security to work we need to add this in Application.java
@Configuration @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) protected static class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .httpBasic() .and() .authorizeRequests() .antMatchers("/index.html", "/home.html", "/login.html", "/").permitAll() .anyRequest().authenticated(); } }
Step 3: Add home.html page with welcome message.
<h1>Message</h1> <div ng-show="authenticated"> <p>The ID is {{controller.message.id}}</p> <p>The content is {{controller.message.content}}</p> </div> <div ng-show="!authenticated"> <p>Login to see your message</p> </div>
The “authenticated” variable is used to provide access on the pages.
Till now, we have successfully used Angular JS to login and logout using Spring Security. But in real application we need actual users to be authenticated against a user database. In the next blog we are going to build the application with users getting authenticated from a user DB.
PS: Examples were referenced from the Spring Blog : https://spring.io/guides/tutorials/spring-security-and-angular-js/
Reference: | Build a new Web Application from scratch using Spring boot, Thymeleaf, AngularJS – Part 3 from our JCG partner Anirudh Bhatnagar at the anirudh bhatnagar blog. |
good article