Spring Boot with MongoDB Example
In this example, we will build a Spring Boot Application, connect it with a MongoDB database and create REST APIs to insert, read, update, and delete data from the MongoDB database.
Follow the steps below to complete this example:
Create a Spring Boot Project
- Go to Spring Initializr at https://start.spring.io and create a Spring Boot application with details as follows:
- Project: Choose Gradle Project or Maven Project.
- Language: Java
- Spring Boot: Latest stable version of Spring Boot is selected by default. So leave it as is.
- Project Metadata: Provide group name in the Group field. The group name is the id of the project. In Artifact field, provide the name of your project. In the package field, provide package name for your project. Next, select your preferred version of Java that is installed on your computer and is available on your local environment.
- Dependencies: Add dependencies for Spring Web, Spring Boot DevTools, and Spring Data MongoDB.
- Click the GENERATE button and save/download the project zip bundle.
- Extract the project to your preferred working directory.
- Import the project to your preferred Java development IDE such as Eclipse or IntelliJ IDEA.
Refer to the image below for example:

The final project structure of our sample application will look something like this after completion in a hierarchical package presentation view:

Add Dependency
To ensure that the user correctly inputs the data, we will use spring-boot-starter-validation to validate the dto (Data Transfer Object) object. At the time of writing this tutorial, the current version of spring-boot-starter-validation is 2.4.5. Find the latest version of spring-boot-starter-validation in the spring-boot-starter-validation Maven Repository.
For Gradle
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-validation', version: '2.4.5'
For Maven
Add Configurations
Open the application.properties file to add configuration for your application port and MongoDB database connection. Do not forget to update the values of spring.data.mongodb.host, spring.data.mongodb.port , spring.data.mongodb.database, spring.data.mongodb.username, and spring.data.mongodb.password with values that is relevant to your project.
server.port = 8080
# MongoDB Configuration
spring.data.mongodb.host = localhost
spring.data.mongodb.port = 27017
spring.data.mongodb.database = my_database
spring.data.mongodb.username = test
spring.data.mongodb.password = 123456
Create Entity Class
To save students data in database, lets create an entity class. An entity class is an object wrapper for a database table (collection in MongoDB). The attributes of the entity class are mapped to the columns of the database table. This entity class should be annotated with @Document.
Spring provides @CreatedBy, @LastModifiedBy, @CreatedDate, @LastModifiedDate to support the tracking of who created or modified an entity. To benefit from that functionality, you should annotate your main application class with @EnableMongoAuditing which we will do later.
package com.example.springboot.mongodb.model;
import java.time.LocalDateTime;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.mongodb.core.mapping.Document;
@Document(collection = "student")
public class Student {
@Id
private String id;
private String firstName;
private String lastName;
private String email;
private String contactNumber;
private String courseName;
@CreatedDate
private LocalDateTime created;
@LastModifiedDate
private LocalDateTime modified;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getContactNumber() {
return contactNumber;
}
public void setContactNumber(String contactNumber) {
this.contactNumber = contactNumber;
}
public String getCourseName() {
return courseName;
}
public void setCourseName(String courseName) {
this.courseName = courseName;
}
public LocalDateTime getCreated() {
return created;
}
public void setCreated(LocalDateTime created) {
this.created = created;
}
public LocalDateTime getModified() {
return modified;
}
public void setModified(LocalDateTime modified) {
this.modified = modified;
}
}
Create DTO Classes
We will create DTO classes to aggregate and encapsulate data for transfer. DTO is short for Data Transfer Object and is one of the enterprise application architecture patterns. A DTO class should only contains getter/setter methods with serialization and deserialization mechanism but should not contain any business logic.
Using DTOs, you can decide which data to return and which data to not return in remote calls to promote security and loose coupling. However DTOs pattern should not be used in local system calls as it's just a simple feature that should not be over-designed.
package com.example.springboot.mongodb.dto;
import java.time.LocalDateTime;
public class StudentDto {
private String id;
private String firstName;
private String lastName;
private String email;
private String contactNumber;
private String courseName;
private LocalDateTime created;
private LocalDateTime modified;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getContactNumber() {
return contactNumber;
}
public void setContactNumber(String contactNumber) {
this.contactNumber = contactNumber;
}
public String getCourseName() {
return courseName;
}
public void setCourseName(String courseName) {
this.courseName = courseName;
}
public LocalDateTime getCreated() {
return created;
}
public void setCreated(LocalDateTime created) {
this.created = created;
}
public LocalDateTime getModified() {
return modified;
}
public void setModified(LocalDateTime modified) {
this.modified = modified;
}
}
package com.example.springboot.mongodb.dto;
import java.time.LocalDateTime;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
public class StudentNewDto {
private String id;
@NotNull(message = "firstName cannot be empty")
@Size(min = 2, max = 30,
message = "firstName must be atleast of 2 letters and not more then 100 letters")
private String firstName;
@NotNull(message = "lastName cannot be empty")
@Size(min = 2, max = 30,
message = "lastName must be atleast of 2 letters and not more then 100 letters")
private String lastName;
@NotEmpty(message = "email cannot be empty")
@Email
private String email;
private String contactNumber;
private String courseName;
private LocalDateTime created;
private LocalDateTime modified;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getContactNumber() {
return contactNumber;
}
public void setContactNumber(String contactNumber) {
this.contactNumber = contactNumber;
}
public String getCourseName() {
return courseName;
}
public void setCourseName(String courseName) {
this.courseName = courseName;
}
public LocalDateTime getCreated() {
return created;
}
public void setCreated(LocalDateTime created) {
this.created = created;
}
public LocalDateTime getModified() {
return modified;
}
public void setModified(LocalDateTime modified) {
this.modified = modified;
}
}
package com.example.springboot.mongodb.dto;
import java.time.LocalDateTime;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
public class StudentExistingDto {
@NotNull(message = "id cannot be empty")
private String id;
@NotNull(message = "firstName cannot be empty")
@Size(min = 2, max = 30,
message = "firstName must be atleast of 2 letters and not more then 100 letters")
private String firstName;
@NotNull(message = "lastName cannot be empty")
@Size(min = 2, max = 30,
message = "lastName must be atleast of 2 letters and not more then 100 letters")
private String lastName;
@NotEmpty(message = "email cannot be empty")
@Email
private String email;
private String contactNumber;
private String courseName;
private LocalDateTime created;
private LocalDateTime modified;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getContactNumber() {
return contactNumber;
}
public void setContactNumber(String contactNumber) {
this.contactNumber = contactNumber;
}
public String getCourseName() {
return courseName;
}
public void setCourseName(String courseName) {
this.courseName = courseName;
}
public LocalDateTime getCreated() {
return created;
}
public void setCreated(LocalDateTime created) {
this.created = created;
}
public LocalDateTime getModified() {
return modified;
}
public void setModified(LocalDateTime modified) {
this.modified = modified;
}
}
Create Custom Exception Handling Classes
Lets create three classes to handle custom exceptions for this example application.
Create ResourceNotFoundException.class that should be a subclass of RuntimeException class. Any class that extends the RuntimeException makes the class unchecked which means no mandatory exception handling is required for them.
package com.example.springboot.mongodb.exception;
public class ResourceNotFoundException extends RuntimeException {
private static final long serialVersionUID = 1L;
public ResourceNotFoundException(String message) {
super(message);
}
}
Create Error.class Java class with a simple getter/setter methods. The following code shows how to do so:
package com.example.springboot.mongodb.exception;
public class Error {
private String message;
private int status;
private Long timestamp;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public Long getTimestamp() {
return timestamp;
}
public void setTimestamp(Long timestamp) {
this.timestamp = timestamp;
}
}
Create GlobalExceptionHandlerController.class that should be annotated with @ControllerAdvice. Any class annotated with @ControllerAdvice makes it a controller-advice. A controller advice allows to handle exception across the whole application instead of just to a single controller. Exception handling methods should be annotated with @ExceptionHandler.
package com.example.springboot.mongodb.exception;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
@ControllerAdvice
public class GlobalExceptionHandlerController {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<Object> resourceNotFound(ResourceNotFoundException ex,
HttpServletRequest request) {
Error error = new Error();
error.setMessage(ex.getMessage());
error.setTimestamp(new Date().getTime());
error.setStatus(HttpStatus.NOT_FOUND.value());
return new ResponseEntity<>(error, null, HttpStatus.NOT_FOUND);
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Object> badRequest(MethodArgumentNotValidException ex,
HttpServletRequest request) {
Error error = new Error();
error.setMessage(ex.getMessage());
error.setTimestamp(new Date().getTime());
error.setStatus(HttpStatus.BAD_REQUEST.value());
return new ResponseEntity<>(error, null, HttpStatus.BAD_REQUEST);
}
}
Create Repository Interface
To perform CRUD (Create Read Update Delete) operations on the table, create an interface and extend it with MongoRepository interface. The MongoRepository interface provides generic CRUD operations on a repository for a specific type. For this example, we will create StudentRepository.class interface.
package com.example.springboot.mongodb.repository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;
import com.example.springboot.mongodb.model.Student;
@Repository
public interface StudentRepository extends MongoRepository<Student, String> {
public Page<Student> findAll(Pageable pageable);
}
Create Service Interface
Let's create an interface and define some abstract methods which we will implement in another class.
package com.example.springboot.mongodb.service;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import com.example.springboot.mongodb.dto.StudentDto;
import com.example.springboot.mongodb.dto.StudentExistingDto;
import com.example.springboot.mongodb.dto.StudentNewDto;
public interface StudentService {
StudentDto addStudent(StudentNewDto studentNewDto);
StudentDto updateStudent(StudentExistingDto studentExistingDto);
void deleteStudent(String studentId);
StudentDto getStudentById(String studentId);
Page<StudentDto> getAllStudents(Pageable pageable);
}
Create Service Implementation Class
Next, we will create a class to implement the methods of the interface we just created. This implementation class should be annotated with @Service. The @Service annotation indicates that the annotated class is a service class where methods with your business logic should be implemented.
package com.example.springboot.mongodb.service.impl;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import com.example.springboot.mongodb.dto.StudentDto;
import com.example.springboot.mongodb.dto.StudentExistingDto;
import com.example.springboot.mongodb.dto.StudentNewDto;
import com.example.springboot.mongodb.exception.ResourceNotFoundException;
import com.example.springboot.mongodb.model.Student;
import com.example.springboot.mongodb.repository.StudentRepository;
import com.example.springboot.mongodb.service.StudentService;
@Service
public class StudentServiceImpl implements StudentService {
@Autowired
private StudentRepository studentRepository;
@Override
public StudentDto addStudent(StudentNewDto studentNewDto) {
Student student = new Student();
student.setId(studentNewDto.getId());
student.setFirstName(studentNewDto.getFirstName());
student.setLastName(studentNewDto.getLastName());
student.setEmail(studentNewDto.getEmail());
student.setContactNumber(studentNewDto.getContactNumber());
student.setCourseName(studentNewDto.getCourseName());
student = studentRepository.save(student);
StudentDto studentDto = new StudentDto();
studentDto.setId(student.getId());
studentDto.setFirstName(student.getFirstName());
studentDto.setLastName(student.getLastName());
studentDto.setEmail(student.getEmail());
studentDto.setContactNumber(student.getContactNumber());
studentDto.setCourseName(student.getCourseName());
studentDto.setCreated(student.getCreated());
studentDto.setModified(student.getModified());
return studentDto;
}
@Override
public StudentDto updateStudent(StudentExistingDto studentExistingDto) {
Optional<Student> studentOpt = studentRepository.findById(studentExistingDto.getId());
if (!studentOpt.isPresent()) {
throw new ResourceNotFoundException("student not found");
}
Student student = studentOpt.get();
student.setFirstName(studentExistingDto.getFirstName());
student.setLastName(studentExistingDto.getLastName());
student.setEmail(studentExistingDto.getEmail());
student.setContactNumber(studentExistingDto.getContactNumber());
student.setCourseName(studentExistingDto.getCourseName());
student = studentRepository.save(student);
StudentDto studentDto = new StudentDto();
studentDto.setId(student.getId());
studentDto.setFirstName(student.getFirstName());
studentDto.setLastName(student.getLastName());
studentDto.setEmail(student.getEmail());
studentDto.setContactNumber(student.getContactNumber());
studentDto.setCourseName(student.getCourseName());
studentDto.setCreated(student.getCreated());
studentDto.setModified(student.getModified());
return studentDto;
}
@Override
public void deleteStudent(String studentId) {
if (studentId == null) {
throw new IllegalArgumentException("studentId must not be null");
}
Optional<Student> studentOpt = studentRepository.findById(studentId);
if (!studentOpt.isPresent()) {
throw new ResourceNotFoundException("student not found");
}
studentRepository.deleteById(studentId);
}
@Override
public StudentDto getStudentById(String studentId) {
if (studentId == null) {
throw new IllegalArgumentException("studentId must not be null");
}
Optional<Student> studentOpt = studentRepository.findById(studentId);
if (!studentOpt.isPresent()) {
throw new ResourceNotFoundException("student not found");
}
Student student = studentOpt.get();
StudentDto studentDto = new StudentDto();
studentDto.setId(student.getId());
studentDto.setFirstName(student.getFirstName());
studentDto.setLastName(student.getLastName());
studentDto.setEmail(student.getEmail());
studentDto.setContactNumber(student.getContactNumber());
studentDto.setCourseName(student.getCourseName());
studentDto.setCreated(student.getCreated());
studentDto.setModified(student.getModified());
return studentDto;
}
@Override
public Page<StudentDto> getAllStudents(Pageable pageable) {
Page<Student> studentsPage = studentRepository.findAll(pageable);
List<StudentDto> studentsDto = new ArrayList<>();
Page<StudentDto> studentsDtoPage = new PageImpl<>(studentsDto, pageable, 0);
if (studentsPage != null && !studentsPage.isEmpty()) {
studentsPage.getContent().forEach(student -> {
StudentDto studentDto = new StudentDto();
studentDto.setId(student.getId());
studentDto.setFirstName(student.getFirstName());
studentDto.setLastName(student.getLastName());
studentDto.setEmail(student.getEmail());
studentDto.setContactNumber(student.getContactNumber());
studentDto.setCourseName(student.getCourseName());
studentDto.setCreated(student.getCreated());
studentDto.setModified(student.getModified());
studentsDto.add(studentDto);
});
studentsDtoPage =
new PageImpl<>(studentsDto, pageable, studentsPage.getTotalElements());
}
return studentsDtoPage;
}
}
Create a Resource Controller
Create a StudentController.java Java controller class. A Controller is an entry point to consume requests from frontend applications and other services. To create REST APIs in Spring Boot, a controller class should be annotated with @RestController.
package com.example.springboot.mongodb.controller;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.data.web.SortDefault;
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.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.springboot.mongodb.dto.StudentDto;
import com.example.springboot.mongodb.dto.StudentExistingDto;
import com.example.springboot.mongodb.dto.StudentNewDto;
import com.example.springboot.mongodb.service.StudentService;
@RestController
@RequestMapping(path = "/students")
public class StudentController {
@Autowired
private StudentService studentService;
@PostMapping(path = "/add")
public ResponseEntity<StudentDto> addStudent(@RequestBody @Valid StudentNewDto studentNewDto) {
StudentDto student = studentService.addStudent(studentNewDto);
return ResponseEntity.ok(student);
}
@PostMapping(path = "/update")
public ResponseEntity<StudentDto> updateStudent(
@RequestBody @Valid StudentExistingDto studentExistingDto) {
StudentDto student = studentService.updateStudent(studentExistingDto);
return ResponseEntity.ok(student);
}
@DeleteMapping(path = "/{studentId}/delete")
public void deleteStudent(@PathVariable(name = "studentId") String studentId) {
studentService.deleteStudent(studentId);
}
@GetMapping(path = "/{studentId}")
public ResponseEntity<StudentDto> getStudent(
@PathVariable(name = "studentId") String studentId) {
StudentDto student = studentService.getStudentById(studentId);
return ResponseEntity.ok(student);
}
@GetMapping(path = "/all")
public ResponseEntity<Page<StudentDto>> getStudents(@PageableDefault(page = 0,
size = 30) @SortDefault.SortDefaults({@SortDefault(sort = "modified",
direction = Sort.Direction.DESC)}) Pageable pageable) {
Page<StudentDto> students = studentService.getAllStudents(pageable);
return ResponseEntity.ok(students);
}
}
Enable Mongo JPA Auditing
To enable Auditing, the main Spring Boot Application class should be annotated with @EnableMongoAuditing.
package com.example.springboot.mongodb;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.mongodb.config.EnableMongoAuditing;
@EnableMongoAuditing
@SpringBootApplication
public class SpringbootMongodbDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootMongodbDemoApplication.class, args);
}
}
Summary
Congratulations! You have learned how to use MongoDB with Spring Boot.