Angular 10 SpringBoot MariaDB CRUD Example

In this tutorial, we show you Angular 10 Http Client & Spring Boot Server example that uses Spring JPA to do CRUD with MariaDB and Angular 10 as a front-end technology to make request and receive response.

Related Posts:
Spring Boot + Angular 10 example | Spring Data JPA + REST + MySQL CRUD example
Spring Boot + Angular 10 example | Spring Data JPA + REST + PostgreSQL CRUD example
Spring Boot + Angular 10 example | Spring Data + REST + Cassandra CRUD example
How to use Spring JPA with PostgreSQL | Spring Boot

Related Pages:

I. Technologies

– Java 1.8
– Maven 3.3.9
– Spring Tool Suite – Version 3.9.4.RELEASE
– Spring Boot: 2.0.4.RELEASE
– Angular 10
– RxJS 6
– MariaDB

II. Overview

spring-boot-angular-6-httpclient-spring-rest-api-data-mariadb + angular-http-service-architecture

1. Spring Boot Server

spring-boot-angular-6-httpclient-spring-rest-api-data-mariadb + spring-server-architecture

2. Angular 10 Client

spring-boot-angular-6-httpclient-spring-rest-api-data-mariadb + angular-client-architecture

III. Practice

1. Project Structure

1.1 Spring Boot Server

spring-boot-angular-6-httpclient-spring-rest-api-data-mariadb + springboot-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 MariaDB in pom.xml

1.2 Angular 10 Client

spring-boot-angular-6-httpclient-spring-rest-api-data-mariadb + angular-client-structure

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-jpa</artifactId>
</dependency>

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.mariadb.jdbc</groupId>
    <artifactId>mariadb-java-client</artifactId>
</dependency>
2.1.2 Customer – Data Model

model/Customer.java


package com.ozenero.springrest.mariadb.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 + "]";
	}
}
2.1.3 JPA Repository

repo/CustomerRepository.java


package com.ozenero.springrest.mariadb.repo;

import java.util.List;

import org.springframework.data.repository.CrudRepository;

import com.ozenero.springrest.mariadb.model.Customer;

public interface CustomerRepository extends CrudRepository {
	List findByAge(int age);
}
2.1.4 REST Controller

controller/CustomerController.java


package com.ozenero.springrest.mariadb.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.ozenero.springrest.mariadb.model.Customer;
import com.ozenero.springrest.mariadb.repo.CustomerRepository;

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

	@Autowired
	CustomerRepository repository;

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

		List customers = new ArrayList<>();
		repository.findAll().forEach(customers::add);

		return customers;
	}

	@PostMapping(value = "/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 deleteCustomer(@PathVariable("id") long 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 deleteAllCustomers() {
		System.out.println("Delete All Customers...");

		repository.deleteAll();

		return new ResponseEntity<>("All customers have been deleted!", HttpStatus.OK);
	}

	@GetMapping(value = "customers/age/{age}")
	public List findByAge(@PathVariable int age) {

		List customers = repository.findByAge(age);
		return customers;
	}

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

		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);
		}
	}
}
2.1.5 Configuration for Spring Datasource & JPA properties

application.properties


spring.datasource.url=jdbc:mariadb://localhost:3306/gkzdb
spring.datasource.username=root
spring.datasource.password=12345
spring.jpa.generate-ddl=true

2.2 Angular 10 Client

2.2.0 Create Service & Components

Run commands below:
ng g s Customer
ng g c CreateCustomer
ng g c CustomerDetails
ng g c CustomersList
ng g c SearchCustomers
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;

  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:

spring-boot-angular-6-httpclient-spring-rest-api-data-mariadb-add-customer

Show Customers:

spring-boot-angular-6-httpclient-spring-rest-api-data-mariadb + show-customers

Click on Active button to update Customer status:

spring-boot-angular-6-httpclient-spring-rest-api-data-mariadb +update-customers

Search Customers by Age:

spring-boot-angular-6-httpclient-spring-rest-api-data-mariadb + search-customers

Delete a Customer:

spring-boot-angular-6-httpclient-spring-rest-api-data-mariadb + delete-customer

Delete All Customers:

spring-boot-angular-6-httpclient-spring-rest-api-data-mariadb + delete-all-customers

IV. Source Code

SpringBootRestAPIsMariadb
Angular6SpringBoot-Client

14 thoughts on “Angular 10 SpringBoot MariaDB CRUD Example”

  1. 389576 605511Youre so cool! I dont suppose Ive learn anything like this before. So good to locate any person with some authentic thoughts on this subject. realy thank you for starting this up. this web site is something that is wanted on the internet, someone with slightly bit originality. helpful job for bringing something new to the internet! 821471

  2. 731466 329671There is an ending. Just remember that I meant for this to be an art game. I do feel like I spent an inordinate amount of time on the more traditional gameplay elements, which may possibly make the meaning of the game a bit unclear. Should you mess around with it though, you will uncover it. 683032

  3. 919468 365910I enjoyed reading your pleasant web site. I see you offer priceless info. stumbled into this website by chance but Im positive glad I clicked on that link. You certainly answered all the questions Ive been dying to answer for some time now. Will surely come back for far more of this. 882639

  4. I actually still cannot quite feel that I could become one of those reading the important guidelines found on your web blog. My family and I are truly thankful for your generosity and for providing me potential to pursue our chosen career path. Many thanks for the important information I obtained from your web site.

  5. Nice post. I understand some thing harder on various blogs everyday. Most commonly it is stimulating to learn to read content using their company writers and exercise something from their store. I’d opt to use some while using the content in my blog regardless of whether you don’t mind. Natually I’ll give you a link on your own web blog. Thank you for sharing.

  6. I enjoy you because of your whole work on this blog. My daughter loves engaging in research and it’s really simple to grasp why. Most people know all of the compelling way you give vital items by means of the web blog and invigorate participation from the others on that subject matter while our own girl is always discovering a whole lot. Take pleasure in the remaining portion of the year. You’re carrying out a powerful job.

  7. 898763 593952Take a peek at the following guidelines what follows discover perfect way to follow such a mainly because you structure your small business this afternoon. earn cash 471153

  8. 517725 348982Youre so cool! I dont suppose Ive read anything in this way before. So good to locate somebody by original thoughts on this topic. realy thanks for beginning this up. this fabulous web site is one thing that is needed on the internet, a person with a bit of originality. beneficial project for bringing a new challenge towards internet! 500179

Leave a Reply

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