📘 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
Use the below links to visit different parts of this tutorial:
- Spring Boot + Angular 8 CRUD Example Tutorial - Main Tutorial
- Spring Boot + Angular 8 CRUD, Part 1 - Develop Spring Boot CRUD Rest APIs
- Spring Boot + Angular 8 CRUD, Part 2 - Create Angular 8 App
- Spring Boot + Angular 8 CRUD, Part 3 - Develop Angular 8 CRUD Operations
- Spring Boot + Angular 8 CRUD, Part 4 - Angular 8 CRUD App Configuration
- Spring Boot + Angular 8 CRUD, Part 5 - Running Angular 8 CRUD App
High-level architecture of Spring boot project
Spring Boot CRUD Rest APIs Development
1. Creating and Importing a Project
- Generate: Maven Project
- Java Version: 1.8 (Default)
- Spring Boot Version: keep default selected
- 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>2.0.5.RELEASE</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>1.8</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-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</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>
The spring-boot-starter-web Starter:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
The spring-boot-starter-data-jpa Starter:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
The spring-boot-starter-test Starter:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
4. Configuring Database (H2 or MySQL)
H2 Database Configuration
<dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency>
If you use the H2 database then we no need to configure the database-related properties in the application.properties file.
If you use H2 in-memory database then you no need to create a database and tables, spring boot automatically do it for you.
server.servlet.context-path=/springboot-crud-rest
MySQL Database Configuration
Step 1: Replace the H2 database dependency with MySQL dependency:
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>
spring.datasource.url = jdbc:mysql://localhost:3306/users_database?useSSL=false spring.datasource.username = root spring.datasource.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 server.servlet.context-path=/springboot-crud-rest
create database users_database
5. Create JPA Entity - Employee.java
- id - primary key
- firstName - First name of an employee
- lastName - Last name of an employee
- email - Email address of an employee
package net.guides.springboot2.springboot2jpacrudexample.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 = "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
+ "]";
}
}
6. 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>{
}
7. 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 javax.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 @CrossOrigin(origins = "http://localhost:4200")
@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 {
// ....
}
8. Exception(Error) Handling for RESTful Services
Resource Not Present
{
"timestamp": 1512713804164,
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/some-dummy-url"
}
What happens when we throw an Exception?
package com.companyname.springbootcrudrest.exception;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(value = HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends Exception{
private static final long serialVersionUID = 1L;
public ResourceNotFoundException(String message){
super(message);
}
}
Customizing Error Response Structure
package com.companyname.springbootcrudrest.exception;
import java.util.Date;
public class ErrorDetails {
private Date timestamp;
private String message;
private String details;
public ErrorDetails(Date timestamp, String message, String details) {
super();
this.timestamp = timestamp;
this.message = message;
this.details = details;
}
public Date getTimestamp() {
return timestamp;
}
public String getMessage() {
return message;
}
public String getDetails() {
return details;
}
}
package com.companyname.springbootcrudrest.exception;
import java.util.Date;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<?> resourceNotFoundException(ResourceNotFoundException ex, WebRequest request) {
ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<?> globleExcpetionHandler(Exception ex, WebRequest request) {
ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
9. 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);
}
}
$ mvn spring-boot:run
Testing REST APIs
Get All Employees:
http://localhost:8080/springboot-crud-rest/api/v1/employees
Get Employee By Id:
http://localhost:8080/springboot-crud-rest/api/v1/employees/{employeeId}
Create Employee:
http://localhost:8080/springboot-crud-rest/api/v1/employees
Update Employee
http://localhost:8080/springboot-crud-rest/api/v1/employees/{employeeId}
Delete Employee By Id:
http://localhost:8080/springboot-crud-rest/api/v1/employees/{employeeId}
This completes the development of Spring boot CRUD Rest APIs.
What's next?
In the next Part 2, we will implement the following steps:
- Install the latest version of Angular CLI
- Create Angular 8 client application using Angular CLI
- Identify Components, Services, and Modules
- Create Service & Components using Angular CLI
- Integrate JQuery and Bootstrap with Angular
Hi this is a very good tutorial, I was able to learn the fundamentals of Spring Boot and Angular and I was able to run the project and also created my own. Thank you very much
ReplyDeleteI have a question tho, I'd like to use the API into a simple html file with Jquery ajax. But whenever I try POST or GET I always have this error in the console:
Access to XMLHttpRequest at 'http://localhost:8080/mynotes/api/v1/mynotes?' from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
May I ask how can I fix this issue, is it in my ajax request? or with the spring boot app? Thank you.
Hi i have doubt like
ReplyDeletedo we need to create database and table in MySql or will it created automatically during running application ?
You only need to manually create the database and Hibernate will automatically create tables in that database. I updated this tutorial with explanation so you can have a look.
DeleteI needed to modify the spring.datasource.url and it works perfectly right now.
ReplyDeletespring.datasource.url = jdbc:mysql://localhost/users_database?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
In IntelliJ, the EmployeeController class just fails to do anything with the imports of javax.validation.Valid and the ResourceNotFoundException. There is just no "there" there, and it does not compile of course. I tried to add fitting Maven dependencies, but I just cannot make it work. Any idea what the reason might be?
ReplyDeletePlease update your UPDATE Rest Api to PUT HTTP methos instead of POST
ReplyDelete