Kotlin Spring Boot + Angular 6 CRUD HttpClient + MySQL example | Spring Data JPA + REST APIs example

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

Related Posts:
How to use Spring JPA MySQL | Spring Boot
Spring JPA + MySQL + AngularJS example | Spring Boot
Spring JPA Hibernate Many to Many – SpringBoot + PostgreSQL
Spring JPA Hibernate One to Many Relationship – SpringBoot + MySQL
Spring Boot + React Redux + MySQL CRUD example
Kotlin + SpringBoot JPA + MySQL- Save/retrieve Files/Images with @Lob annotation
Spring Security – JDBC Authentication – SpringBoot + MySQL + Bootstrap

Related pages:

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

kotlin-spring-boot-angular-6-crud-httpclient-spring-rest-api-data-mysql-crud-spring-jpa + angular-http-service-architecture

1. Spring Boot Server

kotlin-spring-boot-angular-6-crud-httpclient-spring-rest-api-data-mysql-crud-spring-jpa + spring-server-architecture

2. Angular 6 Client

kotlin-spring-boot-angular-6-crud-httpclient-spring-rest-api-data-mysql-crud-spring-jpa + angular-client-architecture

III. Practice

1. Project Structure

1.1 Spring Boot Server

Angular-6-Crud-HttpClient-Kotlin-SpringBoot-MySQL-CRUD-Spring-JPA +Kotlin-SpringBoot-project

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

1.2 Angular 6 Client

kotlin-spring-boot-angular-6-crud-httpclient-spring-rest-api-data-mysql-crud-spring-jpa + 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

	org.springframework.boot
	spring-boot-starter-data-jpa



	org.springframework.boot
	spring-boot-starter-web



	mysql
	mysql-connector-java
	runtime

2.1.2 Customer – Data Model

model/Customer.kt

package com.grokonez.springrest.mysql.model

import javax.persistence.Entity
import javax.persistence.Id
import javax.persistence.GeneratedValue
import javax.persistence.GenerationType
 
@Entity
class Customer(
		var name: String,
		var age: Int,
		var active: Boolean = false,
		@Id @GeneratedValue(strategy = GenerationType.AUTO)
		val id: Long = -1) {
	
	private constructor() : this("", -1)
	
	override fun toString(): String{
		return "Customer [id= + ${this.id} + , name= + ${this.name} + , age= + ${this.age} + , active= + ${this.active} + ]";
	}
}
2.1.3 JPA Repository

repo/CustomerRepository.kt

package com.grokonez.springrest.mysql.repo

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

import com.grokonez.springrest.mysql.model.Customer;

@Repository
interface CustomerRepository : CrudRepository {
	fun findByAge(age: Int): Iterable
}
2.1.4 REST Controller

controller/CustomerController.kt

package com.grokonez.springrest.mysql.controller

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.springrest.mysql.repo.CustomerRepository
import com.grokonez.springrest.mysql.model.Customer

@CrossOrigin(origins = arrayOf("http://localhost:4200"))
@RestController
@RequestMapping("/api")
class CustomerController {
	@Autowired
	lateinit var repository: CustomerRepository
	
	@GetMapping("/customers")
	fun findAll() = repository.findAll()
	
	@PostMapping("/customers/create")
	fun postCustomer(@RequestBody customer: Customer): Customer{
		return repository.save( Customer(customer.name, customer.age));
	}
	
	@DeleteMapping("/customers/{id}")
	fun deleteCustomer(@PathVariable("id") id: Long): ResponseEntity{
		println("Delete Customer with ID = " + id + "...");
		repository.deleteById(id);
		return ResponseEntity("Customer has been deleted!", HttpStatus.OK);
	}
	
	@DeleteMapping("/customers/delete")
	fun deleteAllCustomers(): ResponseEntity{
		println("Delete All Customers...");
		repository.deleteAll();
		return ResponseEntity("All customers have been deleted!", HttpStatus.OK);
	}
	
	@GetMapping("customers/age/{age}")
	fun findByAge(@PathVariable age: Int) = repository.findByAge(age);
 
	@PutMapping("/customers/{id}")
	fun updateCustomer(@PathVariable("id") id: Long, @RequestBody customer: Customer):  ResponseEntity {
		println("Update Customer with ID = " + id + "...");
 
		var customerData = repository.findById(id);
 
		if (customerData.isPresent()) {
			var _customer = customerData.get();
			_customer.name = customer.name;
			_customer.age = customer.age;
			_customer.active = customer.active;
			return ResponseEntity(repository.save(_customer), HttpStatus.OK);
		} else {
			return ResponseEntity(HttpStatus.NOT_FOUND);
		}
	}
}
2.1.5 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
2.2 Angular 6 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 {
    return this.http.get(`${this.baseUrl}/${id}`);
  }

  createCustomer(customer: Object): Observable {
    return this.http.post(`${this.baseUrl}` + `/create`, 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}`, { responseType: 'text' });
  }

  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}` + `/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

{{customer.name}}
{{customer.age}}
{{customer.active}}
Inactive Active Delete

– 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

Customers

– 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

Create Customer

You submitted successfully!

– 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

Find By Age

  • {{customer.id}} - {{customer.name}} {{customer.age}}

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

{{title}}

{{description}}

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:

kotlin-spring-boot-angular-6-crud-httpclient-spring-rest-api-data-mysql-crud-spring-jpa-add-customer

Show Customers:

kotlin-spring-boot-angular-6-crud-httpclient-spring-rest-api-data-mysql-crud-spring-jpa + show-customers

Click on Active button to update Customer status:

kotlin-spring-boot-angular-6-crud-httpclient-spring-rest-api-data-mysql-crud-spring-jpa +update-customers

Search Customers by Age:

kotlin-spring-boot-angular-6-crud-httpclient-spring-rest-api-data-mysql-crud-spring-jpa + search-customers

Delete a Customer:

kotlin-spring-boot-angular-6-crud-httpclient-spring-rest-api-data-mysql-crud-spring-jpa + delete-customer

Delete All Customers:

kotlin-spring-boot-angular-6-crud-httpclient-spring-rest-api-data-mysql-crud-spring-jpa + delete-all-customers

IV. Source Code

SpringKotlinRestAPIsMySQL
Angular6SpringBoot-Client



By grokonez | August 16, 2018.


Related Posts


2 thoughts on “Kotlin Spring Boot + Angular 6 CRUD HttpClient + MySQL example | Spring Data JPA + REST APIs example”

Got Something To Say:

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

*