Aplikacja Spring Boot ze Spring REST i Spring Data MongoDB

MongoDB to potężny, zorientowany na dokumenty system zarządzania bazami danych o otwartym kodzie źródłowym, znany ze swojej elastyczności, skalowalności i szerokiego zakresu funkcji. Jest to część rodziny systemów baz danych NoSQL, zaprojektowanych do obsługi dużych ilości danych i zapewniających wysoką wydajność, wysoką dostępność i łatwą skalowalność. MongoDB przechowuje dane w dokumentach podobnych do JSON w parach klucz-wartość, co pozwala na Java Spring Boot aby wykorzystać Struktura JSON w kodzie.

Spring Boot z MongoDB

Możemy natknąć się na sytuacje, w których używamy Spring Boot z Bazy danych SQL, ale aby wykorzystać MongoDB ze Spring boot, Spring Data MongoDB oferuje lekki dostęp do danych repozytorium i obsługę bazy danych MongoDB, co zmniejsza złożoność kodu.

Zakładając, że mają Państwo dość dobre zrozumienie MongoDB, przyjrzymy się budowaniu aplikacji Spring Boot z Spring Data MongoDB.

Wymagania wstępne

6 kroków do stworzenia aplikacji Spring Boot z Spring REST i Spring Data MongoDB

W tym artykule użyłem MongoDB Atlas bazy danych, która jest wielochmurową usługą bazodanową dla deweloperów, która umożliwia bezpłatne tworzenie i utrzymywanie baz danych w chmurze. Użyłem również MongoDB Compass, narzędzie GUI do wizualizacji bazy danych. Jeśli nie mają Państwo konta w MongoDB Atlas, można je wypróbować za darmo.

Krok 1: Tworzenie aplikacji Spring Boot za pomocą Spring Initializer

W pierwszej kolejności należy utworzyć aplikację Spring Boot przy użyciu Spring Initializr, który generuje projekt Spring Boot z wybranymi zależnościami. Po wybraniu pól, jak pokazano na poniższym obrazku, proszę kliknąć przycisk Generate, iProszę przenieść wyodrębniony projekt do IDE.

Proszę wygenerować aplikację Spring Boot przy użyciu inicjalizatora Spring

Struktura projektu:

Struktura projektu z "Student" podkreślono

Krok 2: Konfiguracja bazy danych

Aby skonfigurować MongoDB w aplikacji Spring boot, dodamy adres URL bazy danych w pliku src/main/resources/application.properties jak pokazano poniżej:

spring.data.mongodb.uri = mongodb+srv://username:password@student.port.mongodb.net/student

Model:

MongoDB to nierelacyjna baza danych zorientowana na dokumenty. Stworzyliśmy Student oraz Adres Model Java do przechowywania obiektów. @Document adnotacja służy do podania niestandardowej nazwy kolekcji, a @Field służy do podania niestandardowej nazwy klucza dla obiektu.

W poniższym kodzie stworzyliśmy przykład zmiennych z różnymi typami danych, takimi jak Data, Lista itp.

Student.java

package com.example.studentmanagementsystem.model;

import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;

import java.time.LocalDate;
import java.util.List;

@Document("Student")
public class Student {
    @Id
    @Indexed(unique = true)
    private String id;
    private String name;
    private double cgpa;
    @Field("has_arrears")
    private boolean hasArrears;
    @Field("course_list")
    private List<String> courseList;
    private Address address;
    @Field("enrollment_date")
    @JsonFormat
            (shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy")
    private LocalDate enrollmentDate;
}

Address.java

package com.example.studentmanagementsystem.model;

import jakarta.persistence.Entity;
import org.springframework.data.mongodb.core.mapping.Field;

@Entity
public class Address {
    private String street;
    private String city;
    private String state;
    private String country;
    @Field("zip_code")
    private String zipcode;
}

Krok 3: Tworzenie repozytorium

Stworzyliśmy interfejs StudentRepository, które rozciąga się na MongoRepository. MongoRepository to interfejs dostarczany przez Spring Data, który umożliwia predefiniowane operacje CRUD i automatyczne mapowanie. Operacje CRUD lub REST to nic innego jak komunikacja między usługami i danymi w trwały i ustrukturyzowany sposób.

Spring @Repository służy do wskazania, że klasa zapewnia mechanizm przechowywania, pobierania, wyszukiwania, aktualizacji i usuwania operacji na obiektach i działa jako warstwa trwałości.

Utwórzmy metody findBy do pobierania danych z bazy danych, jak pokazano w poniższym kodzie:

package com.example.studentmanagementsystem.repository;
import com.example.studentmanagementsystem.model.Student;
import org.springframework.data.mongodb.repository.Aggregation;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;
import java.time.LocalDate;
import java.util.List;

@Repository
public interface StudentRepository extends MongoRepository<Student, String> {
    List<Student> findByNameAndCgpa(String name, Double cgpa);

    Student findByAddress_City(String city);

    List<Student> findByAddress_CountryOrHasArrears(String country, Boolean hasArrears);

    List<Student> findByEnrollmentDateBetweenOrderByEnrollmentDate(LocalDate startDate, LocalDate endDate);

    List<Student> findByCgpaGreaterThanEqual(Double cgpa);

    String findByNameIgnoreCase(String name);

    List<Student> findByCgpaOrderByNameDesc(Double cgpa, String name);
  
//aggregation example for overall average cgpa
    @Aggregation("{ $group : { _id : null, averageCgpa : { $avg : $cgpa} } }")
    Long avgCgpa();

}

Krok 4: Tworzenie usługi

Zbudujmy warstwę usług dla repozytorium Student, aby komunikować się z danymi w bazie danych MongoDB. Stworzymy kilka metod, aby wykorzystać operacje CRUD, takie jak metody wstawiania, pobierania i usuwania.

package com.example.studentmanagementsystem.service;

import com.example.studentmanagementsystem.model.Student;
import com.example.studentmanagementsystem.repository.StudentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.util.List;
import java.util.Optional;

@Service
public class StudentService {
    @Autowired
    private StudentRepository studentRepo;

    public void addStudentData(Student studentDetails) {
        studentRepo.insert(studentDetails);
    }

    public void addMultipleStudentsData(List<Student> studentsDetail) {
        studentRepo.insert(studentsDetail);
    }

    public List<Student> fetchAllStudentsData() {
        return studentRepo.findAll();
    }

    public Optional<Student> fetchStudentDataById(String id) {
        return studentRepo.findById(id);
    }

    public List<Student> fetchStudentDataByNameAndCgpa(String name, Double cgpa) {
        return studentRepo.findByNameAndCgpa(name, cgpa);
    }

    public Student fetchStudentDataByCity(String city) {
        return studentRepo.findByAddress_City(city);
    }

    public List<Student> fetchStudentDataByCountryOrArrears(String country, Boolean hasArrears) {
        return studentRepo.findByAddress_CountryOrHasArrears(country, hasArrears);
    }

    public List<Student> fetchStudentDataByCgpa(Double cgpa) {
        return studentRepo.findByCgpaGreaterThanEqual(cgpa);
    }

    public List<Student> fetchStudentDataByEnrollmentDate(LocalDate startDate, LocalDate endDate) {
        return studentRepo.findByEnrollmentDateBetweenOrderByEnrollmentDate(startDate, endDate);
    }

    public List<Student> fetchStudentDataByCgpaAndName(Double cgpa, String name) {
        return studentRepo.findByCgpaOrderByNameDesc(cgpa, name);
    }

    public Long fetchAverageCgpa() {
        return studentRepo.avgCgpa();
    }

    public String fetchStudentDataByName(String name) {
        return studentRepo.findByNameIgnoreCase(name);
    }

    public void deleteStudentData(Student studentDetails) {
        studentRepo.insert(studentDetails);
    }

    public void deleteAllStudentData() {
        studentRepo.deleteAll();
    }
}

Krok 5: Tworzenie kontrolera

Następnie należy utworzyć wywołania CRUD REST API dla zasobu Student w celu pobierania, wstawiania lub usuwania zasobów w bazie danych MongoDB.

The Spring @RestController jest używana do tworzenia usług internetowych RESTful i łączy w sobie adnotacje @Controller i @Responsebody, ułatwiając pisanie metod obsługi.

package com.example.studentmanagementsystem.controller;

import com.example.studentmanagementsystem.model.Student;
import com.example.studentmanagementsystem.service.StudentService;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDate;
import java.util.List;
import java.util.Optional;

@RestController
@RequestMapping("/student")
public class StudentController {
    @Autowired
    private StudentService studentService;

    @PostMapping("/addStudent")
    public void populateStudentData(@RequestBody Student student){
          studentService.addStudentData(student);
    }

    @PostMapping("/addStudentsData")
    public void populateStudentsData(@RequestBody List<Student> students){
        studentService.addMultipleStudentsData(students);
    }

    @GetMapping("/getAllStudentsData")
    public List<Student> fetchAllStudentsData(){
        return studentService.fetchAllStudentsData();
    }

    @GetMapping("/getStudentById/{id}")
    public Optional<Student> fetchStudentDataById(@PathVariable String id){
       return studentService.fetchStudentDataById(id);
    }
    @GetMapping("/getStudentByNameAndCgpa")
    public List<Student> fetchStudentDataByNameAndCgpa(@RequestParam String name, @RequestParam Double cgpa){
        return studentService.fetchStudentDataByNameAndCgpa(name, cgpa);
    }
    @GetMapping("/getStudentByCity/{city}")
    public Student fetchStudentDataByCity(@PathVariable String city){
        return studentService.fetchStudentDataByCity(city);
    }
    @GetMapping("/getStudentByCountryOrArrears")
    public List<Student> fetchStudentDataByCountryOrArrears(@RequestParam String country,@RequestParam Boolean hasArrears){
        return studentService.fetchStudentDataByCountryOrArrears(country, hasArrears);
    }
    @GetMapping("/getStudentByEnrollmentDate")
    public List<Student> fetchStudentDataByEnrollmentDate(@JsonFormat
                                                                      (shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy") LocalDate startDate, @JsonFormat
            (shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy") LocalDate endDate){
        return studentService.fetchStudentDataByEnrollmentDate(startDate, endDate);
    }
    @GetMapping("/getStudentByName")
    public String fetchStudentDataByName(@RequestParam String name){
        return studentService.fetchStudentDataByName(name);
    }
    @GetMapping("/getStudentByCgpa")
    public List<Student> fetchStudentDataByCgpa(@RequestParam Double cgpa){
        return studentService.fetchStudentDataByCgpa(cgpa);
    }
    @GetMapping("/getAvgCgpa")
    public Long fetchStudentAvgCgpa(){
        return studentService.fetchAverageCgpa();
    }
    @DeleteMapping("/deleteStudent")
    public void deleteStudentData(Student student){
        studentService.deleteStudentData(student);
    }

    @DeleteMapping("/deleteAllStudents")
    public void deleteAllStudentsData(){
        studentService.deleteAllStudentData();
    }
}

Krok 6: Testowanie

Przetestujmy teraz jedno z wywołań API w Postmanie, aby pobrać dane z bazy danych, jak pokazano na poniższym obrazku.

Poniższa metoda HTTP zwraca wszystkie informacje o uczniu w tablicy obiektów JSON.

  1. Metoda: GET

Adres URL żądania: http://localhost:8080/student/getAllStudentsData

Pobieranie danych z bazy danych za pomocą Postmana

Zbudowaliśmy aplikację Spring Boot wykorzystującą bazę danych MongoDB i stworzyliśmy operacje CRUD, takie jak tworzenie, usuwanie i pobieranie danych z bazy danych, w tym różne sposoby pobierania danych. Spring Data MongoDB pomaga nam korzystać z wbudowanych metod dla operacji CRUD, co zmniejsza złożoność kodu w warstwie trwałości.