In this tutorial, we show you Angular 8 Http Client & Spring Boot Server example that uses Spring JPA to do CRUD with MySQL and Angular 8 as a front-end technology to make HTTP request and receive response.
Related Post:
– How to use Spring JPA MySQL | Spring Boot
– How to install Angular 8 locally
Contents
Technologies
– Java 8
– Maven 3.3.9
– Spring Tool Suite – Version 3.8.4.RELEASE
– Spring Boot: 2.1.3.RELEASE
– Angular 8
– RxJS 6
Video
Spring Boot + Angular 8 + MySQL example Overview
Spring Boot RestApis Server

Our Spring Boot Server can work with MySQL Database and provides APIs:
- GET
/customers/
: get all customers - GET
/customers/[id]
: get a customer byid
- GET
/customers/age/[age]
: find all customers byage
- POST
/customers/
: save a customer - PUT
/customers/[id]
: update a customer byid
- DELETE
/customers/[id]
: delete a customer byid
- DELETE
/customers/
: delete all customers
Angular 8 Client
The image below shows overview about Angular Components that we will create:

Implement Spring Boot Server
Project Structure

– Customer class corresponds to entity and table customer.
– CustomerRepository is an interface extends CrudRepository, 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 JPA properties in application.properties
– Dependencies for Spring Boot and MySQL in pom.xml
We will keep the tutorial as simple as possible, so for post with Spring JPA details, you can visit:
How to use Spring JPA MySQL | Spring Boot
Dependencies
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
Data Model
model/Customer.java
package com.grokonez.spring.restapi.mysql.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "customer")
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
@Column(name = "name")
private String name;
@Column(name = "age")
private int age;
@Column(name = "active")
private boolean active;
public Customer() {
}
public Customer(String name, int age) {
this.name = name;
this.age = age;
this.active = false;
}
public long 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 + "]";
}
}
JPA Repository
repo/CustomerRepository.java
package com.grokonez.spring.restapi.mysql.repo;
import java.util.List;
import org.springframework.data.repository.CrudRepository;
import com.grokonez.spring.restapi.mysql.model.Customer;
public interface CustomerRepository extends CrudRepository {
List findByAge(int age);
}
REST Controller
controller/CustomerController.java
package com.grokonez.spring.restapi.mysql.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.grokonez.spring.restapi.mysql.model.Customer;
import com.grokonez.spring.restapi.mysql.repo.CustomerRepository;
@CrossOrigin(origins = "http://localhost:4200")
@RestController
@RequestMapping("/api")
public class CustomerController {
@Autowired
CustomerRepository repository;
@GetMapping("/customers")
public ResponseEntity> getAllCustomers() {
List customers = new ArrayList<>();
try {
repository.findAll().forEach(customers::add);
if (customers.isEmpty()) {
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<>(customers, HttpStatus.OK);
} catch (Exception e) {
return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@GetMapping("/customers/{id}")
public ResponseEntity getCustomerById(@PathVariable("id") long id) {
Optional customerData = repository.findById(id);
if (customerData.isPresent()) {
return new ResponseEntity<>(customerData.get(), HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
@PostMapping(value = "/customers")
public ResponseEntity postCustomer(@RequestBody Customer customer) {
try {
Customer _customer = repository.save(new Customer(customer.getName(), customer.getAge()));
return new ResponseEntity<>(_customer, HttpStatus.CREATED);
} catch (Exception e) {
return new ResponseEntity<>(null, HttpStatus.EXPECTATION_FAILED);
}
}
@DeleteMapping("/customers/{id}")
public ResponseEntity deleteCustomer(@PathVariable("id") long id) {
try {
repository.deleteById(id);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
} catch (Exception e) {
return new ResponseEntity<>(HttpStatus.EXPECTATION_FAILED);
}
}
@DeleteMapping("/customers")
public ResponseEntity deleteAllCustomers() {
try {
repository.deleteAll();
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
} catch (Exception e) {
return new ResponseEntity<>(HttpStatus.EXPECTATION_FAILED);
}
}
@GetMapping(value = "customers/age/{age}")
public ResponseEntity> findByAge(@PathVariable int age) {
try {
List customers = repository.findByAge(age);
if (customers.isEmpty()) {
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<>(customers, HttpStatus.OK);
} catch (Exception e) {
return new ResponseEntity<>(HttpStatus.EXPECTATION_FAILED);
}
}
@PutMapping("/customers/{id}")
public ResponseEntity updateCustomer(@PathVariable("id") long id, @RequestBody Customer customer) {
Optional 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);
}
}
}
Configuration for Spring Datasource & JPA properties
application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/testdb?useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
spring.jpa.generate-ddl=true
Implement Angular 8 HTTP Client
Project Structure

We have:
– 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
– app-routing.module.ts: Routing configuration
Create Service & Components
On Project folder, 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
App Module
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { AppRoutingModule } from './app-routing.module';
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';
@NgModule({
declarations: [
AppComponent,
CreateCustomerComponent,
CustomerDetailsComponent,
CustomersListComponent,
SearchCustomersComponent
],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule,
HttpClientModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Add Router
app-routing.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } 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 { }
AppComponent HTML for routing:
app.component.html
<div style="padding: 20px;">
<h1 style="color: blue">grokonez.com</h1>
<h3>{{title}}</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>
Data Model
Create new file named customer.ts:
export class Customer {
id: number;
name: string;
age: number;
active: boolean;
}
Data Service
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 {
return this.http.get(`${this.baseUrl}/${id}`);
}
createCustomer(customer: any): Observable {
return this.http.post(this.baseUrl, customer);
}
updateCustomer(id: number, value: any): Observable {
return this.http.put(`${this.baseUrl}/${id}`, value);
}
deleteCustomer(id: number): Observable {
return this.http.delete(`${this.baseUrl}/${id}`);
}
getCustomersList(): Observable {
return this.http.get(this.baseUrl);
}
getCustomersByAge(age: number): Observable {
return this.http.get(`${this.baseUrl}/age/${age}`);
}
deleteAll(): Observable {
return this.http.delete(this.baseUrl);
}
}
Components
List of Customers
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: 'app-customers-list',
templateUrl: './customers-list.component.html',
styleUrls: ['./customers-list.component.css']
})
export class CustomersListComponent implements OnInit {
customers: Observable;
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
<h3>Customers</h3>
<div *ngFor="let customer of customers | async" style="width: 300px;">
<app-customer-details [customer]='customer'></app-customer-details>
</div>
<div>
<button type="button" class="button btn-danger" (click)='deleteCustomers()'>Delete All</button>
</div>
Customer Details
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: 'app-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>
Create Customer
create-customer/create-customer.component.ts
import { Component, OnInit } from '@angular/core';
import { Customer } from '../customer';
import { CustomerService } from '../customer.service';
@Component({
selector: 'app-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);
this.submitted = true;
},
error => console.log(error));
this.customer = new Customer();
}
onSubmit() {
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>
Search Customers
search-customers/search-customers.component.ts
import { Component, OnInit } from '@angular/core';
import { Customer } from '../customer';
import { CustomerService } from '../customer.service';
@Component({
selector: 'app-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.customers = [];
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>
Run & Check Results
– 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:

Source Code
– server-SpringBootRestApiMySQL
– client-Angular8SpringBoot
Last updated on March 18, 2021.
Can you please include your .css styles? Without the styles, the page looks ugly.
Hi Vicent, it’s bootstrap, inside index.html file (source code). 🙂
Hi, I’m new to angular and spring. I have a background in jsp and java. When creating the client and server is it better to split the two into to project or can you put them both under one?
I had started one and made them both under the same project then I found this example to for how to hook into database and noticed you have them separate.
BTW based on the example here I will be definitely be visiting your site more often.
Hello,in my application.properties all my spring.datasource… are unused property and i have a java.sql.SQLSyntaxErrorException: Unknown database ‘testdb’
it’s a problem with my sql connection? Thanks.Julien
You should create a new database named “testdb”, and create a table named “customer” where you can find relevant columns in file “Customer.java”
Thank you for the great tutorial. I have a question, If I use abstract class for model how can I handle controller and other stuff?
hi please how can i add update customer ?