Angular 12 SpringBoot MongoDB CRUD Example

In this tutorial, JavaSampleApproach shows you Angular 12 Http Client & Spring Boot Server example that uses Spring Data to interact with MongoDB and Angular 12 as a front-end technology to make request and receive response.

Related Posts:
How to use Angular Http Client to fetch Data from SpringBoot RestAPI – Angular 12
How to use Angular HttpClient to POST, PUT, DELETE data on SpringBoot Rest APIs – Angular 12
How to build SpringBoot MongoDb RestfulApi
How to use SpringData MongoRepository to interact with MongoDB

Full Reactive:
Angular 12 + Spring WebFlux + Spring Data Reactive MongoDB example | Full-Reactive Angular 12 Http Client – Spring Boot RestApi Server

I. Technologies

– Java 1.8
– Maven 3.3.9
– Spring Tool Suite 3.9.0.RELEASE
– Spring Boot 1.5.8.RELEASE
– Angular 12
– MongoDB 3.4.10

II. Overview

angular-http-service-architecture

1. Spring Boot Server

angular4-springdata-mongodb-server-overview

Spring Data MongoDB – MongoRepository example:
How to use SpringData MongoRepository to interact with MongoDB

2. Angular 12 Client

angular4-springdata-mongodb-httpclient-overview

For more details:
– About Angular 12 Routing:
How to work with Angular Routing – Spring Boot + Angular 12
– About Angular Http Client to GET/POST/DELETE:
+ How to use Angular Http Client to fetch Data from SpringBoot RestAPI – Angular 12
+ How to use Angular HttpClient to POST, PUT, DELETE data on SpringBoot Rest APIs – Angular 12

III. Practice

1. Project Structure

1.1 Spring Boot Server

angular4-springdata-mongodb-server-structure

– Class Customer corresponds to document in customer collection.
CustomerMongoRepository is an interface extends MongoRepository, will be autowired in CustomerController for implementing repository methods and custom finder methods.
CustomerController is a REST Controller which has request mapping methods for RESTful requests such as: getAll, create, update, delete Customers.
– Configuration for Spring Data MongoDB properties in application.properties
– Dependencies for Spring Boot and Spring Data MongoDB in pom.xml

1.2 Angular 12 Client

angular4-springdata-mongodb-client-structure

In this example, we have:
– 3 components: customers-list, customer-details, create-customer.
– 3 modules: FormsModule, HttpClientModule, AppRoutingModule.
customer.ts: class Customer (id, name, age, active).
customer.service.ts: Service for HttpClient methods.

2. How to do

2.1 Spring Boot Server

2.1.1 Dependency
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2.1.2 Customer – Data Model

package com.javasampleapproach.angular4mongodb.model;

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

@Document(collection = "customer")
public class Customer {
	@Id
	private String id;

	private String name;
	private int age;
	private boolean active;

	public Customer() {
	}

	public Customer(String name, int age) {
		this.name = name;
		this.age = age;
	}

	public String getId() {
		return id;
	}

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

	public String getName() {
		return this.name;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public int getAge() {
		return this.age;
	}

	public boolean isActive() {
		return active;
	}

	public void setActive(boolean active) {
		this.active = active;
	}

	@Override
	public String toString() {
		return "Customer [id=" + id + ", name=" + name + ", age=" + age + ", active=" + active + "]";
	}
}
2.1.3 MongoDB Repository

package com.javasampleapproach.angular4mongodb.repo;

import org.springframework.data.mongodb.repository.MongoRepository;

import com.javasampleapproach.angular4mongodb.model.Customer;

public interface CustomerMongoRepository extends MongoRepository {

}
2.1.4 REST Controller
package com.javasampleapproach.angular4mongodb.controller;

import java.util.List;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.javasampleapproach.angular4mongodb.model.Customer;
import com.javasampleapproach.angular4mongodb.repo.CustomerMongoRepository;

@CrossOrigin(origins = "http://localhost:4200")
@RestController
@RequestMapping("/api")
public class CustomerController {

	@Autowired
	CustomerMongoRepository customerRepository;

	@GetMapping("/customers")
	public List<Customer> getAllCustomers() {
		System.out.println("Get all Customers...");

		return customerRepository.findAll();
	}

	@PostMapping("/customers/create")
	public Customer createCustomer(@Valid @RequestBody Customer customer) {
		System.out.println("Create Customer: " + customer.getName() + "...");

		customer.setActive(false);
		return customerRepository.save(customer);
	}

	@PutMapping("/customers/{id}")
	public ResponseEntity<Customer> updateCustomer(@PathVariable("id") String id, @RequestBody Customer customer) {
		System.out.println("Update Customer with ID = " + id + "...");

		Customer customerData = customerRepository.findOne(id);
		if (customer == null) {
			return new ResponseEntity<>(HttpStatus.NOT_FOUND);
		}
		customerData.setName(customer.getName());
		customerData.setAge(customer.getAge());
		customerData.setActive(customer.isActive());
		Customer updatedcustomer = customerRepository.save(customerData);
		return new ResponseEntity<>(updatedcustomer, HttpStatus.OK);
	}

	@DeleteMapping("/customers/{id}")
	public ResponseEntity<String> deleteCustomer(@PathVariable("id") String id) {
		System.out.println("Delete Customer with ID = " + id + "...");

		customerRepository.delete(id);
		
		return new ResponseEntity<>("Customer has been deleted!", HttpStatus.OK);
	}
	
	@DeleteMapping("/customers/delete")
	public ResponseEntity<String> deleteAllCustomers() {
		System.out.println("Delete All Customers...");

		customerRepository.deleteAll();
		
		return new ResponseEntity<>("All customers have been deleted!", HttpStatus.OK);
	}
}
2.1.5 Configuration for Spring Data MongoDB

spring.data.mongodb.database=jsa_mongodb
spring.data.mongodb.port=27017

2.2 Angular 12 Client

2.2.1 AppModule

import { AppRoutingModule } from './app-routing.module';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';

import { AppComponent } from './app.component';

import { CustomersListComponent } from './customers/customers-list/customers-list.component';
import { CustomerDetailsComponent } from './customers/customer-details/customer-details.component';
import { CreateCustomerComponent } from './customers/create-customer/create-customer.component';

import { CustomerService } from './customers/customer.service';

@NgModule({
  declarations: [
    AppComponent,
    CustomersListComponent,
    CustomerDetailsComponent,
    CreateCustomerComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    AppRoutingModule,
    HttpClientModule
  ],
  providers: [CustomerService],
  bootstrap: [AppComponent]
})

export class AppModule { }
2.2.2 Model

export class Customer {
  id: string;
  name: string;
  age: number;
  active: boolean;
}
2.2.3 DataService
import { Injectable } from '@angular/core';
import { HttpClient, HttpRequest } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';

import { Customer } from './customer';

@Injectable()
export class CustomerService {

  private baseUrl = 'http://localhost:8080/api/customers';

  constructor(private http: HttpClient) { }

  getCustomer(id: string): Observable<Object> {
    return this.http.get(`${this.baseUrl}/${id}`);
  }

  createCustomer(customer: Object): Observable<Object> {
    return this.http.post(`${this.baseUrl}` + `/create`, customer);
  }

  updateCustomer(id: string, value: any): Observable<Object> {
    return this.http.put(`${this.baseUrl}/${id}`, value);
  }

  deleteCustomer(id: string): Observable<any> {
    return this.http.delete(`${this.baseUrl}/${id}`, { responseType: 'text' });
  }

  getCustomersList(query = {}): Observable<any> {
    return this.http.get(`${this.baseUrl}`);
  }

  deleteAll(): Observable<any> {
    return this.http.delete(`${this.baseUrl}` + `/delete`, { responseType: 'text' });
  }
}
2.2.4 Components

– CustomerDetailsComponent:

import { Component, OnInit, Input } from '@angular/core';

import { CustomerService } from '../customer.service';
import { Customer } from '../customer';

import { CustomersListComponent } from '../customers-list/customers-list.component';

@Component({
  selector: 'customer-details',
  templateUrl: './customer-details.component.html',
  styleUrls: ['./customer-details.component.css']
})
export class CustomerDetailsComponent implements OnInit {

  @Input() customer: Customer;

  constructor(private customerService: CustomerService, private listComponent: CustomersListComponent) { }

  ngOnInit() {
  }

  updateActive(isActive: boolean) {
    this.customerService.updateCustomer(this.customer.id,
      { name: this.customer.name, age: this.customer.age, active: isActive })
      .subscribe(
      data => {
        console.log(data);
        this.customer = data as Customer;
      },
      error => console.log(error));
  }

  deleteCustomer() {
    this.customerService.deleteCustomer(this.customer.id)
      .subscribe(
      data => {
        console.log(data);
        this.listComponent.reloadData();
      },
      error => console.log(error));
  }

}
<div *ngIf="customer">
	<div>
		<label>Name: </label> {{customer.name}}
	</div>
	<div>
		<label>Age: </label> {{customer.age}}
	</div>
	<div>
		<label>Active: </label> {{customer.active}}
	</div>

	<span class="button is-small btn-primary" *ngIf='customer.active' (click)='updateActive(false)'>Inactive</span>

	<span class="button is-small btn-primary" *ngIf='!customer.active' (click)='updateActive(true)'>Active</span>

	<span class="button is-small btn-danger" (click)='deleteCustomer()'>Delete</span>

	<hr/>
</div>

– CustomersListComponent:

import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs/Observable';

import { CustomerService } from '../customer.service';
import { Customer } from '../customer';

@Component({
  selector: 'customers-list',
  templateUrl: './customers-list.component.html',
  styleUrls: ['./customers-list.component.css']
})
export class CustomersListComponent implements OnInit {

  customers: Observable<Customer[]>;

  constructor(private customerService: CustomerService) {

  }

  ngOnInit() {
    this.reloadData();
  }

  deleteCustomers() {
    this.customerService.deleteAll()
      .subscribe(
      data => {
        console.log(data);
        this.reloadData();
      },
      error => console.log('ERROR: ' + error));
  }

  reloadData() {
    this.customers = this.customerService.getCustomersList();
  }
}
<h1>Customers</h1>

<div *ngFor="let customer of customers | async" style="width: 300px;">
	<customer-details [customer]='customer'></customer-details>
</div>

<div>
	<button type="button" class="button btn-danger" (click)='deleteCustomers()'>Delete All</button>
</div>

– CreateCustomerComponent:

import { Component, OnInit } from '@angular/core';
import { FormsModule } from '@angular/forms';

import { Customer } from '../customer';
import { CustomerService } from '../customer.service';

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

  customer: Customer = new Customer();
  submitted = false;

  constructor(private customerService: CustomerService) { }

  ngOnInit() {
  }

  newCustomer(): void {
    this.submitted = false;
    this.customer = new Customer();
  }

  save() {
    this.customerService.createCustomer(this.customer)
      .subscribe(data => console.log(data), error => console.log(error));
    this.customer = new Customer();
  }

  onSubmit() {
    this.submitted = true;
    this.save();
  }
}
<h3>Create Customer</h3>
<div [hidden]="submitted" style="width: 300px;">
	<form (ngSubmit)="onSubmit()">
		<div class="form-group">
			<label for="name">Name</label> <input type="text"
				class="form-control" id="name" required [(ngModel)]="customer.name"
				name="name">
		</div>

		<div class="form-group">
			<label for="age">Age</label> <input type="text"
				class="form-control" id="age" required [(ngModel)]="customer.age"
				name="age">
		</div>

		<button type="submit" class="btn btn-success">Submit</button>
	</form>
</div>

<div [hidden]="!submitted">
	<h4>You submitted successfully!</h4>
	<button class="btn btn-success" (click)="newCustomer()">Add</button>
</div>
2.2.5 AppRoutingModule

import { CreateCustomerComponent } from './customers/create-customer/create-customer.component';
import { CustomersListComponent } from './customers/customers-list/customers-list.component';

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

const routes: Routes = [
  { path: '', redirectTo: 'customers', pathMatch: 'full' },
  { path: 'customers', component: CustomersListComponent },
  { path: 'add', component: CreateCustomerComponent },
];

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

export class AppRoutingModule { }
2.2.6 App Component

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})

export class AppComponent {
  title = 'JavaSampleApproach';
  description = 'Angular4-MongoDB';

  constructor() { }

}
<div class="container-fluid">
	<div style="color: blue;">
		<h1>{{title}}</h1>
		<h3>{{description}}</h3>
	</div>

	<nav>
		<a routerLink="customers" class="btn btn-primary active" role="button" routerLinkActive="active">Customers</a>
		<a routerLink="add" class="btn btn-primary active" role="button" routerLinkActive="active">Add</a>
	</nav>
	<router-outlet></router-outlet>
</div>

3. Run & Check Result

Build and Run Spring Boot project with commandlines: mvn clean install and mvn spring-boot:run.
– Run the Angular App with command: npm start.

– Open browser for url http://localhost:4200/:
Add Customer(Jack,27):
angular4-springdata-mongodb-result-add-customer

Add more customers, check MongoDB collection:
angular4-springdata-mongodb-result-show-customers-cmd

Choose tab Customers:
angular4-springdata-mongodb-result-show-customers

Update active status by click on Active label:
angular4-springdata-mongodb-result-update-customer

Delete a customer (Katherin):
angular4-springdata-mongodb-result-delete-customer

Check MongoDB collection again, Jack‘s active status has changed, and Katherin data has been deleted:
angular4-springdata-mongodb-result-after-customers-cmd

Click Delete All button:
angular4-springdata-mongodb-result-delete-all-customers

IV. Source Code

SpringBootAngular4MongoDB
Angular4MongoDB

Leave a Reply

Your email address will not be published. Required fields are marked *