In this tutorial, we show you Angular 6 Http Client & Spring Boot Server example that uses Spring Data to do CRUD with Cassandra and Angular 6 as a front-end technology to make request and receive response.
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
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 CassandraRepository, 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 Cassandra 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.0 Set up Cassandra
Open Cassandra CQL Shell:
– Create Cassandra keyspace with name javasampleapproach:
create keyspace javasampleapproach with replication={'class':'SimpleStrategy', 'replication_factor':1};
– Create customer table for javasampleapproach keyspace:
use javasampleapproach; CREATE TABLE customer( id timeuuid PRIMARY KEY, name text, age int, active boolean );
2.1 Spring Boot Server
2.1.1 Dependency
org.springframework.boot spring-boot-starter-data-cassandra org.springframework.boot spring-boot-starter-web
2.1.2 Customer – Data Model
model/Customer.java
package com.javasampleapproach.springrest.cassandra.model; import java.util.UUID; import org.springframework.data.cassandra.core.mapping.PrimaryKey; import org.springframework.data.cassandra.core.mapping.Table; @Table public class Customer { @PrimaryKey private UUID id; private String name; private int age; private boolean active; public Customer() { } public UUID getId() { return id; } public void setId(UUID id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = 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.cassandra.repo; import java.util.List; import java.util.UUID; import org.springframework.data.cassandra.repository.CassandraRepository; import com.javasampleapproach.springrest.cassandra.model.Customer; public interface CustomerRepository extends CassandraRepository{ List findByAge(int age); }
2.1.4 REST Controller
controller/CustomerController.java
package com.javasampleapproach.springrest.cassandra.controller; import java.util.List; import java.util.Optional; import java.util.UUID; 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.datastax.driver.core.utils.UUIDs; import com.javasampleapproach.springrest.cassandra.model.Customer; import com.javasampleapproach.springrest.cassandra.repo.CustomerRepository; @CrossOrigin(origins = "http://localhost:4200") @RestController @RequestMapping("/api") public class CustomerController { @Autowired CustomerRepository repository; @GetMapping("/customers") public ListgetAllCustomers() { System.out.println("Get all Customers..."); return repository.findAll(); } @PostMapping("/customers/create") public ResponseEntity postCustomer(@RequestBody Customer customer) { System.out.println("Create Customer: " + customer.getName() + "..."); customer.setId(UUIDs.timeBased()); Customer _customer = repository.save(customer); return new ResponseEntity<>(_customer, HttpStatus.OK); } @DeleteMapping("/customers/{id}") public ResponseEntity deleteCustomer(@PathVariable("id") UUID 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("customers/age/{age}") public List findByAge(@PathVariable int age) { List customers = repository.findByAge(age); return customers; } @PutMapping("/customers/{id}") public ResponseEntity updateCustomer(@PathVariable("id") UUID 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.data.cassandra.keyspace-name=javasampleapproach spring.data.cassandra.contact-points=127.0.0.1 spring.data.cassandra.port=9042
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
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}}
– 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:
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
– SpringRestCassandra-Server