📘 Premium Read: Access my best content on Medium member-only articles — deep dives into Java, Spring Boot, Microservices, backend architecture, interview preparation, career advice, and industry-standard best practices.
✅ Some premium posts are free to read — no account needed. Follow me on Medium to stay updated and support my writing.
🎓 Top 10 Udemy Courses (Huge Discount): Explore My Udemy Courses — Learn through real-time, project-based development.
▶️ Subscribe to My YouTube Channel (172K+ subscribers): Java Guides on YouTube
If you are looking for an Angular 7 with spring boot 2 integration example then check out Spring Boot + Angular 7 CRUD Example article.
Recommendation - Check out the same tutorial upgraded using the latest release of Angular 8 at Spring Boot + Angular 8 CRUD Example Tutorial
You can download the source code of this tutorial from my GitHub repository at the end of this tutorial.
Features Implementation
- Create an Employee
- Update an Employee
- List of Employees
- Delete Employee
- View Employee
- You will develop your first FULL STACK Application with Angular 8 and Spring Boot.
Important: Note that update employee and view employee features covered in Spring Boot + Angular 8 CRUD Example Tutorial.
What you'll learn
- You will develop your first FULL STACK Application with Angular 6 and Spring Boot
- You will learn the basics of building AWESOME Frontend Applications with Angular 6
- You will be introduced to building great RESTful APIs with Spring Boot
- You will learn to solve the challenges of connecting an Angular frontend to a RESTful API
- You will learn the basics of Angular - Angular Modules, Components, Data Binding and Routing
- You will learn to connect REST API to JPA/Hibernate with Spring Boot
- You will learn to use a wide variety of Spring Boot Starter Projects - Spring Boot Web, and Spring Boot Data JPA
What we will build?
- springboot2-jpa-crud-example: This project is used to develop CRUD RESTFul APIs for a simple Employee Management System using Spring Boot, JPA, and MySQL as a database.
- angular6-springboot-client: This project is used to develop a single page application using Angular 6 as front-end technology. This angular 6 application consumes CRUD Restful APIs developed and exposed by a springboot2-jpa-crud-example project.
Tools and technologies used
Server-side technologies
- Spring Boot - 3
- JDK - 17 or later
- Spring Framework - 6
Front end technologies
- Angular 6
- Bootstrap 4
- npm- 6.4.1
- JQuery
Tools
- Maven - 3.2+
- IDE - Eclipse or Spring Tool Suite (STS)
- Visual Studio 2017
- Angular CLI
Spring Boot CRUD Rest APIs
1. Create and Setup
- Project: Maven Project
- Java Version: 17 (Default)
- Spring Boot: 3.0.4
- Group: net.guides.springboot2
- Artifact: springboot2-jpa-crud-example
- Name: springboot2-jpa-crud-example
- Description: Rest API for a Simple Employee Management Application
- Package Name : net.guides.springboot2.springboot2jpacrudexample
- Packaging: jar (This is the default value)
- Dependencies: Web, JPA, MySQL, DevTools
2. Packaging Structure
3. The pom.xml File
<?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>
<groupId>net.guides.springboot2</groupId>
<artifactId>springboot2-jpa-crud-example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>springboot2-jpa-crud-example</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>17</java.version>
</properties>
<dependencies>
<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.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</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>
4. Create JPA Entity - Employee.java
package net.guides.springboot2.springboot2jpacrudexample.model;
import jakarta.persistence.*;
@Entity
@Table(name = "employees")
public class Employee {
private long id;
private String firstName;
private String lastName;
private String emailId;
public Employee() {
}
public Employee(String firstName, String lastName, String emailId) {
this.firstName = firstName;
this.lastName = lastName;
this.emailId = 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 getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
@Column(name = "last_name", nullable = false)
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
@Column(name = "email_address", nullable = false)
public String getEmailId() {
return emailId;
}
public void setEmailId(String emailId) {
this.emailId = emailId;
}
@Override
public String toString() {
return "Employee [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + ", emailId=" + emailId
+ "]";
}
}
5. Create a Spring Data Repository - EmployeeRepository.java
package net.guides.springboot2.springboot2jpacrudexample.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import net.guides.springboot2.springboot2jpacrudexample.model.Employee;
@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long>{
}
6. Create Spring Rest Controller - EmployeeController.java
package net.guides.springboot2.springboot2jpacrudexample.controller;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
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 net.guides.springboot2.springboot2jpacrudexample.exception.ResourceNotFoundException;
import net.guides.springboot2.springboot2jpacrudexample.model.Employee;
import net.guides.springboot2.springboot2jpacrudexample.repository.EmployeeRepository;
@RestController
@RequestMapping("/api/v1")
public class EmployeeController {
@Autowired
private EmployeeRepository employeeRepository;
@GetMapping("/employees")
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("/employees")
public Employee createEmployee(@Valid @RequestBody Employee employee) {
return employeeRepository.save(employee);
}
@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.getEmailId());
employee.setLastName(employeeDetails.getLastName());
employee.setFirstName(employeeDetails.getFirstName());
final Employee updatedEmployee = employeeRepository.save(employee);
return ResponseEntity.ok(updatedEmployee);
}
@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 found for this id :: " + employeeId));
employeeRepository.delete(employee);
Map<String, Boolean> response = new HashMap<>();
response.put("deleted", Boolean.TRUE);
return response;
}
}
Enable CORS on the Server
To enable CORS on the server, add a @CrossOrigin annotation to the EmployeeController.
@CrossOrigin(origins = "http://localhost:4200")
@RestController
@RequestMapping("/api/v1")
public class EmployeeController {
// ....
}
@CrossOrigin(origins = "http://localhost:4200")
@RestController
@RequestMapping("/api/v1")
public class EmployeeController {
// ....
}
7. Running Application
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
This completes the development of Spring boot CRUD Rest APIs. Now we will develop a client application using Angular 6.
Angular 6 Client Application
Create Angular 6 client application using Angular CLI
$ npm install -g @angular/cli
ng new angular6-springboot-client
Components, Services, and Modules
- Components
- create-employee
- employee-list
- employee-details
- Services
- employee.service.ts - Service for Http Client methods
- Modules
- FormsModule
- HttpClientModule
- AppRoutingModule.
- Employee Class (Typescript class)
- employee.ts: class Employee (id, firstName, lastName, emailId)
Create Service & Components
- ng g s employee
– ng g c create-employee
– ng g c employee-details
– ng g c employee-list
C:\angular6\angular6-springboot-client\src\app>ng g s employee
CREATE src/app/employee.service.spec.ts (343 bytes)
CREATE src/app/employee.service.ts (137 bytes)
C:\angular6\angular6-springboot-client\src\app>ng g c create-employee
CREATE src/app/create-employee/create-employee.component.html (34 bytes)
CREATE src/app/create-employee/create-employee.component.spec.ts (685 bytes)
CREATE src/app/create-employee/create-employee.component.ts (304 bytes)
CREATE src/app/create-employee/create-employee.component.css (0 bytes)
UPDATE src/app/app.module.ts (509 bytes)
C:\angular6\angular6-springboot-client\src\app>ng g c employee-details
CREATE src/app/employee-details/employee-details.component.html (35 bytes)
CREATE src/app/employee-details/employee-details.component.spec.ts (692 bytes)
CREATE src/app/employee-details/employee-details.component.ts (308 bytes)
CREATE src/app/employee-details/employee-details.component.css (0 bytes)
UPDATE src/app/app.module.ts (629 bytes)
C:\angular6\angular6-springboot-client\src\app>ng g c employee-list
CREATE src/app/employee-list/employee-list.component.html (32 bytes)
CREATE src/app/employee-list/employee-list.component.spec.ts (671 bytes)
CREATE src/app/employee-list/employee-list.component.ts (296 bytes)
CREATE src/app/employee-list/employee-list.component.css (0 bytes)
UPDATE src/app/app.module.ts (737 bytes)
Integrate Bootstrap with Angular
npm install bootstrap jquery --save
...
"styles": [
"src/styles.css",
"node_modules/bootstrap/dist/css/bootstrap.min.css"
],
"scripts": [
"node_modules/jquery/dist/jquery.min.js",
"node_modules/bootstrap/dist/js/bootstrap.min.js"
]
...
Create Employee class employee.ts
export class Employee {
id: number;
firstName: string;
lastName: string;
emailId: string;
active: boolean;
}
EmployeeService - employee-service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class EmployeeService {
private baseUrl = '/api/v1/employees';
constructor(private http: HttpClient) { }
getEmployee(id: number): Observable<Object> {
return this.http.get(`${this.baseUrl}/${id}`);
}
createEmployee(employee: Object): Observable<Object> {
return this.http.post(`${this.baseUrl}`, employee);
}
updateEmployee(id: number, value: any): Observable<Object> {
return this.http.put(`${this.baseUrl}/${id}`, value);
}
deleteEmployee(id: number): Observable<any> {
return this.http.delete(`${this.baseUrl}/${id}`, { responseType: 'text' });
}
getEmployeesList(): Observable<any> {
return this.http.get(`${this.baseUrl}`);
}
}
EmployeeListComponent - employee-list.component.ts
import { Observable } from "rxjs";
import { EmployeeService } from "./../employee.service";
import { Employee } from "./../employee";
import { Component, OnInit } from "@angular/core";
@Component({
selector: "app-employee-list",
templateUrl: "./employee-list.component.html",
styleUrls: ["./employee-list.component.css"]
})
export class EmployeeListComponent implements OnInit {
employees: Observable<Employee[]>;
constructor(private employeeService: EmployeeService) {}
ngOnInit() {
this.reloadData();
}
reloadData() {
this.employees = this.employeeService.getEmployeesList();
}
deleteEmployee(id: number) {
this.employeeService.deleteEmployee(id)
.subscribe(
data => {
console.log(data);
this.reloadData();
},
error => console.log(error));
}
}
Create a template for EmployeeListComponent employee-list.component.html
<div class="panel panel-default">
<div class="panel-heading">
<h1>Employees</h1>
</div>
<div class="panel-body">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Firstname</th>
<th>Lastname</th>
<th>Email</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let employee of employees | async">
<td>{{employee.firstName}}</td>
<td>{{employee.lastName}}</td>
<td>{{employee.emailId}}</td>
<td><button (click)="deleteEmployee(employee.id)">Delete</button></td>
</tr>
</tbody>
</table>
</div>
</div>
CreateEmployeeComponent - create-employee.component.ts
import { EmployeeService } from './../employee.service';
import { Employee } from './../employee';
import { Component, OnInit } from '@angular/core';
@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 employeeService: EmployeeService) { }
ngOnInit() {
}
newEmployee(): void {
this.submitted = false;
this.employee = new Employee();
}
save() {
this.employeeService.createEmployee(this.employee)
.subscribe(data => console.log(data), error => console.log(error));
this.employee = new Employee();
}
onSubmit() {
this.submitted = true;
this.save();
}
}
Create a template for EmployeeCreateComponent create-employee.component.html
<h3>Create 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.firstName" name="firstName">
</div>
<div class="form-group">
<label for="name">Last Name</label>
<input type="text" class="form-control" id="lastName" required [(ngModel)]="employee.lastName" name="lastName">
</div>
<div class="form-group">
<label for="name">First Name</label>
<input type="text" class="form-control" id="emailId" required [(ngModel)]="employee.emailId" name="emailId">
</div>
<button type="submit" class="btn btn-success">Submit</button>
</form>
</div>
<div [hidden]="!submitted">
<h4>You submitted successfully!</h4>
</div>
EmployeeDetailsComponent- employee-details.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';
@Component({
selector: 'app-employee-details',
templateUrl: './employee-details.component.html',
styleUrls: ['./employee-details.component.css']
})
export class EmployeeDetailsComponent implements OnInit {
@Input() employee: Employee;
constructor(private employeeService: EmployeeService, private listComponent: EmployeeListComponent) { }
ngOnInit() {
}
}
Create a template for EmployeeDetailsComponent employee-details.component.html
<div *ngIf="employee">
<div>
<label>Name: </label> {{employee.firstName}}
</div>
<div>
<label>Age: </label> {{employee.lastName}}
</div>
<div>
<label>Active: </label> {{employee.emailId}}
</div>
<div>
<label>Active: </label> {{employee.active}}
</div>
<span class="button is-small btn-primary" *ngIf='employee.active' (click)='updateActive(false)'>Inactive</span>
<span class="button is-small btn-primary" *ngIf='!employee.active' (click)='updateActive(true)'>Active</span>
<span class="button is-small btn-danger" (click)='deleteEmployee()'>Delete</span>
<hr/>
</div>
AppRoutingModule - app-routing.module.ts
import { EmployeeDetailsComponent } from './employee-details/employee-details.component';
import { CreateEmployeeComponent } from './create-employee/create-employee.component';
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { EmployeeListComponent } from './employee-list/employee-list.component';
const routes: Routes = [
{ path: '', redirectTo: 'employee', pathMatch: 'full' },
{ path: 'employees', component: EmployeeListComponent },
{ path: 'add', component: CreateEmployeeComponent },
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
AppComponent - app/app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'Angular 6 + Spring Boot 2 + Spring Data JPA + MySQL + CRUD Tutorial';
}
app/app.component.html
<div class="container">
<h2>{{title}}</h2>
<hr>
<nav class="navbar navbar-expand-sm bg-dark navbar-dark">
<!-- Links -->
<ul class="navbar-nav">
<li class="nav-item">
<a routerLink="employees" class="btn btn-primary active" role="button" routerLinkActive="active">Employees</a>
</li>
<li class="nav-item" style="margin-left: 10px;">
<a routerLink="add" class="btn btn-primary active" role="button" routerLinkActive="active">Add</a>
</li>
</ul>
</nav>
<router-outlet></router-outlet>
</div>
app/app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { CreateEmployeeComponent } from './create-employee/create-employee.component';
import { EmployeeDetailsComponent } from './employee-details/employee-details.component';
import { EmployeeListComponent } from './employee-list/employee-list.component';
import { HttpClientModule } from '@angular/common/http';
@NgModule({
declarations: [
AppComponent,
CreateEmployeeComponent,
EmployeeDetailsComponent,
EmployeeListComponent
],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule,
HttpClientModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Configure a proxy for your API calls with Angular CLI
this.http.get('http://locahost:8080/api/v1/employees') .map(res => res.json());
Configuring your Angular CLI dev-server proxy
- add the proper CORS headers - This is definitely a must in a case when you design a generic API where you don’t even know the consumer.
- use a proxy - A proxy is a piece of software that is in between your JavaScript/Angular app doing the Ajax request and your backend API. This is the choice to go in a classic app.
proxy.conf.json
{ "/api/v1/employees": { "target": "http://localhost:8080", "secure": false } }
Running Angular 6 Application
Let's run the above developed Angular App with a command: npm startNote that when you execute npm start, ng serve will be invoked which is a command to the CLI to fire up its internal development server.
Output
Open browser for URL http://URLalhost:4200/:Employee List Page
Add Employee Page
Delete Employee
Important: Note that update employee and view employee features covered in Spring Boot + Angular 8 CRUD Example Tutorial.
Note: If you still get CORS Issue then refer below section:Enable CORS on the Server // Important
To enable CORS on the server, add a @CrossOrigin annotation to the EmployeeController.
@CrossOrigin(origins = "http://localhost:4200")
@RestController
@RequestMapping("/api/v1")
public class EmployeeController {
// ....
}
@CrossOrigin(origins = "http://localhost:4200")
@RestController
@RequestMapping("/api/v1")
public class EmployeeController {
// ....
}
Source Code on GitHub
The source code of this tutorial available on my GitHub repository at https://github.com/RameshMF/angular6-springboot-crud-tutorial
Hello and thanks for the tutorial.
ReplyDeleteI'm having a trouble, when I try to call the backend from the front-end I get this error:
HttpErrorResponse {headers: HttpHeaders, status: 404, statusText: "Not Found", url: "http://localhost:4200/api/v1/employees", ok: false, …}
I don't know why is trying to call the URL with the port 4200, it should be with the port of the backend 8080. Can you help me please.
Thanks
Angular application is running on port 4200 and spring boot is running on 8080 port. You need to specify full rest API URL like http://localhost:8080/api/v1/employees to call rest APIs of spring boot application. I have used proxy configuration to avoid CSRF related issues. Replace "api/v1/employees" with "http://localhost:8080/api/v1/employees" in EmployeeService class then it should work.
DeleteThanks for answer, now I'm having en error when I want to get an specific employee or when I want to delete. this is the error
DeleteI don't know what is happening.
Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'DELETE' not supported]
In my case, it was missing one more change after create the proxy file. I edited the package.json file’s start script to be:
Delete"start": "ng serve --proxy-config proxy.conf.json"
Then it worked.
(https://medium.com/@spencerfeng/setup-a-proxy-for-api-calls-for-your-angular-cli-app-6566c02a8c4d)
Hi,
ReplyDeleteThank you for this wonderful tutorial but I am facing same 404 error when I used "api/v1/employees" and CSRF error when i used "http://localhost:8080/api/v1/employees" .
Please help me with solution. Thanks in advance.
I am getting below error after click on "employees" button. I have already created database files
ReplyDeleteAccess to XMLHttpRequest at 'http://localhost:8080/api/v1' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
zone.js:2969 GET http://localhost:8080/api/v1 net::ERR_FAILED
Refer 'Enable CORS on the Server' section in this tutorial. Let me know if you still face the issue
DeleteHey, I'm having troubles with the update component
ReplyDeleteHi, could you give the source code link???Please..
ReplyDeleteThe source code of this article available on my GitHub repository at https://github.com/RameshMF/angular6-springboot-crud-tutorial
DeleteHey, i get all of this but where should i specify the database configurations like dbName and user ,password ?
ReplyDeleteYou need to specify database details in application.properties of spring boot project.
Deleteusing yml ?
DeleteHi Ramesh,
ReplyDeleteYou are not metion the code for update. can you please provide that.
todo-list.component.ts not available in src/app of angular 8 context path.
please provide that as early as possible
Hi, the todo-list.component.ts file is not related to this project. This file name was typo and I replaced this file name from todo-list.component.ts to employee-list.component.ts. I have update this tutorial for the same. Thank you.
Delete