In this tutorial, we show you Angular 6 Http Client & Spring Boot Server example that uses Spring Data to do CRUD with MongoDb and Angular 6 as a front-end technology to make request and receive response.
Related Posts:
– Spring Boot + Angular 6 example | Spring Data JPA + REST + PostgreSQL CRUD example
– Spring Boot + Angular 6 example | Spring Data JPA + REST + MySQL CRUD example
– Angular 6 HttpClient + Spring Boot + MariaDB example | Spring Data JPA + RestAPIs CRUD example
– Spring Boot + Angular 6 example | Spring Data + REST + Cassandra CRUD example
Contents
I. Technologies
– Java 1.8
– Maven 3.3.9
– Spring Tool Suite – Version 3.8.4.RELEASE
– Spring Boot: 2.0.3.RELEASE
– Angular 6
– RxJS 6
II. Overview
Demo
1. Spring Boot Server
2. Angular 6 Client
III. Practice
1. Project Structure
1.1 Spring Boot Server
– Customer class corresponds to entity and table customer.
– CustomerRepository 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: getAllCustomers
, postCustomer
, deleteCustomer
, deleteAllCustomers
, findByAge
, updateCustomer
.
– Configuration for Spring Datasource and Spring Data properties in application.properties
– Dependencies for Spring Boot and MongoDb in pom.xml
1.2 Angular 6 Client
In this example, we focus on:
– 4 components: customers-list, customer-details, create-customer, search-customer.
– 3 modules: FormsModule, HttpClientModule, AppRoutingModule.
– customer.ts: class Customer (id, firstName, lastName)
– customer.service.ts: Service for Http Client 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
model/Customer.java
package com.javasampleapproach.springrest.mongodb.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 Repository
repo/CustomerRepository.java
package com.javasampleapproach.springrest.mongodb.repo; import java.util.List; import org.springframework.data.mongodb.repository.MongoRepository; import com.javasampleapproach.springrest.mongodb.model.Customer; public interface CustomerRepository extends MongoRepository<Customer, String>{ List<Customer> findByAge(int age); } |
2.1.4 REST Controller
controller/CustomerController.java
package com.javasampleapproach.springrest.mongodb.controller; import java.util.ArrayList; import java.util.List; import java.util.Optional; 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.springrest.mongodb.model.Customer; import com.javasampleapproach.springrest.mongodb.repo.CustomerRepository; @CrossOrigin(origins = "http://localhost:4200") @RestController @RequestMapping("/api") public class CustomerController { @Autowired CustomerRepository repository; @GetMapping("/customers") public List<Customer> getAllCustomers() { System.out.println("Get all Customers..."); List<Customer> customers = new ArrayList<>(); repository.findAll().forEach(customers::add); return customers; } @PostMapping("/customers/create") public Customer postCustomer(@RequestBody Customer customer) { Customer _customer = repository.save(new Customer(customer.getName(), customer.getAge())); return _customer; } @DeleteMapping("/customers/{id}") public ResponseEntity<String> deleteCustomer(@PathVariable("id") String id) { System.out.println("Delete Customer with ID = " + id + "..."); repository.deleteById(id); return new ResponseEntity<>("Customer has been deleted!", HttpStatus.OK); } @DeleteMapping("/customers/delete") public ResponseEntity<String> deleteAllCustomers() { System.out.println("Delete All Customers..."); repository.deleteAll(); return new ResponseEntity<>("All customers have been deleted!", HttpStatus.OK); } @GetMapping("customers/age/{age}") public List<Customer> findByAge(@PathVariable int age) { List<Customer> customers = repository.findByAge(age); return customers; } @PutMapping("/customers/{id}") public ResponseEntity<Customer> updateCustomer(@PathVariable("id") String id, @RequestBody Customer customer) { System.out.println("Update Customer with ID = " + id + "..."); Optional<Customer> customerData = repository.findById(id); if (customerData.isPresent()) { Customer _customer = customerData.get(); _customer.setName(customer.getName()); _customer.setAge(customer.getAge()); _customer.setActive(customer.isActive()); return new ResponseEntity<>(repository.save(_customer), HttpStatus.OK); } else { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } } } |
2.1.5 Configuration for Spring Datasource & Data MongoDb properties
application.properties
spring.data.mongodb.database=jsa_mongodb spring.data.mongodb.port=27017 |
2.2 Angular 6 Client
2.2.0 Create Service & Components
Run commands below:
– ng g s customer
– ng g c create-customer
– ng g c customer-details
– ng g c customers-list
– ng g c search-customers
On each Component selector, delete app-
prefix, then change tslint.json rules
– "component-selector"
to false.
2.2.1 Model
customer.ts
export class Customer { id: number; name: string; age: number; active: boolean; } |
2.2.2 CustomerService
customer.service.ts
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class CustomerService { private baseUrl = 'http://localhost:8080/api/customers'; constructor(private http: HttpClient) { } getCustomer(id: number): Observable<Object> { return this.http.get(`${this.baseUrl}/${id}`); } createCustomer(customer: Object): Observable<Object> { return this.http.post(`${this.baseUrl}` + `/create`, customer); } updateCustomer(id: number, value: any): Observable<Object> { return this.http.put(`${this.baseUrl}/${id}`, value); } deleteCustomer(id: number): Observable<any> { return this.http.delete(`${this.baseUrl}/${id}`, { responseType: 'text' }); } getCustomersList(): Observable<any> { return this.http.get(`${this.baseUrl}`); } getCustomersByAge(age: number): Observable<any> { return this.http.get(`${this.baseUrl}/age/${age}`); } deleteAll(): Observable<any> { return this.http.delete(`${this.baseUrl}` + `/delete`, { responseType: 'text' }); } } |
2.2.3 Components
– CustomerDetailsComponent:
customer-details/customer-details.component.ts
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)); } } |
customer-details/customer-details.component.html
<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:
customers-list/customers-list.component.ts
import { Component, OnInit } from '@angular/core'; import { Observable } from 'rxjs'; 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(); } } |
customers-list/customers-list.component.html
<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:
create-customer/create-customer.component.ts
import { Component, OnInit } from '@angular/core'; 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(); } } |
create-customer/create-customer.component.html
<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> |
– SearchCustomersComponent:
search-customers/search-customers.component.ts
import { Component, OnInit } from '@angular/core'; import { Customer } from '../customer'; import { CustomerService } from '../customer.service'; @Component({ selector: 'search-customers', templateUrl: './search-customers.component.html', styleUrls: ['./search-customers.component.css'] }) export class SearchCustomersComponent implements OnInit { age: number; customers: Customer[]; constructor(private dataService: CustomerService) { } ngOnInit() { this.age = 0; } private searchCustomers() { this.dataService.getCustomersByAge(this.age) .subscribe(customers => this.customers = customers); } onSubmit() { this.searchCustomers(); } } |
search-customers/search-customers.component.html
<h3>Find By Age</h3> <div style="width: 300px;"> <form (ngSubmit)="onSubmit()"> <div class="form-group"> <label for="lastname">Age</label> <input type="text" class="form-control" id="age" required [(ngModel)]="age" name="age"> </div> <div class="btn-group"> <button type="submit" class="btn btn-success">Submit</button> </div> </form> </div> <ul> <li *ngFor="let customer of customers"> <h4>{{customer.id}} - {{customer.name}} {{customer.age}}</h4> </li> </ul> |
2.2.4 AppRoutingModule
app-routing.module.ts
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { CustomersListComponent } from './customers-list/customers-list.component'; import { CreateCustomerComponent } from './create-customer/create-customer.component'; import { SearchCustomersComponent } from './search-customers/search-customers.component'; const routes: Routes = [ { path: '', redirectTo: 'customer', pathMatch: 'full' }, { path: 'customer', component: CustomersListComponent }, { path: 'add', component: CreateCustomerComponent }, { path: 'findbyage', component: SearchCustomersComponent }, ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { } |
And AppComponent HTML for routing:
app.component.html
<div style="padding: 20px;"> <h1 style="color: blue">{{title}}</h1> <h3>{{description}}</h3> <nav> <a routerLink="customer" 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> <a routerLink="findbyage" class="btn btn-primary active" role="button" routerLinkActive="active">Search</a> </nav> <router-outlet></router-outlet> </div> |
2.2.5 AppModule
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 { CreateCustomerComponent } from './create-customer/create-customer.component'; import { CustomerDetailsComponent } from './customer-details/customer-details.component'; import { CustomersListComponent } from './customers-list/customers-list.component'; import { SearchCustomersComponent } from './search-customers/search-customers.component'; import { AppRoutingModule } from './app-routing.module'; import { HttpClientModule } from '@angular/common/http'; @NgModule({ declarations: [ AppComponent, CreateCustomerComponent, CustomerDetailsComponent, CustomersListComponent, SearchCustomersComponent ], imports: [ BrowserModule, FormsModule, AppRoutingModule, HttpClientModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { } |
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: ng serve
.
– Open browser for url http://localhost:4200/
:
Add Customer:
Show Customers:
Click on Active button to update Customer status:
Search Customers by Age:
Delete a Customer:
Delete All Customers:
IV. Source Code
– Angular6SpringBoot-Client
– SpringRestMongoDb-Server
Last updated on February 7, 2020.
Perfeito tutorial completo !
Thank you for providing a straightforward WORKING example of Angular+Java. There are many other tutorials and examples that describe similar configurations, but they are often missing complete descriptions, cluttered with ancillary technologies, or don’t actually work as described.
Hi Kurt Risser,
Thank you for your praise, it gives us more motivation to work harder and make more tutorials.
Best Regards,
grokonez.
Good Spring boot article! Thanks!
I’m new in angular and angular portion of this project not work for me. Can you provide some detail how i do that. If i want to create by my self not clone your given link? And customer.ts not generated by default any of container generated command. so please provide some guidance.