In this tutorial, we show you Angular 13 Http Client & Spring Boot Server example that uses Spring JPA to do CRUD with MariaDB and Angular 13 as a front-end technology to make request and receive response.
Related Posts:
– Spring Boot + Angular 13 example | Spring Data JPA + REST + MySQL CRUD example
– Spring Boot + Angular 13 example | Spring Data JPA + REST + PostgreSQL CRUD example
– Spring Boot + Angular 13 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 13
– RxJS 6
– MariaDB
II. Overview
1. Spring Boot Server
2. Angular 13 Client
III. Practice
1. Project Structure
1.1 Spring Boot Server
– 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 13 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-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 13 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:
Show Customers:
Click on Active button to update Customer status:
Search Customers by Age:
Delete a Customer:
Delete All Customers:
IV. Source Code
– SpringBootRestAPIsMariadb
– Angular6SpringBoot-Client
640123 953252We keep your page. Watch it offline again soon. Really intriguing post. 687547
833245 34938Your writing is fine and gives food for thought. I hope that Ill have a lot more time to read your articles . Regards. I wish you that you regularly publish new texts and invite you to greet me 773457
828653 917509Thanks for this superb. I was wondering whether you were preparing of writing related posts to this 1. .Keep up the excellent articles! 460023
The subsequent time I learn a blog, I hope that it doesnt disappoint me as much as this one. I mean, I do know it was my option to read, but I really thought youd have something attention-grabbing to say. All I hear is a bunch of whining about something that you could possibly repair should you werent too busy on the lookout for attention.
You need to be a part of a contest for one of the most useful blogs on the internet. I am going to recommend this web site!
Aw, this is a very nice post. In concept I would like to set up writing this way moreover – taking time and actual effort to manufacture a great article… but what / things I say… I procrastinate alot through no indicates seem to go carried out.
Hola i would really love to subscribe and read your blog posts !
Sorry for that huge review, but I am actually loving the new Zune, and hope this, along with the outstanding reviews some other people have written, will help you determine if it’s the appropriate selection for you.
Thanks for the suggestions you have shared here. Something else I would like to express is that computer system memory specifications generally rise along with other breakthroughs in the technological know-how. For instance, when new generations of cpus are brought to the market, there is certainly usually an equivalent increase in the scale calls for of all pc memory and hard drive room. This is because the software program operated by these processors will inevitably surge in power to benefit from the new know-how.
Hi my friend! I want to say that this post is amazing, great written and include almost all vital infos. I would like to see more posts like this .
You made some first rate factors there. I regarded on the web for the problem and located most people will go together with with your website.
Im excited to discover this web site. I need to to thank you for ones time for this wonderful read!! I definitely savored every bit of it and I have you bookmarked to look at new information in your web site.
I was extremely pleased to discover this page. I want to to thank you for ones time due to this wonderful read!! I definitely appreciated every part of it and I have you bookmarked to look at new information on your web site.
399846 941158There is noticeably a bundle comprehend this. I suppose you produced specific nice points in functions also. 767353
The Marvel Cinematic Universe is a series of superhero movies based upon personalities that show up in comic books published by Marvel Comic books. The MCU is the common world in which every one of the films are established.|The initial film launched was Iron Male in 2008, followed by The Incredible Hunk, Iron Man, Thor, Captain America: The First Avenger, and afterwards Marvel’s The Avengers. Every one of these motion pictures were consulted with important recognition as well as ticket office success.