We are using Grammarly to help us writing this article

Spring Boot, MongoDB and Angular 5 CRUD Java Web Application

by Didin J. on Feb 06, 2018 Spring Boot, MongoDB and Angular 5 CRUD Java Web Application

Step by step tutorial of building create-read-update-delete CRUD Java web application using Spring Boot, MVC, MongoDB and Angular 5

Comprehensive step by step tutorial of building create-read-update-delete CRUD Java web application using Spring Boot, MVC, MongoDB and Angular 5. The main concept of this tutorial is separate backend and frontend. The backend is Spring Boot, Data, and MongoDB, the frontend is Angular 5. We will combine the previous Spring Boot tutorial of building Java REST API. There are the options for using backend framework with Angular 5 front end. First, develop and running backend and Angular 5 on the different port, so the backend side should be CORS enable. Second, wrapping all development and runtime together using the same port. We will use the second option.

The following tools, frameworks, and modules are required for this tutorial achievement:

- Java Development Kit 8
- Spring Boot
- Spring Web
- Spring Data
- Gradle
- MongoDB
- Angular 5
- Node.js
- Angular CLI
- Spring Initializer
- Terminal or Command Line
- Text Editor or IDE

We assume that you have installed JDK 8, Gradle and Node.js. Now, you have to install Angular CLI. For that, open and edit the terminal or Node.js command line then type this command.

sudo npm install -g @angular/cli

Now, you can move to the main steps of the tutorial.


1. Generate Spring Boot Application

As usual, we start creating Spring Boot application by generating the application and its library using Spring Initializer. After go to Spring Initializer using the web browser, create the new application and add the library as below.

Spring Boot, MongoDB and Angular 5 CRUD Java Web Application - Spring Initalizr

Click `Generate Project` button and the Spring boot application will be downloaded by your browser. Next, extract the zipped Spring Boot project then copy or move to your Java projects folder. To run the Spring Boot application, type this command from the terminal or command line.

./gradlew bootRun

You will not find a landing page on the browser yet because of there's no frontend or HTML page in the static folder. To connect Spring Boot with MongoDB, open and edit `src/main/java/resources/application.properties` then add this lines.

spring.data.mongodb.database=springangular
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017

Next, start MongoDB in the other terminal or command line if it's not run yet. Run again Spring Boot application. Now, Spring Boot and MongoDB are connected and ready.


2. Create Model or Entity Class

If are using Text Editor, you have to create a folder for models. From the terminal create a models folder in `src/main/java/com/djamware/angular`.

mkdir src/main/java/com/djamware/angular/models

To create Model or Entity Class simply create a new file at `src/main/java/com/djamware/angular/models` then name it `Contact.java`.

touch  src/main/java/com/djamware/angular/models/Contact.java

Open and edit `src/main/java/com/djamware/angular/models/Contact.java` then add this lines of codes.

package com.djamware.angular.models;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

@Document(collection = "contacts")
public class Contact {
    @Id
    String id;
    String name;
    String address;
    String city;
    String phone;
    String email;

    public Contact() {
    }

    public Contact(String name, String address, String city, String phone, String email) {
        this.name = name;
        this.address = address;
        this.city = city;
        this.phone = phone;
        this.email = email;
    }

    public String getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

That class mapped to MongoDB collection with the name `contacts`.


3. Create a New Repository Interface for Contact Model

For connecting to Contact model, we need to create a Java interface or repository. Create a folder named `repositories` inside `src/main/java/com/djamware/angular/` folder.

mkdir src/main/java/com/djamware/angular/repositories

Next, create a Java Interface file inside that folder.

touch src/main/java/com/djamware/angular/repositories/ContactRepository.java

Open and edit `src/main/java/com/djamware/angular/repositories/ContactRepository.java` then add this lines of codes.

package com.djamware.angular.repositories;

import com.djamware.angular.models.Contact;
import org.springframework.data.repository.CrudRepository;

public interface ContactRepository extends CrudRepository<Contact, String> {
    @Override
    Contact findOne(String id);

    @Override
    void delete(Contact deleted);
}

We only add `findOne` and `delete` method to the interface because the rest method already handled by `CrudRepository` of Spring Data MongoDB.


4. Create a New RESTful Controller for Accessing Contact Data

Now, it's a time for RESTful Web Service (REST API) implementation by creating a new RESTful controller file. Create a folder named `controllers` inside `src/main/java/com/djamware/angular/` folder.

mkdir src/main/java/com/djamware/angular/controllers

Create a Java file named `ContactController.java` inside that new folder.

touch src/main/java/com/djamware/angular/controllers/ContactController.java

Open and edit `src/main/java/com/djamware/angular/controllers/ContactController.java` then add this lines of codes.

package com.djamware.angular.controllers;

import com.djamware.angular.models.Contact;
import com.djamware.angular.repositories.ContactRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ContactController {

    @Autowired
    ContactRepository contactRepository;

    @RequestMapping(method=RequestMethod.GET, value="/contacts")
    public Iterable<Contact> contact() {
        return contactRepository.findAll();
    }

    @RequestMapping(method=RequestMethod.POST, value="/contacts")
    public Contact save(@RequestBody Contact contact) {
        contactRepository.save(contact);

        return contact;
    }

    @RequestMapping(method=RequestMethod.GET, value="/contacts/{id}")
    public Contact show(@PathVariable String id) {
        return contactRepository.findOne(id);
    }

    @RequestMapping(method=RequestMethod.PUT, value="/contacts/{id}")
    public Contact update(@PathVariable String id, @RequestBody Contact contact) {
        Contact c = contactRepository.findOne(id);
        if(contact.getName() != null)
            c.setName(contact.getName());
        if(contact.getAddress() != null)
            c.setAddress(contact.getAddress());
        if(contact.getCity() != null)
            c.setCity(contact.getCity());
        if(contact.getPhone() != null)
            c.setPhone(contact.getPhone());
        if(contact.getEmail() != null)
            c.setEmail(contact.getEmail());
        contactRepository.save(c);
        return contact;
    }

    @RequestMapping(method=RequestMethod.DELETE, value="/contacts/{id}")
    public String delete(@PathVariable String id) {
        Contact contact = contactRepository.findOne(id);
        contactRepository.delete(contact);

        return "";
    }
}

Now, re-run again Spring Boot application then test the RESTful API.

./gradlew bootRun

Open another terminal then type this command to get Contact list from the RESTful API.

curl -i -H "Accept: application/json" localhost:8080/contacts

It should display a response like this.

HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Mon, 05 Feb 2018 12:14:39 GMT

[]

To add a contact, type this command to post a contact data.

curl -i -X POST -H "Content-Type: application/json" -d '{"name":"John Doe","address":"Jl. Cipaganti No.112","city":"Bandung","phone":"0811223112233","email":"[email protected]"}' localhost:8080/contacts

It should display a response like this.

HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Tue, 06 Feb 2018 02:59:00 GMT

{"id":"5a7919f4b9d4f13c2cb6f539","name":"John Doe","address":"Jl. Cipaganti No.112","city":"Bandung","phone":"0811223112233","email":"[email protected]"}

You can check on MongoDB console to verify that new contact data is saved. Next, to get a single contact data by ID type this command.

curl -i -H "Accept: application/json" localhost:8080/contacts/5a784bbfb9d4f121d9a31195

And here's the response.

HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Mon, 05 Feb 2018 12:22:49 GMT

{"id":"5a784bbfb9d4f121d9a31195","name":"John Doe","address":"Jl. Cipaganti No.112","city":"Bandung","phone":"0811223112233","email":"[email protected]"}

You can test update and delete using these commands.

curl -i -X PUT -H "Content-Type: application/json" -d '{"name":"John Dodol"}'
curl -i -X DELETE localhost:8080/contacts/5a784bbfb9d4f121d9a31195


5. Create an Angular 5 Application

This time for the frontend side, in the terminal and root project folder type this command.

ng new frontend

That Angular-CLI command will create an Angular 5 application folder named `frontend`. To make Angular 5 build running as Spring Boot frontend, open and edit `frontend/.angular-cli.json` then change `outDir` value as below.

...
"outDir": "../src/main/resources/static",
...

Now, test the Angular 5 configuration by type this command.

npm install
ng build

If there's something missing when do `npm install` install the required Node modules that shown in the error message. If everything fine, you can re-start Spring Boot and open the browser then point to `localhost:8080`. You should see this landing page.

Spring Boot, MongoDB and Angular 5 CRUD Java Web Application - Angular 5 Home


6. Create Angular 5 Component for Displaying Contact List

To create Angular 5 Component, simply run this command inside `frontend` folder.

ng g component contact

That command will generate all required files for build contact component and also automatically added contact component to app.module.ts.

create src/app/contact/contact.component.css (0 bytes)
create src/app/contact/contact.component.html (26 bytes)
create src/app/contact/contact.component.spec.ts (635 bytes)
create src/app/contact/contact.component.ts (273 bytes)
update src/app/app.module.ts (402 bytes)

Before add any functionality to the component, we need to add `HttpClientModule` to `app.module.ts`. Open and edit `src/app/app.module.ts` then add this import.

import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';

Add it to `@NgModule` imports after `BrowserModule`.

imports: [
  BrowserModule,
  FormsModule,
  HttpClientModule
],

Next, we will making a request to Contact RESTful API using this Angular 5 `HttpClient` module. Open and edit `frontend/src/app/contact/contact.component.ts` then add this import.

import { HttpClient } from '@angular/common/http';

Inject `HttpClient` to the constructor.

constructor(private http: HttpClient) { }

Add array variable for holding contacts data before the constructor.

contacts: any;

Add a few lines of codes for getting a list of contact data from RESTful API inside `ngOnInit` function.

ngOnInit() {
  this.http.get('/contacts').subscribe(data => {
    this.contacts = data;
  });
}

Now, we can display the contact list on the page. Open and edit `frontend/src/app/contact/contact.component.html` then replace all tags with this lines of HTML tags.

<div class="container">
  <h1>Contact List</h1>
  <table class="table">
    <thead>
      <tr>
        <th>Name</th>
        <th>City</th>
        <th>Email</th>
        <th>Action</th>
      </tr>
    </thead>
    <tbody>
      <tr *ngFor="let contact of contacts">
        <td>{{ contact.title }}</td>
        <td>{{ contact.city }}</td>
        <td>{{ contact.email }}</td>
        <td>Show Detail</td>
      </tr>
    </tbody>
  </table>
</div>

That HTML tags include style class from Bootstrap CSS library. Open and edit `frontend/src/index.html` then add the Bootstrap CSS and JS library.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Frontend</title>
  <base href="/">

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
  <!-- Latest compiled and minified CSS -->
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
  <!-- Optional theme -->
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
</head>
<body>
  <app-root></app-root>
  <!-- Latest compiled and minified JavaScript -->
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
</body>
</html>


7. Create Angular 5 Routes to Contact Component

To use contact component as default landing page, open and edit `frontend/src/app/app.module.ts` the add import for Routing.

import { RouterModule, Routes } from '@angular/router';

Create constant router for routing to contact component before `@NgModule`.

const appRoutes: Routes = [
  {
    path: 'contact',
    component: ContactComponent,
    data: { title: 'Contact List' }
  },
  { path: '',
    redirectTo: '/contact',
    pathMatch: 'full'
  }
];

In @NgModule imports, section adds ROUTES constant, so imports section will be like this.

imports: [
  BrowserModule,
  FormsModule,
  HttpClientModule,
  RouterModule.forRoot(
    appRoutes,
    { enableTracing: true } // <-- debugging purposes only
  )
],

To activate that routes in Angular 5, open and edit `frontend/src/app/app.component.html` then replace all codes with this.

<router-outlet></router-outlet>

Now, we have to test our Spring Boot application displaying contact list using Angular 5. Build Angular 5 application from the frontend folder.

ng build

Then back to root folder to re-run the Spring Boot application.

cd ../
./gradlew bootRun

Refresh the page `localhost:8080` in the browser and you should see this page.

Spring Boot, MongoDB and Angular 5 CRUD Java Web Application - Contact List


8. Create Angular 5 Component for Displaying Contact Detail

Same as previous section, type this command to generate new component.

ng g component contact-detail

Add router to `frontend/src/app/app.module.ts` routes constant.

const appRoutes: Routes = [
  {
    path: 'contact',
    component: ContactComponent,
    data: { title: 'Contact List' }
  },
  {
    path: 'contact-detail/:id',
    component: ContactDetailComponent,
    data: { title: 'Contact Details' }
  },
  { path: '',
    redirectTo: '/contact',
    pathMatch: 'full'
  }
];

Open and edit `frontend/src/app/contact-detail/contact-detail.component.ts`. Replace all codes with this.

import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { ActivatedRoute } from '@angular/router';

@Component({
  selector: 'app-contact-detail',
  templateUrl: './contact-detail.component.html',
  styleUrls: ['./contact-detail.component.css']
})
export class ContactDetailComponent implements OnInit {

  contact = {};

  constructor(private route: ActivatedRoute, private http: HttpClient) { }

  ngOnInit() {
    this.getContactDetail(this.route.snapshot.params['id']);
  }

  getContactDetail(id) {
    this.http.get('/contacts/'+id).subscribe(data => {
      this.contact = data;
    });
  }

}

Open and edit `frontend/src/app/contact-detail/contact-detail.component.html`. Replace all codes with this.

<div class="container">
  <h1>{{ contact.name }}</h1>
  <dl class="list">
    <dt>Address</dt>
    <dd>{{ contact.address }}</dd>
    <dt>City</dt>
    <dd>{{ contact.city }}</dd>
    <dt>Phone</dt>
    <dd>{{ contact.phone }}</dd>
    <dt>Email</dt>
    <dd>{{ contact.email }}</dd>
  </dl>
</div>

Open and edit `frontend/src/app/contact/contact.component.html` then replace `Show Detail` text inside `Action` column with this.

<td><a [routerLink]="['/contact-detail', contact.id]">Show Detail</a></td>


9. Create Angular 5 Component for Add New Contact

To create a component to add new Contact, type this command as usual.

ng g component contact-create

Add router to `frontend/src/app/app.module.ts` routes constant.

const appRoutes: Routes = [
  {
    path: 'contact',
    component: ContactComponent,
    data: { title: 'Contact List' }
  },
  {
    path: 'contact-detail/:id',
    component: ContactDetailComponent,
    data: { title: 'Contact Details' }
  },
  {
    path: 'contact-create',
    component: ContactCreateComponent,
    data: { title: 'Create Contact' }
  },
  { path: '',
    redirectTo: '/contact',
    pathMatch: 'full'
  }
];

Add 'contact-create' link on `frontend/src/app/contact/contact.component.html`.

<h1>Contact List
  <a [routerLink]="['/contact-create']" class="btn btn-default btn-lg">
    <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
  </a>
</h1>

Now, open and edit `frontend/src/app/contact/contact-create.component.ts` then replace all with this codes.

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app-contact-create',
  templateUrl: './contact-create.component.html',
  styleUrls: ['./contact-create.component.css']
})
export class ContactCreateComponent implements OnInit {

  contact = {};

  constructor(private http: HttpClient, private router: Router) { }

  ngOnInit() {
  }

  saveContact() {
    this.http.post('/contacts', this.contact)
      .subscribe(res => {
          this.router.navigate(['/contact-detail', res]);
        }, (err) => {
          console.log(err);
        }
      );
  }

}

Modify `frontend/src/app/contact-create/contact-create.component.html`, replace all with this HTML tags.

<div class="container">
  <h1>Add New Contact</h1>
  <div class="row">
    <div class="col-md-6">
      <form (ngSubmit)="saveContact()" #contactForm="ngForm">
        <div class="form-group">
          <label for="name">Name</label>
          <input type="text" class="form-control" [(ngModel)]="contact.name" name="name" required>
        </div>
        <div class="form-group">
          <label for="name">Address</label>
          <input type="text" class="form-control" [(ngModel)]="contact.address" name="address" required>
        </div>
        <div class="form-group">
          <label for="name">City</label>
          <input type="text" class="form-control" [(ngModel)]="contact.city" name="city" required>
        </div>
        <div class="form-group">
          <label for="name">Phone</label>
          <input type="phone" class="form-control" [(ngModel)]="contact.phone" name="phone" required>
        </div>
        <div class="form-group">
          <label for="name">Email</label>
          <input type="email" class="form-control" [(ngModel)]="contact.email" name="email" required>
        </div>
        <div class="form-group">
          <button type="submit" class="btn btn-success" [disabled]="!contactForm.form.valid">Save</button>
        </div>
      </form>
    </div>
  </div>
</div>


10. Create Angular 5 Component for Edit Contact

As usual, we will generate component for edit contact. Type this command for doing that.

ng g component contact-edit

Add route in `frontend/src/app/app.module.ts` so, it looks like this.

const appRoutes: Routes = [
  {
    path: 'contact',
    component: ContactComponent,
    data: { title: 'Contact List' }
  },
  {
    path: 'contact-detail/:id',
    component: ContactDetailComponent,
    data: { title: 'Contact Details' }
  },
  {
    path: 'contact-create',
    component: ContactCreateComponent,
    data: { title: 'Create Contact' }
  },
  {
    path: 'contact-edit/:id',
    component: ContactEditComponent,
    data: { title: 'Edit Contact' }
  },
  { path: '',
    redirectTo: '/contact',
    pathMatch: 'full'
  }
];

Open and edit again `frontend/src/app/contact-detail/contact-details.component.html` and add edit `routeLink` in the last line.

<div class="row">
  <div class="col-md-12">
    <a [routerLink]="['/contact-edit', contact.id]" class="btn btn-success">EDIT</a>
  </div>
</div>

Now, open and edit `frontend/src/app/contact-edit/contact-edit.component.ts` then replace all codes with this.

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app-contact-edit',
  templateUrl: './contact-edit.component.html',
  styleUrls: ['./contact-edit.component.css']
})
export class ContactEditComponent implements OnInit {

  contact = {};

  constructor(private http: HttpClient, private router: Router, private route: ActivatedRoute) { }

  ngOnInit() {
    this.getContact(this.route.snapshot.params['id']);
  }

  getContact(id) {
    this.http.get('/contacts/'+id).subscribe(data => {
      this.contact = data;
    });
  }

  updateContact(id, data) {
    this.http.put('/contacts/'+id, data)
      .subscribe(res => {
          let id = res['id'];
          this.router.navigate(['/contact-detail', id]);
        }, (err) => {
          console.log(err);
        }
      );
  }

}

Open and edit `frontend/src/app/contact-edit/contact-edit.component.html` then replace all codes with this.

<div class="container">
  <h1>Edit Contact</h1>
  <div class="row">
    <div class="col-md-6">
      <form (ngSubmit)="updateContact(contact.id)" #contactForm="ngForm">
        <div class="form-group">
          <label for="name">Name</label>
          <input type="text" class="form-control" [(ngModel)]="contact.name" name="name" required>
        </div>
        <div class="form-group">
          <label for="name">Address</label>
          <input type="text" class="form-control" [(ngModel)]="contact.address" name="address" required>
        </div>
        <div class="form-group">
          <label for="name">City</label>
          <input type="text" class="form-control" [(ngModel)]="contact.city" name="city" required>
        </div>
        <div class="form-group">
          <label for="name">Phone</label>
          <input type="phone" class="form-control" [(ngModel)]="contact.phone" name="phone" required>
        </div>
        <div class="form-group">
          <label for="name">Email</label>
          <input type="email" class="form-control" [(ngModel)]="contact.email" name="email" required>
        </div>
        <div class="form-group">
          <button type="submit" class="btn btn-success" [disabled]="!contactForm.form.valid">Update</button>
        </div>
      </form>
    </div>
  </div>
</div>


11. Create Delete Function on Contact-Detail Component

Open and edit `frontend/src/app/contact-detail/contact-detail`.component.ts then add `Router` module to `@angular/router`.

import { ActivatedRoute, Router } from '@angular/router';

Inject `Router` in the constructor params.

constructor(private router: Router, private route: ActivatedRoute, private http: HttpClient) { }

Add this function for delete contact.

deleteContact(id) {
  this.http.delete('/contacts/'+id)
    .subscribe(res => {
        this.router.navigate(['/contact']);
      }, (err) => {
        console.log(err);
      }
    );
}

Add delete button in `frontend/src/app/contact-detail/contact-detail.component.html` on the right of Edit `routerLink`.

<div class="row">
  <div class="col-md-12">
    <a [routerLink]="['/contact-edit', contact.id]" class="btn btn-success">EDIT</a>
    <button class="btn btn-danger" type="button" (click)="deleteContact(contact.id)">DELETE</button>
  </div>
</div>


12. Run and Test Spring Boot, MongoDB, and Angular 5 Java CRUD Web Application

Now, it's time for functionality the whole application. Build the Angular 5 application first.

cd frontend
ng build

Back to Spring Boot application then run again the application.

cd ../
./gradlew bootRun

Here's the Java CRUD web application looks like.

Spring Boot, MongoDB and Angular 5 CRUD Java Web Application - Contact List

Spring Boot, MongoDB and Angular 5 CRUD Java Web Application - Contact Show

Spring Boot, MongoDB and Angular 5 CRUD Java Web Application - Contact Edit

That it's for now. If something wrong with the codes in this tutorial, you can compare it with the working full source code in our GitHub.

That just the basic. If you need more deep learning about Java and Spring Framework you can take the following cheap course:

Thanks!

The following resources might be useful for you:

Loading…