Spring Boot + Angular 5 +Spring Data + Rest Example(CRUD)

By Dhiraj Ray, 05 January,2018   73K

This tutorial provides a complete implementation of Spring Boot, Angular 5 and spring data to build an end to end single page java web application with example.We will be using spring boot 1.5 to expose REST APIs and angular5 with routing to build our client that will be consuming the APIs exposed by the server.Also, we will be integrating MySql database with the backend code for CRUD operation.We will be using angular CLI to generate angular project and spring boot initializers to generate spring boot project.At the end of this article, you will be able to build a user management application with CRUD operation that can either be deployed to a standalone tomcat or deploy client and server to different servers with cross origin requests.

In the next article, we will look into different ways to package spring boot and angular 5 application together in a single war file with maven and deploy to standalone tomcat. Also you might be interested in integrating this application with Angular5 JWT Authentication with Spring Boot Security

The latest Angular version is 6 and here is an CRUD Example with Angular 6

Table of Contents
1. Angular 5 Features 
2. Environment Setup
2.1 Angular 5 Environment SetUp
2.2 Spring Boot Environment SetUp
3. Default Files Generated by CLI command
4. Spring Boot Implementation
4.1 Spring Boot Rest APIs
4.2 Spring Boot Service Implementation
4.3 Spring Data Implementation
4.4 Spring Boot Datasource Configuration
5. Angular Implementation
5.1 Create Angular Component
5.2 Create Angular Views
5.3 Angular Routing
5.4 Angular Module
6 Angular CLI Proxy Configuration
7. Running Spring Boot Application
8. Running Angular App

Angular 5 Features

1. Angular 5 is more faster, lighter and easy to use.

2. Material design capabilities and improved compiler with build optimizer

3. New HttpClientModule is introduced which is a complete rewrite of the existing HttpModule.

4. TypeScript 2.4 support.

5. Reactive Forms Support

Environment Setup

We have two different part, client and server, of the application that we are going to build and hence, the environment set up is also specific to each part.

Angular5 Environment SetUp

We will have a plain angular project setup here.Check one of my article to integrate material design in angular 5 project. Angular 5 provides a beautiful tool - Angular CLI to get started with Angular. Here, we will be using the same tool to generate a sample angular app and then modify it to match our requirement.To get started with Angular CLI, it is required to have node installed so that we can use the NPM tool. You can check if node is installed or not on your machine by hitting node -v. On my machine I get following result.

node-version

If not installed visit NodeJs official website to install it first.Now, once it is done, traverse to your workspace location and execute following commands to install angular cli and generate a sample angular project.

npm install -g @angular/cli
ng new portal-app

Once this is done, you can traverse to the location and see a folder portal-app is created that contains all the files and folders generated by angular cli command to get started with angular 5.Now you can open your favourite editor to import the project.I imported this project in IntellijIdea and got the structure as below:

angular-cli-structure

One thing to check here is that if you have installed your NodeJs with sudo command, then you might get some permission issue as below while installing angular cli.To avoid these kind of situation, it is always recommended to use brew command while installing any new software.

If you face this issue then provide read/write access to the folder - /usr/local/lib/node_modules or follow the instruction here - Mac Support

For windows user, you can use git command line or cygwin for the installation.

Spring Boot Environment SetUp

Spring boot team has really made spring boot environment setup easy by providing default initializers.Open the url https://start.spring.io/ and generate the project as follow.

spring-boot-project-initializers

Now unzip user-portal.zip and import into java IDE. Following will be the final structure.

final-spring-boot-project-structure

Default Files Generated by CLI command

Now let us try to understand the different files generated.

Modules - Modules break up the application into logical pieces of code. Each piece of code or module is designed to perform a single task.All the modules are loaded by main.ts.

Component - Component is used to bring the modules together.

tsconfig.json - The presence of tsconfig.json file in a directory indicates that the directory is the root of a typescript project.This file specifies the root files and typescript compiler motions required to compile typescript.

package.json - It contains all the dependencies defined for the angular project.Once, we do nom install, these dependencies are automatically downloaded.

karma.conf.json - Config file for karma unit tests.

The file .angular-cli.json will have all the application configurations such as info about the root and out directory.The welcome or main html file along with the main ts file. All the other environment related information will be present here.

Now it's time to run the dfault generated application and see it in the browser. If you are using IntellijIdea then you can run ng serve command from Terminal inside it and if not hit following command in the terminal.

 cd portal-app
 ng serve
 

After this open your browser and hit the url - http://localhost:4200/ and the angular app is up. Now we can start modifying the app to create a user management portal.

Spring Boot Rest APIs

Now, let's start by creating our APIs first.We have UerController where all the APIs for CRUD operation is exposed.The @CrossOrigin is used to allow Cross-Origin Resource Sharing (CORS) so that our angular application running on different server can consume these APIs from a browser.We can also configure the proxy in angular side using proxy.config.json which has been discussed in the subsequent topic.

UserController.java
package com.devglan.userportal;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@CrossOrigin(origins = "http://localhost:4200", maxAge = 3600)
@RestController
@RequestMapping({"/api"})
public class UserController {

    @Autowired
    private UserService userService;

    @PostMapping
    public User create(@RequestBody User user){
        return userService.create(user);
    }

    @GetMapping(path = {"/{id}"})
    public User findOne(@PathVariable("id") int id){
        return userService.findById(id);
    }

    @PutMapping
    public User update(@RequestBody User user){
        return userService.update(user);
    }

    @DeleteMapping(path ={"/{id}"})
    public User delete(@PathVariable("id") int id) {
        return userService.delete(id);
    }

    @GetMapping
    public List findAll(){
        return userService.findAll();
    }
}

Spring Boot Service Implementation

The service class has no extra logic here and it's a very a simple implementation.

UserServiceImpl.java
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserRepository repository;

    @Override
    public User create(User user) {
        return repository.save(user);
    }

    @Override
    public User delete(int id) {
        User user = findById(id);
        if(user != null){
            repository.delete(user);
        }
        return user;
    }

    @Override
    public List findAll() {
        return repository.findAll();
    }

    @Override
    public User findById(int id) {
        return repository.findOne(id);
    }

    @Override
    public User update(User user) {
        return null;
    }
}

Spring Data Implementation

We will be using Spring data JPA implementation for ORM related solution.To know inside implementation of Spring data you can visit my other post - Spring Boot JPA and Spring Boot Hibernate implementation.

UserRepository.java
package com.devglan.userportal;

import org.springframework.data.repository.Repository;

import java.util.List;

public interface UserRepository extends Repository {

    void delete(User user);

    List findAll();

    User findOne(int id);

    User save(User user);
}

Spring Boot Datasource Configuration

application.properties
server.contextPath=/user-portal
spring.datasource.url=jdbc:mysql://localhost:3306/testdb
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.show-sql=true
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl
spring.jpa.hibernate.naming.physical-strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy

Default Scripts

CREATE TABLE user(id INT NOT NULL AUTO_INCREMENT,email VARCHAR(255),first_name  VARCHAR(255),last_name VARCHAR(255),PRIMARY KEY (id))ENGINE=InnoDB;

Create Angular Component

Angular CLI has generate command to create component.Hit the command ng generate component user and it will create a user folder inside app folder.This user folder will have all the required files for user module.

At first we will modify app.component.html to include 2 links for list users and add users.All our views willl be loaded inside router-outlet.

app.component.html
<div class="container-fluid">
<div class="col-md-offset-1">
  <h1>
    Welcome to {{title}}!
  </h1>
</div>

<a routerLink="/users"> List Users</a>
<a style="margin-left:10px" routerLink="/add">Add User</a>
<br/>
<router-outlet></router-outlet>
</div>

Since, we have two routes defined above, we require two different views(user.component.html, add-user.component.html) and components(user.component.ts, add-user.component.ts) to render on each click.Now let us implement the code for user.component.ts.Here, the method ngOnInit() will be invoked when this component is loaded and it will fetch all the user records and the html page will be populated.

user.compnent.ts
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';

import { User } from '../models/user.model';
import { UserService } from './user.service';

@Component({
  selector: 'app-user',
  templateUrl: './user.component.html',
  styles: []
})
export class UserComponent implements OnInit {

  users: User[];

  constructor(private router: Router, private userService: UserService) {

  }

  ngOnInit() {
    this.userService.getUsers()
      .subscribe( data => {
        this.users = data;
      });
  };

  deleteUser(user: User): void {
    this.userService.deleteUser(user)
      .subscribe( data => {
        this.users = this.users.filter(u => u !== user);
      })
  };

}

Similarly we have add-user.component.ts
import { Component } from '@angular/core';
import { Router } from '@angular/router';

import { User } from '../models/user.model';
import { UserService } from './user.service';

@Component({
  templateUrl: './add-user.component.html'
})
export class AddUserComponent {

  user: User = new User();

  constructor(private router: Router, private userService: UserService) {

  }

  createUser(): void {
    this.userService.createUser(this.user)
        .subscribe( data => {
          alert("User created successfully.");
        });

  };

}

user.model.ts
export class User {

  id: string;
  firstName: string;
  lastName: string;
  email: string;
}
user.service.ts
import {Injectable} from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';

import { User } from '../models/user.model';


const httpOptions = {
  headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};

@Injectable()
export class UserService {

  constructor(private http:HttpClient) {}

  //private userUrl = 'http://localhost:8080/user-portal/user';
	private userUrl = '/api';

  public getUsers() {
    return this.http.get<User[]>(this.userUrl);
  }

  public deleteUser(user) {
    return this.http.delete(this.userUrl + "/"+ user.id);
  }

  public createUser(user) {
    return this.http.post<User>(this.userUrl, user);
  }

}

Create Angular Views

As discussed we have two views - user.component.html and add-user.component.html

user.component.html
<div class="col-md-6">
<h2> User Details</h2>

<table class="table table-striped">
  <thead>
  <tr>
    <th class="hidden">Id</th>
    <th>FirstName</th>
    <th>LastName</th>
    <th>Email</th>
    <th>Action</th>
  </tr>
  </theadv
  <tbody>
  <tr *ngFor="let user of users">
    <td class="hidden">{{user.id}}</td>
    <td>{{user.firstName}}</td>
    <td>{{user.lastName}}</td>
    <td>{{user.email}}</td>
    <td><button class="btn btn-danger" (click)="deleteUser(user)"> Delete User</button></td>
  </tr>
  </tbody>
</table>
</div>

add-user.component.html
<div class="col-md-6">
  <h2 class="text-center">Add User</h2>
<form>
  <div class="form-group">
    <label for="email">Email address:</label>
    <input type="email" [(ngModel)]="user.email" placeholder="Email" name="email" class="form-control" id="email">
  </div>

  <div class="form-group">
    <label for="firstName">First Name:</label>
    <input [(ngModel)]="user.firstName" placeholder="First Name" name="firstName" class="form-control" id="firstName">
  </div>

  <div class="form-group">
    <label for="lastName">Last Name:</label>
   <input [(ngModel)]="user.lastName" placeholder="Last name" name="lastName" class="form-control" id="lastName">
  </div>

  <button class="btn btn-success" (click)="createUser()">Create</button>
</form>
</div>

Angular Routing

Now it's time to configure routing in angular.In this configuration, we will configure the path and corresponding component to load which will in turn load the respective view.Following is our routing configuration.

app.routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

import { UserComponent } from './user/user.component';
import {AddUserComponent} from './user/add-user.component';

const routes: Routes = [
  { path: 'users', component: UserComponent },
  { path: 'add', component: AddUserComponent }
];

@NgModule({
  imports: [
    RouterModule.forRoot(routes)
  ],
  exports: [
    RouterModule
  ],
  declarations: []
})
export class AppRoutingModule { }

Angular Module

Now we are almost done with our application.We only need to include all the above implementation in our main module.

app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';

import { AppComponent } from './app.component';
import { UserComponent } from './user/user.component';
import { AppRoutingModule } from './app.routing.module';
import {UserService} from './user/user.service';
import {HttpClientModule} from "@angular/common/http";
import {AddUserComponent} from './user/add-user.component';

@NgModule({
  declarations: [
    AppComponent,
    UserComponent,
    AddUserComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,
    FormsModule
  ],
  providers: [UserService],
  bootstrap: [AppComponent]
})
export class AppModule { }

Angular CLI Proxy Configuration

To configure proxy in angular CLI, we need to create proxy.config.json file in the root of the angular project and edit the start script in package.json.

proxy.config.json
{
  "/api/*": {
    "target": "http://localhost:8080/user-portal",
    "secure": false
  }
}

The value of target here is the context root of the application and api is the endpoint for user API.

package.json
 "start": "ng serve --proxy-config proxy.config.json",

Doing so, the request to http://localhost:4200/api would be proxied to http://localhost:8080/user-portal.

Recently, when I tried above command, it gave me following error.

spring-boot2-angular5-error

To fix the above error,replace "@angular/cli": "1.6.3", with "@angular/cli": "^1.6.3", in package.json and run npm update.After this it should work perfectly.

Now make sure to change the userUrl value to '/api' in user.service.ts file and comment @CrossOrigin in UserController.java.Once this done use ng serve --proxy-config proxy.config.json or npm start to start the angular app.

Final Application Structure

angular-final-project-structure

Running Spring Boot Application

We will be using spring boot embedded tomcat feature to deploy application.For more on this feature check this.

UserPortalApplication.java
package com.devglan.userportal;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class UserPortalApplication {

	public static void main(String[] args) {
		SpringApplication.run(UserPortalApplication.class, args);
	}
}

Run Angular App

Now the server is up.Hit ng serve to deploy angular application and let's test the application.

Hit the url - http://localhost:4200/ and you can see following result.

angular-home

Now, click on the Add User link and following form will appear to add user.

angular-add-user

Now, click on the list user after adding multiple users.

angular-list-user

Conclusion

This is pretty much about spring boot and angular 5 integration tutorial.In the next article, we will look into deploying this application in a single war file with maven and tomcat. You can download the source from here.If time permits, we will try to integrate spring security with it.Please let me know your comments below.

1. Angular 6 Example

2. Spring Boot Angular Websocket

3. Angular Jwt Authentication

4. Angular Material Dialog

5. Angular Material App

If You Appreciate What We Do Here On Devglan, You Should Consider: