Spring Boot is a popular Java framework used to build microservice applications, REST APIs, etc. It is also one of the widely used frameworks for developing microservices.
Angular is a popular javascript frontend development framework used to build web applications. Angular also provides rich support to create a good user experience and provides tools that help in simplifying large and complex web application development.
In this article, we will learn how to build a simple CRUD application using the Angular front end and also the Spring boot as a backend framework.
We will create a simple-looking web application where users can add student details, update or delete them from the system. We will also display a table that shows all available student details in the database.

Below are the version details used in this example:
- Angular: 10.0.14
- Angular CLI: 10.0.8
- Spring boot: 2.3.3.RELEASE
- Embedded H2 database.
- Spring Tool Suite IDE.
- Visual Studio Code.
Table of Contents
- Spring Boot Application
- Create a Spring Boot application
- Add database related configurations
- Create Student entity class
- Create the JPA repository class
- Create the REST controller endpoints
- Testing the APIs
- Create Angular application
- Create service layer
- Update the student component
- Update the student component template
- Testing the application
- Conclusion
Spring Boot Application
We will create RESTful endpoints that support CRUD operation from the angular frontend app with the help of the Spring Boot framework.
The RESTful endpoint will have REST APIs to create a new student, update student information, get all available students, and also delete the student entity from the database.
We will also use an embedded H2 database in this example.
Create a Spring Boot application
Let us create a new spring boot application with the spring-boot-starter-web, spring-boot-starter-data-jpa, h2, and the lombok maven dependencies.
Below is the required maven dependency list.
<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>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>
- spring-boot-starter-web: Provides support for creating a web application and REST APIs.
- spring-boot-starter-data-jpa: Provides support for database related operation.
- h2: Adds an embedded H2 database during application runtime.
- Lombok: A utility that helps to reduce boilerplate code.
Add database related configurations
Update the application.properties configuration file under the Spring Boot applications src/main/resources/ folder with below content.
spring.datasource.url=jdbc:h2:~/asbdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE spring.datasource.data-username=sa spring.datasource.data-password= spring.jpa.show-sql=true
We have added the required configurations to connect to the embedded H2 database. The above properties define the data source URL, username, and password(optional).
Also, we have set the spring.jpa.show-sql property’s value to true. This configuration makes the application print the generated SQL queries in the application console.
Create Student entity class
Create a JPA entity class with the name Student and add the below content.
The entity class contains an Id(auto-generated), name, and grade of the student. If you are new to JPA, I recommend you to read this introductory post.
package com.asbnotebook.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; import lombok.Getter; import lombok.Setter; @Entity @Table(name = "STUDENT") @Getter @Setter public class Student { @Id @Column(name = "ID") @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @Column(name = "NAME") private String name; @Column(name = "GRADE") private Integer grade; }
The STUDENT table will be auto-generated by JPA on application startup. Spring boot uses the default DDL strategy(create-drop) for the embedded databases.
Create the JPA repository class
Create a JPA repository interface with the name StudentRepository and extend the JpaRepository interface as given below.
With this, the spring data jpa library gives CRUD operation support to our repository interface.
package com.asbnotebook.repo; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; import com.asbnotebook.model.Student; @Repository public interface StudentRepository extends JpaRepository<Student, Long>{ }
Create the REST controller endpoints
The final step is to create the REST endpoints that support the CRUD operation on the Student entity.
Create a controller class with the name StudentController, and add the below content.
package com.asbnotebook.controller; 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.RestController; import com.asbnotebook.model.Student; import com.asbnotebook.repo.StudentRepository; @CrossOrigin(origins = {"http://localhost:4200"}) @RestController public class StudentController { @Autowired private StudentRepository studentRepository; @GetMapping("/students/") public ResponseEntity<List<Student>> getStudents() { List<Student> students = studentRepository.findAll(); return new ResponseEntity<>(students, HttpStatus.OK); } @PostMapping("/students/") public ResponseEntity<Student> createStudent(@RequestBody Student student) { Student std = studentRepository.save(student); return new ResponseEntity<>(std, HttpStatus.OK); } @PutMapping("/students/") public ResponseEntity<Student> updateStudent(@RequestBody Student student) { Optional<Student> std = studentRepository.findById(student.getId()); Student stdUpdated = std.get(); stdUpdated.setGrade(student.getGrade()); stdUpdated.setName(student.getName()); Student studentUpdated = studentRepository.save(stdUpdated); return new ResponseEntity<>(studentUpdated, HttpStatus.OK); } @DeleteMapping("/students/{id}") public ResponseEntity<String> createStudent(@PathVariable(name = "id") Long id) { studentRepository.deleteById(id); return new ResponseEntity<>("student id: "+ id + " deleted successfully", HttpStatus.OK); } }
- We have annotated the class with the @RestController annotation to make it a REST controller that contains our CRUD APIs. This annotation also takes care of converting the response to JSON format, and handles the incoming requests, maps them to the proper handler methods.
- @CrossOrigin: This annotation whitelists the domain origins that are allowed to request to the APIs.
- Angular runs a development server at the URL http://localhost:4200 when we execute the ng serve command. We are adding the same URL with the @CrossOrigin annotation that we were using earlier.
- We also have injected the StudentRepository instance and added different methods to supports CRUD operation on the student entity.
Finally, we can run the application and test the endpoints.
Start the spring boot application, and our REST APIs will be available at http://localhost:8080/
Testing the APIs
We can use Postman or any other API testing tool to test the REST APIs.
Also, make sure that the Spring boot application is up. Now we can test the REST endpoints with the help of Postman.
Note: We may have to remove the @CrossOrigin annotation from the rest controller class, for now, to avoid CORS error.
Create API
Send the Post request with the student JSON request, as given below. The application will create a new student record in the H2 database.

Update API
Pass the student request JSON with id and update the name and grade fields as given below. The application will update the student details with new values.

Read API
To retrieve all available students from the database, invoke the GET API, as given below.

Delete API
Pass the student id in the request path and invoke the HTTP DELETE API, as given below.
The application will delete the student record from the H2 database that matches the request input id.

Congratulations!! We have completed half part of our Spring Boot and Angular CRUD application.
Create Angular application
The next part of the Spring boot and angular CRUD application is to create the frontend application.
Create a new angular application with the name springboot-angular-crud-app and navigate inside the application folder.
ng new springboot-angular-crud-app cd springboot-angular-crud-app
Add bootstrap UI library to the angular application by running the below command.
ng add @ng-bootstrap/ng-bootstrap
We have added the NgBootstrap library to our angular application.
Create a new student component by running the below command.
ng generate component student
Update the app.componenet html file with the below content.
<body> <header> <nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark"> <div class="collapse navbar-collapse justify-content-center"> <h4 class="text-light bg-dark">Student details</h4> </div> </nav> </header> <!-- Begin page content --> <main role="main" class="flex-shrink-0"> <div class="container"> <div class="mt-5 col-12 mt-6 d-flex justify-content-center"> <app-student></app-student> </div> </div> </main> <footer class="footer fixed-bottom bg-dark"> <div class="container"> <span class="text-muted">ASB Notebook</span> </div> </footer> </body>
We have added a navigation bar that contains a simple header with static text and a static footer.
The student component will get rendered within these two HTML components.
Run the below command within the application folder.
ng serve
Angular will compile the application, build it, and also set up a local server for running our application locally.
Finally, our Angular application will be available at http://localhost:4200

Create service layer
Run the below command to generate a new Angular service.
ng generate service service/student
Angular service helps us create a utility class that we can use for various purposes, like making HTTP calls, connecting to local storage, etc.
Angular services class uses the @Injectable decorator that makes it an angular service. We can also inject the service class instances into any part of the application.
Replace the student.service.ts file with the below content.
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http' let student_service = "http://localhost:8080/students/"; export interface StudentInterface { id : number; name : String; grade : number; } @Injectable({ providedIn: 'root' }) export class StudentService { constructor(private http : HttpClient) { } loadStudents() { return this.http.get<Array<StudentInterface>>(student_service); } createStudent(student: StudentInterface) { return this.http.post<StudentInterface>(student_service, student); } updateStudent(student: StudentInterface) { return this.http.put<StudentInterface>(student_service, student); } deleteStudent(id:number) { return this.http.delete<String>(student_service + id, { responseType: 'text' as 'json'} ); } }
- We have imported HttpClient this will help us making HTTP connection with the Spring boot REST APIs.
- We have created a StudentInterface type that holds values related to particular student entry.
- Also, the @Injectable decorator makes this class an angular service.
- We have injected the HttpClient instance in the constructor method.
- The loadStudents() method retrieves all available students list from the Spring boot application’s GET API.
- Also, the creatStudent(), updateStudent() methods calls POST and PUT APIs to create and update student details, respectively.
- Finally, the deleteStudent() method invokes DELETE API and passes the student id in the API URL path.
Update the app.module.ts file and add the required imports.
//other imports import { HttpClientModule } from '@angular/common/http'; import { StudentService } from './service/student.service'; @NgModule({ imports: [ HttpClientModule ], providers: [StudentService] }) export class AppModule { }
The code snippet shows only the required changes to the existing file.
Update the student component
Update the student.component.ts file and also replace the existing content with the below content.
import { Component, OnInit } from '@angular/core'; import { StudentService, StudentInterface } from './service/student.service'; import { NgbModal, NgbModalRef, NgbModalOptions } from '@ng-bootstrap/ng-bootstrap'; @Component({ selector: 'app-student', templateUrl: './student.component.html', styleUrls: ['./student.component.css'] }) export class StudentComponent implements OnInit { _students: Array<StudentInterface> = []; _message: String = ""; _student: StudentInterface; modalReference: NgbModalRef; modalOption: NgbModalOptions = {}; constructor(private studentService: StudentService, private modalService: NgbModal) { } deleteStudent(id: number) { this.studentService.deleteStudent(id).subscribe(msg => this._message = msg); this._students.splice(this._students.findIndex(s => s.id === id), 1); } updateStudent(id: number) { this.studentService.updateStudent(this._student).subscribe(student => this._student = student); } addStudent() { this.studentService.createStudent(this._student).subscribe(student => { this._student = student; this._students.push(this._student); }); } createUpdate() { if(this._student.id === null || this._student.id === 0){ this.addStudent(); } else { this.updateStudent(this._student.id); } this.modalReference.close(); } ngOnInit(): void { this.studentService.loadStudents().subscribe(students => this._students = students); this._message = ""; } open(id : number, content) { this.modalOption.backdrop = 'static'; this.modalOption.keyboard = false; this.modalReference = this.modalService.open(content, this.modalOption); if(id === 0 ) { this._student = {id : 0, name : null, grade : 0}; } else { this._student = this._students.find(s => s.id === id); } } }
- We have imported the StudentService, StudentInterface, that we have created earlier.
- We have also imported Bootstrap Modal related modules from the NgBootstrap library.
- Also, the StudentService and NgbModal instances are injected into the Angular component class using the class constructor.
- The _students array will hold the list of students retrieved from the backend service.
- The _message field holds the text message displayed on the deletion of a student record.
- The _student instance holds the current student object that is being created/updated.
- We have also defined bootstrap modal related instances to customize the default bootstrap modal.
- The component class implements the OnInit component life cycle even, which loads all available students on Angular component initialization.
- The open() method is invoked during the creation/update of new students. This method will also open a bootstrap modal that contains input fields to enter student details.
- The delete() method deletes the student instance and also updates the message that gets displayed on the UI screen.
Update the app.module.ts file to add FormsModule, RectiveFormsModule, and also add the required entry in the import section.
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppComponent } from './app.component'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { StudentComponent } from './student/student.component'; import { HttpClientModule } from '@angular/common/http'; import { StudentService } from './service/student.service'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; @NgModule({ declarations: [ AppComponent, StudentComponent ], imports: [ BrowserModule, NgbModule, HttpClientModule, FormsModule, ReactiveFormsModule ], providers: [StudentService], bootstrap: [AppComponent] }) export class AppModule { }
The above code is the complete app.module.ts file of our application.
Update the student component template
Update the student.component html file with the below content.
<div class="alert alert-danger" role="alert" *ngIf="_message.length > 0"> {{_message}} </div> <table class="table table-striped"> <thead> <tr> <th scope="col">Sl No.</th> <th scope="col">ID</th> <th scope="col">Name</th> <th scope="col">Grade</th> <th scope="col"></th> <th scope="col"><button class="btn btn-success" (click)="open(0, content)">ADD</button></th> </tr> </thead> <tbody> <tr *ngFor="let student of _students; index as i"> <th scope="row">{{ i + 1 }}</th> <td>{{student.id}}</td> <td>{{ student.name }}</td> <td>{{ student.grade }}</td> <td><button class="btn btn-primary" (click)="open(student.id, content)">UPDATE</button></td> <td><button class="btn btn-danger" (click)="deleteStudent(student.id)">DELETE</button></td> </tr> </tbody> </table> <ng-template #content let-modal> <div class="modal-header"> <h4 class="modal-title" id="modal-basic-title">Create/Update Student</h4> <button type="button" class="close" aria-label="Close" (click)="modal.dismiss('Cross click')" *ngIf="_student.id === 0"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> <form (ngSubmit)="createUpdate()"> <div class="form-group"> <h2>Name : </h2> <input type="text" name="name" placeholder="Student Name" [(ngModel)]="_student.name"/> <h2>Grade : </h2> <input type="number" name="grade" [(ngModel)]="_student.grade"/> </div> <button type="submit" class="btn btn-success">SAVE</button> </form> </div>
- The bootstrap alert will be displayed whenever a student record gets deleted.
- All student records are shown in a table with UPDATE and DELETE buttons along with other details.
- Also, we have an ADD button that will open the bootstrap modal window to input student details.
- Finally, the bootstrap window contains a SAVE button that invokes createUpdate() method to create/update the student details.
Congratulations! We have finally completed the front-end part of our Angular application.
Let us run and test it.
Testing the application
Run the application using the ng serve CLI command.
We should be able to get the below page.

Create a new student by clicking on the ADD button on the above screen.
This will open the bootstrap modal window as shown below.

Enter the name and grade input fields and click on the SAVE button. The application saves the student details by invoking the back-end Spring boot API and also it closes the modal window.
We can also observe the saved student details in the below screen.

Update the student by clicking on the UPDATE button.

Also, Delete the student record by clicking on the DELETE button.

Finally, we have created a full-stack web application and performed basic CRUD operations.
Conclusion
In this article, we learned how to create a simple CRUD application using Angular and Spring boot framework.
Also, we created REST APIs to support CRUD operations.
We also learned how the Spring data JPA library provides built-in repository interfaces and provides data operation support.
Next, we also learned how to create an Angular application, how to create an Angular service, and invoke the backend REST APIs.
Finally, we learned how to add bootstrap support to our Angular application.
The complete example is available on GitHub.