Spring Boot + Angular 8 CRUD Example
Github Link: https://github.com/mehulk05/Spring-Boot-Angular-8-CRUD-Example
Github Link: https://github.com/mehulk05/Spring-Boot-Angular-8-CRUD-Example
Before Begining, I have learned and got the inspiration to write this article from Java Guides. You can refer that tutorial here
Introduction
A lot of people asking how angular can work with Spring Boot Application. Here is the tutorial in very simple language. In this article, I will show you how to develop a CRUD (create read update delete) web application using Angular 8 and Spring Boot. The application contains the Employee form which has the CRUD operations like add, view, delete, and update it. For the front end, we will use Angular and consume the service. Whereas the backend will be in spring Boot which will provide us some data
BackEnd Technology
- SpringBoot 2
- Hibernate 5
- Spring Data JPA
FrontEnd Technology
- Angular8
- Bootstrap
- Jquery
So We will be creating it in 5 parts
1. Creating SpringBoot project
2. Creating Rest API using Spring Boot
3. Create an Angular App
4. Creating Component, Service and Modal files in angular
5 Configuring App to run
1. Creating SpringBoot project
- 1.1 Create a Spring project
To create a spring boot project you can go to spring Initializer. You can begin with the default settings and generate a project and then unzip it and open in any IDE(preferrable Spring tool suite or Eclipse). Below is the image you can add the following dependency
- 1.2 Update POM.xml
Next step is you need to go to pom.xml in package structure and aa following dependencies
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.main</groupId>
<artifactId>Employee</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Employee</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</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>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- 1.3 Configure database properties
Configure your database to store values
spring.datasource.url = jdbc:mysql://localhost:3306/employeedb?useSSL=false
spring.datasource.username = yourchoice of user name //root
spring.datasource.password = your choice of password //root## Hibernate Properties
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto = update
2. Creating Rest API using Spring Boot
- Create employee
- Update Employee
- Delete Employee
- List Employee
- Get a single employee by its id
- 2.1 Create the entity class (Employee.java)
Here, we are creating an Entity/POJO (Plain Old Java Object) class. The code for employee.java can be found here on my repo
package mehulk05.springboot2.springboot2jpacrudexample.model;
import javax.persistence.Column;import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.GeneratedValue;
import javax.persistence.Entity;
import javax.persistence.GenerationType;
@Entity
@Table(name = "Emp")
public class Employee {
private long id;
private String fname;
private String lname;
private String email;
public Employee() {
}
public Employee(String firstName, String lastName, String emailId) {
this.fname= firstName;
this.lname= lastName;
this.email= emailId;
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
@Column(name = "first_name", nullable = false)
public String getFname() {
return fna;
}
public void setFirstName(String firstName) {
this.fname= firstName;
}
@Column(name = "last_name", nullable = false)
public String getLname() {
return lname;
}
public void setLastName(String lastName) {
this.lname= lastName;
}
@Column(name = "email_address", nullable = false)
public String getEmail() {
return email;
}
public void setEmailId(String emailId) {
this.email= emailId;
}
@Override
public String toString() {
return "Employee [id=" + id + ", first-Name=" + fname+ ", last-Name=" + lname+ ", email-Id=" + email
+ "]";
}
}
- 2.2 Create the DAO interface(EmployeeRepository.java)
Here, we are creating the DAO interface to perform database related operations.Below is GitHub link
package mehulk05.springboot2.springboot2jpacrudexample.repository;
import org.springframework.stereotype.Repository;
import org.springframework.data.jpa.repository.JpaRepository;
import mehulk05.springboot2.springboot2jpacrudexample.model.Employee;
@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long>{
}
- 2.3 Create the controller class
Here, we are creating the Controller class to make communication on a different path. Below is GitHub link
package mehulk05.springboot2.springboot2jpacrudexample.controller;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import mehulk05.springboot2.springboot2jpacrudexample.exception.ResourceNotFoundException;
import mehulk05.springboot2.springboot2jpacrudexample.model.Employee;
import mehulk05.springboot2.springboot2jpacrudexample.repository.EmployeeRepository;
@RestController @CrossOrigin(origins = "http://localhost:4200")
@RequestMapping("/api/path1")
public class EmployeeController {
@Autowired
private EmployeeRepository employeeRepository;
@GetMapping("/employee")
public List<Employee> getAllEmployees() {
return employeeRepository.findAll();
}
@GetMapping("/employees/{id}")
public ResponseEntity<Employee> getEmployeeById(@PathVariable(value = "id") Long employeeId)
throws ResourceNotFoundException {
Employee employee = employeeRepository.findById(employeeId)
.orElseThrow(() -> new ResourceNotFoundException("Employee not found for this id :: " + employeeId));
return ResponseEntity.ok().body(employee);
}
@PostMapping("/employee")
public Employee createEmployee(@Valid @RequestBody Employee employee) {
return employeeRepository.save(employee);
}
@DeleteMapping("/employees/{id}")
public Map<String, Boolean> deleteEmployee(@PathVariable(value = "id") Long employeeId)
throws ResourceNotFoundException {
Employee employee = employeeRepository.findById(employeeId)
.orElseThrow(() -> new ResourceNotFoundException("Employee not present for the id :: " + employeeId));
employeeRepository.delete(employee);
Map<String, Boolean> response = new HashMap<>();
response.put("deleted", Boolean.TRUE);
return response;
} @PutMapping("/employees/{id}")
public ResponseEntity<Employee> updateEmployee(@PathVariable(value = "id") Long employeeId,
@Valid @RequestBody Employee employeeDetails) throws ResourceNotFoundException {
Employee employee = employeeRepository.findById(employeeId)
.orElseThrow(() -> new ResourceNotFoundException("Employee not found for this id :: " + employeeId));
employee.setEmailId(employeeDetails.getEmail());
employee.setLastName(employeeDetails.getLname());
employee.setFirstName(employeeDetails.getFname());
final Employee updatedEmployee = employeeRepository.save(employee);
return ResponseEntity.ok(updatedEmployee);
}
}
- 2.4 Handling Errors
For error handling, you can refer to my GitHub link. I am skipping that part here
3. Create an Angular App
ng new Employe-Crud
So what we will add in angular app
Components:
- create-employee
- employee-list
- employee-details
Service
- employee-service.service.ts
Modal
- employee.ts
To install jquery and bootstrap you can refer any external resource’
4. Creating Component, Service and Modal files in angular
4.1 Modal Class(Employee.ts)
export class Employee {
id: number;
fname: string;
lname: string;
email: string;
active: boolean;
}
4.2 Employee List Component(employee-list.component.ts)
Below is Github link
import { EmployeeDetailsComponent } from '../employee-details/employee-details.component';
import { Observable } from "rxjs";import { Employee } from "../employee";import { Router } from '@angular/router';
import { Component, OnInit } from "@angular/core";import { EmployeeService } from "../employee.service";
@Component({
selector: "app-employee-list",
templateUrl: "./employee-list.component.html",
styleUrls: ["./employee-list.component.css"]
})
export class EmployeeListComponent implements OnInit {
employee: Observable<Employee[]>;
constructor(private es: EmployeeService,
private router: Router) {}
ngOnInit() {
this.reloadData();
}
reloadData() {
this.employees = this.es.getEmployeesList();
}
deleteEmployee(id: number) {
this.es.deleteEmployee(id)
.subscribe(
data => {
console.log(data);
this.reloadData();
},
error => console.log(error));
}
employeeDetails(id: number){
this.router.navigate(['details', id]);
}
}
employee-component.html
<div class="panel panel-primary">
<div class="panel-heading">
<h2>Employees List</h2>
</div>
<div class="panel-body main">
<table class="table table-hover table-striped">
<thead>
<tr>
<th>First-name</th>
<th>Last-name</th>
<th>Email-Id</th>
<th>Actions </th>
</tr>
</thead>
<tbody>
<tr *ngFor="let emp of employees | async">
<td>{{emp.firstName}}</td>
<td>{{emp.lastName}}</td>
<td>{{emp.emailId}}</td> <td><button (click)="deleteEmployee(emp.id)" class="btn btn-danger btn-delete">Delete</button> <button (click)="employeeDetails(emp.id)" class="btn btn-info btn-detail" style="margin-left: 10px">Details</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
4.3 Create Employe Component
In this, we will write code for creating an employee. You can find Github link here
create-employe.component.ts
import { Component, OnInit } from '@angular/core';
import { Employee } from '../employee';
import { Router } from '@angular/router';
import { EmployeeService } from '../employee.service';@Component({
selector: 'app-create-employee',
templateUrl: './create-employee.component.html',
styleUrls: ['./create-employee.component.css']
})
export class CreateEmployeeComponent implements OnInit {employee: Employee = new Employee();
submitted = false;constructor(private es: EmployeeService,
private router: Router) { }ngOnInit() {
}newEmployee(): void {
this.submitted = false;
this.employee = new Employee();
}save() {
this.es.createEmployee(this.employee)
.subscribe(data => console.log(data), error => console.log(error));
this.employee = new Employee();
this.gotoList();
}onSubmit() {
this.submitted = true;
this.save();
}gotoList() {
this.router.navigate(['/employees']);
}
}
create-employee.component.html
<h3>New Employe Clickk here to create</h3>
<div [hidden]="submitted" style="width: 500px;">
<form (ngSubmit)="onSubmit()">
<div class="form-group">
<label for="fname">First Name</label>
<input type="text" class="form-control" id="fname" required [(ngModel)]="employee.fname" name="firstName">
</div>
<div class="form-group">
<label for="name">Last Name</label>
<input type="text" class="form-control" id="lastName" required [(ngModel)]="employee.lname" name="lastName">
</div>
<div class="form-group">
<label for="name">First Name</label>
<input type="text" class="form-control" id="emailId" required [(ngModel)]="employee.email" name="emailId">
</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)="newEmployee()">Add</button> -->
</div>
4.4 Update Employee Component
Here we will write angular code for updating component
update-employee.component.html
<h3>Click here to Update Employee</h3>
<div [hidden]="submitted" style="width: 400px;">
<form (ngSubmit)="onSubmit()">
<div class="form-group">
<label for="name">First Name</label>
<input type="text" class="form-control" id="firstName" required [(ngModel)]="employee.fname" name="firstName">
</div>
<div class="form-group">
<label for="name">Last Name</label>
<input type="text" class="form-control" id="lastName" required [(ngModel)]="employee.lname" name="lastName">
</div>
<div class="form-group">
<label for="name">First Name</label>
<input type="text" class="form-control" id="emailId" required [(ngModel)]="employee.email" name="emailId">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
update-component.ts
import { Employee } from '../employee';
import { Component, OnInit, Input } from '@angular/core';
import { EmployeeService } from '../employee.service';
import { EmployeeListComponent } from '../employee-list/employee-list.component';
import { Router, ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-employee-details',
templateUrl: './employee-details.component.html',
styleUrls: ['./employee-details.component.css']
})
export class EmployeeDetailsComponent implements OnInit {
id: number;
employee: Employee;
constructor(private route: ActivatedRoute,private router: Router,
private es: EmployeeService) { }
ngOnInit() {
this.employee = new Employee();
this.id = this.route.snapshot.params['id'];
this.es.getEmployee(this.id)
.subscribe(data => {
console.log(data)
this.employee = data;
}, error => console.log(error));
}
employee_list(){
this.router.navigate(['employees']);
}
}
4.5 Employee Detail
Here we will write angular code to show employee-detail .here is my Github link for same
employee-detail.component.html
<h2>Employee Details</h2>
<hr/>
<div *ngIf="employee">
<div>
<label><b>First Name: </b></label> {{employee.fname}}
</div>
<div>
<label><b>Last Name: </b></label> {{employee.lname}}
</div>
<div>
<label><b>Email Id: </b></label> {{employee.email}}
</div>
</div>
<br>
<br>
<button (click)="Employee_list()" class="btn btn-primary">Back to Employee List</button><br>
Employe-detail.component.ts
import { Employee } from '../employee';
import { Component, OnInit, Input } from '@angular/core';
import { EmployeeService } from '../employee.service';
import { EmployeeListComponent } from '../employee-list/employee-list.component';
import { Router, ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-employee-detail',
templateUrl: './employee-detail.component.html',
styleUrls: ['./employee-detail.component.css']
})
export class EmployeeDetailComponent implements OnInit {
id: number;
employee: Employee;
constructor(private route: ActivatedRoute,private router: Router,
private es: EmployeeService) { }
ngOnInit() {
this.employee = new Employee();
this.id = this.route.snapshot.params['id'];
this.es.getEmployee(this.id)
.subscribe(data => {
console.log(data)
this.employee = data;
}, error => console.log(error));
}
Employee_list(){
this.router.navigate(['employees']);
}
}
Service
Employee service will contain all the methods and provide data to all the components. The EmployeeService will be used to fetch the data from the spring-boot local server (backend) .below is Github link for the same.
4.7 Employee-serice.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class EmployeeService {
private url= 'http://localhost:8080/springboot-crud-rest/api/path1/employees';
constructor(private http: HttpClient) { }
getEmployee(id: number): Observable<any> {
return this.http.get(`${this.url}/${id}`);
}
createEmployee(employee: Object): Observable<Object> {
return this.http.post(`${this.url}`, employee);
}
updateEmployee(id: number, value: any): Observable<Object> {
return this.http.put(`${this.url}/${id}`, value);
}
deleteEmployee(id: number): Observable<any> {
return this.http.delete(`${this.url}/${id}`, { responseType: 'text' });
}
getEmployeesList(): Observable<any> {
return this.http.get(`${this.url}`);
}
}
5 Configuring App to run
Here in this section, we will be configuring app so that we can run it. First of all, we will add routing
5.1 Routing:
Routing is used to call or navigate different components in our Angular app. Below is the Github link
App.routing.modue.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { EmployeeListComponent } from './employee-list/employee-list.component';
import { CreateEmployeeComponent } from './create-employee/create-employee.component';
import { UpdateEmployeeComponent } from './update-employee/update-employee.component';
import { EmployeeDetailsComponent } from './employee-details/employee-details.component';const routes: Routes = [{ path: '', redirectTo: 'employee', pathMatch: 'full' },
{ path: 'employees', component: EmployeeListComponent },
{ path: 'add-emp', component: CreateEmployeeComponent },
{ path: 'update-emp/:id', component: UpdateEmployeeComponent },
{ path: 'emp-detail/:id', component: EmployeeDetailsComponent },
];@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
5.2 AppComponent
App component is the app-root file which is executed in index.html.To make our component accessible we need to add some code in app.component.html.Below is the GitHub link for same
app.component.html
<nav class="navbar navbar-expand-sm bg-primary navbar-dark">
<ul class="navbar-nav">
<li class="nav-item">
<a routerLink="employees" class="nav-link" routerLinkActive="active">Employee List</a>
</li>
<li class="nav-item">
<a routerLink="add-emp" class="nav-link" routerLinkActive="active">Add Employee</a>
</li>
</ul>
</nav>
<div class="container">
<br>
<h2 style="text-align: center;">{{title}}</h2>
<hr>
<div class="card">
<div class="card-body">
<router-outlet></router-outlet>
</div>
</div>
</div>
6 Running the app and spring-boot app
Step 1: First of all run the spring boot app. Once you see the success message in the console of spring boot move to step 2
Step 2: Now run the angular app by running a command
ng serve -o
If you find some port conflict issue you can manually specify port no
ng serve --port 5000
Screenshot
Source Code on my GitHub repository
Feel free to ask if you have any doubts. I will be grateful to help you out. If you like my blogs, Show your support at https://paypal.me/mehulk05?country.x=IN&locale.x=en_GB