Spring Boot MongoDB

Welkom bij het Spring Boot MongoDB voorbeeld. Spring Boot is de gemakkelijkste manier om snel een Spring-project op te zetten en MongoDB is de meest populaire NoSQL database. Laten we eens kijken hoe we Spring kunnen integreren met de MongoDB-database.

Spring Boot MongoDB

We hebben de volgende API’s nodig om te werken met Spring Boot en de MongoDB-database.

  • Spring Data MongoDB
  • Spring Boot

Er zijn twee benaderingen waarmee we verbinding kunnen maken met de MongoDB-database – MongoRepository en MongoTemplate. We zullen proberen vast te stellen wat de ene API biedt ten opzichte van de andere en wanneer je een van beiden moet kiezen voor jouw gebruiksscenario. We zullen gebruik maken van de Spring Initializr tool om snel het project op te zetten. Dus laten we beginnen.

Spring Boot MongoDB Project Opzet

We zullen de Spring Initializr tool gebruiken om snel het project op te zetten. We gebruiken slechts twee afhankelijkheden zoals hieronder getoond: Download het project en pak het uit. Importeer het vervolgens in jouw favoriete IDE – Eclipse of IntelliJ IDEA.

Maven Afhankelijkheden

Hoewel we de installatie al hebben voltooid met het gereedschap, als je het handmatig wilt instellen, gebruiken we het Maven-buildsysteem voor dit project en hier zijn de afhankelijkheden die we hebben gebruikt:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.journaldev.spring</groupId>
	<artifactId>spring-boot-mongodb</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>spring-boot-mongodb</name>
	<description>Spring Boot MongoDB Example</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.9.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-mongodb</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-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>

Zorg ervoor dat je de stabiele versie gebruikt voor Spring Boot vanuit het Maven-centraal.

Spring Boot MongoDB Modelklasse

We hebben een eenvoudige modelklasse User.java.

package com.journaldev.bootifulmongodb.model;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

@Document
public class User {

	@Id
	private String userId;
	private String name;
	private Date creationDate = new Date();
	private Map<String, String> userSettings = new HashMap<>();

	public String getUserId() {
		return userId;
	}

	public void setUserId(String userId) {
		this.userId = userId;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Date getCreationDate() {
		return creationDate;
	}

	public void setCreationDate(Date creationDate) {
		this.creationDate = creationDate;
	}

	public Map<String, String> getUserSettings() {
		return userSettings;
	}

	public void setUserSettings(Map<String, String> userSettings) {
		this.userSettings = userSettings;
	}
}

Spring Boot MongoDB API’s

We zullen de volgende functionaliteiten en database-interacties hebben in onze app.

  • Haal alle gebruikers op
  • Haal een gebruiker op met ID
  • Haal gebruikersinstellingen op
  • Haal een bepaalde sleutel uit de map op
  • Gebruikersinstelling toevoegen/bijwerken

Spring Data MongoDB – MongoRepository

Nu zullen we de Spring Data MongoDB-repository gebruiken om toegang te krijgen tot onze gegevens. Spring Data MongoRepository biedt ons gemeenschappelijke functionaliteiten die we gemakkelijk kunnen inpluggen en gebruiken. Laten we onze Repository-interface definiëren.

package com.journaldev.bootifulmongodb.dal;

import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;

import com.journaldev.bootifulmongodb.model.User;

@Repository
public interface UserRepository extends MongoRepository<User, String> {
}

Definiëren van MongoDB-eigenschappen

Voordat we onze controller opzetten, is het belangrijk dat we verbinding maken met een lokale instantie van MongoDB. We zullen Spring Boot-eigenschappen gebruiken om dit te doen.

# Lokale MongoDB-configuratie
spring.data.mongodb.authentication-database=admin
spring.data.mongodb.username=root
spring.data.mongodb.password=root
spring.data.mongodb.database=user_db
spring.data.mongodb.port=27017
spring.data.mongodb.host=localhost

# App-configuratie
server.port=8102
spring.application.name=BootMongo
server.context-path=/user

Dus de app zal draaien op poort 8102 en verbinding maken met een lokale MongoDB-instantie met de verstrekte referenties. Als je een lokale instantie hebt zonder ingeschakelde autorisatie, kun je gewoon de eerste drie regels configuratie verwijderen.

Het definiëren van de Spring-controller

Laten we eindelijk overgaan tot het maken van onze Controller-klasse.

package com.journaldev.bootifulmongodb.controller;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.journaldev.bootifulmongodb.dal.UserRepository;
import com.journaldev.bootifulmongodb.model.User;

@RestController
@RequestMapping(value = "/")
public class UserController {

	private final Logger LOG = LoggerFactory.getLogger(getClass());

	private final UserRepository userRepository;

	public UserController(UserRepository userRepository) {
		this.userRepository = userRepository;
	}
}

We hebben zojuist de repository interface-afhankelijkheid geautomatiseerd en zullen dit vervolgens gebruiken.

Het definiëren van de API’s

Voor de functionaliteiten die we hebben genoemd, zullen we nu API’s maken en toegang krijgen tot de userRepository-afhankelijkheid, die intern gebruik zal maken van de Spring Data MongoRepository API. Let op dat we geen code voor database-interactie hoeven te schrijven in de interface omdat Spring Data dat allemaal voor ons doet.

Alle gebruikers ophalen

@RequestMapping(value = "", method = RequestMethod.GET)
public List<User> getAllUsers() {
	LOG.info("Getting all users.");
	return userRepository.findAll();
}

findAll() is gewoon een methode die Spring Data MongoRepository intern biedt.

Een gebruiker op ID ophalen

Laten we nu een specifieke gebruiker met een ID ophalen.

@RequestMapping(value = "/{userId}", method = RequestMethod.GET)
public User getUser(@PathVariable String userId) {
	LOG.info("Getting user with ID: {}.", userId);
	return userRepository.findOne(userId);
}

findOne() is gewoon een methode die Spring Data MongoRepository intern biedt om een object op te halen op basis van een ID.

Een nieuwe gebruiker toevoegen

We zullen een nieuwe gebruiker toevoegen in de onderstaande functie.

@RequestMapping(value = "/create", method = RequestMethod.POST)
public User addNewUsers(@RequestBody User user) {
	LOG.info("Saving user.");
	return userRepository.save(user);
}

Gebruikersinstellingen ophalen

Nu we voorbeeldgegevens aan de database hebben toegevoegd, laten we proberen er een deel van te extraheren.

@RequestMapping(value = "/settings/{userId}", method = RequestMethod.GET)
public Object getAllUserSettings(@PathVariable String userId) {
	User user = userRepository.findOne(userId);
	if (user != null) {
		return user.getUserSettings();
	} else {
		return "User not found.";
	}
}

Een specifieke gebruikersinstelling ophalen

@RequestMapping(value = "/settings/{userId}/{key}", method = RequestMethod.GET)
public String getUserSetting(@PathVariable String userId, @PathVariable String key) {
	User user = userRepository.findOne(userId);
	if (user != null) {
		return user.getUserSettings().get(key);
	} else {
		return "User not found.";
	}
}

Let op in de bovenstaande query dat we het gebruikersobject hebben opgehaald, vervolgens de volledige instellingsmap hebben geëxtraheerd (die duizenden objecten zou kunnen bevatten) en ten slotte onze eigen waarde hebben opgehaald. Dit is een nadeel van Spring Data-query’s wanneer we het rechtstreeks als API gebruiken.

Een nieuwe gebruikersinstelling toevoegen

Laten we proberen wat gegevens toe te voegen aan een bestaande gebruiker:

@RequestMapping(value = "/settings/{userId}/{key}/{value}", method = RequestMethod.GET)
public String addUserSetting(@PathVariable String userId, @PathVariable String key, @PathVariable String value) {
	User user = userRepository.findOne(userId);
	if (user != null) {
		user.getUserSettings().put(key, value);
		userRepository.save(user);
		return "Key added";
	} else {
		return "User not found.";
	}
}

Met alle code die we hebben geschreven, is het duidelijk dat we geen enkele regel code hoefden te schrijven om toegang te krijgen tot de database, afgezien van het definiëren van de repository-interface en het autowiren van de afhankelijkheid. Dit is het gemak dat de Spring Data MongoRepository API ons biedt, maar het heeft ook enkele nadelen. We zullen dit toelichten wanneer we ook de versie met MongoTemplate hebben gedefinieerd. Laten we daar ook mee beginnen.

Spring Data MongoDB – MongoTemplate

We zullen hier de databasequery’s van MongoTemplate definiëren. Met MongoTemplate zult u zien dat we veel meer fijnmazige controle hebben over wat we opvragen en welke gegevens zijn opgenomen in de resultaten.

Het definiëren van de DAL-interface

Om een contract te bieden op het niveau van toegang tot de database, zullen we beginnen met het definiëren van een interface die net als onze ingebouwde methoden van Spring Data werkt.

package com.journaldev.bootifulmongodb.dal;

import java.util.List;

import com.journaldev.bootifulmongodb.model.User;

public interface UserDAL {

	List<User> getAllUsers();

	User getUserById(String userId);

	User addNewUser(User user);

	Object getAllUserSettings(String userId);

	String getUserSetting(String userId, String key);

	String addUserSetting(String userId, String key, String value);
}

Implementatie van de DAL-interface

Laten we doorgaan en deze methoden definiëren.

package com.journaldev.bootifulmongodb.dal;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Repository;

import com.journaldev.bootifulmongodb.model.User;

@Repository
public class UserDALImpl implements UserDAL {

	@Autowired
	private MongoTemplate mongoTemplate;

	@Override
	public List getAllUsers() {
		return mongoTemplate.findAll(User.class);
	}

	@Override
	public User getUserById(String userId) {
		Query query = new Query();
		query.addCriteria(Criteria.where("userId").is(userId));
		return mongoTemplate.findOne(query, User.class);
	}

	@Override
	public User addNewUser(User user) {
		mongoTemplate.save(user);
		// Nu bevat het gebruikersobject ook het ID
		return user;
	}

	@Override
	public Object getAllUserSettings(String userId) {
		Query query = new Query();
		query.addCriteria(Criteria.where("userId").is(userId));
		User user = mongoTemplate.findOne(query, User.class);
		return user != null ? user.getUserSettings() : "User not found.";
	}

	@Override
	public String getUserSetting(String userId, String key) {
		Query query = new Query();
		query.fields().include("userSettings");
		query.addCriteria(Criteria.where("userId").is(userId).andOperator(Criteria.where("userSettings." + key).exists(true)));
		User user = mongoTemplate.findOne(query, User.class);
		return user != null ? user.getUserSettings().get(key) : "Not found.";
	}

	@Override
	public String addUserSetting(String userId, String key, String value) {
		Query query = new Query();
		query.addCriteria(Criteria.where("userId").is(userId));
		User user = mongoTemplate.findOne(query, User.class);
		if (user != null) {
			user.getUserSettings().put(key, value);
			mongoTemplate.save(user);
			return "Key added.";
		} else {
			return "User not found.";
		}
	}
}

De methodenimplementaties in de bovenstaande klasse maken gebruik van de MongoTemplate-afhankelijkheid. Zie hoe de getUserById(...)-methode de gebruiker ophaalt. We construeren een query en geven de vereiste parameters door. Wat u meer interesseert, is waarschijnlijk de getUserSetting-query. Laten we begrijpen wat hierboven is gebeurd:

  • We hebben queries geconstrueerd met criteria om gelijkheid te controleren.
  • De include-methode omvat de veldnamen die het resultaat moet bevatten wanneer het uit de database wordt gehaald. Dit betekent dat in dit geval de userSettings-sleutel zal worden geëxtraheerd, wat veel onnodige gegevens bespaart die moeten worden opgehaald.
  • Ook hebben we gezocht op zowel de gebruikers- als de map-sleutel. Als een van beide niet wordt gevonden, retourneren we lege gegevens, wat betekent dat de vereiste sleutel niet is gevonden. Dit bespaart zelfs het ophalen van het User-object als de vereiste sleutel niet aanwezig was.

Spring Data MongoDB Test Run

We kunnen deze app eenvoudig uitvoeren met een enkele opdracht:

mvn spring-boot:run

Zodra de app draait, kunnen we proberen een nieuwe gebruiker op te slaan met behulp van deze API:

https://localhost:8102/user/create

Omdat dit een POST-verzoek is, sturen we ook JSON-gegevens:

{
  "name" : "Shubham",
  "userSettings" : {
    "bike" : "pulsar"
  }
}

Omdat we het Mongo-response zelf retourneren, krijgen we iets als:

{
  "userId": "5a5f28cc3178058b0fafe1dd",
  "name": "Shubham",
  "creationDate": 1516165830856,
  "userSettings": {
    "bike" : "pulsar"
  }
}

Je kunt alle gebruikers ophalen door de API als GET-verzoek te gebruiken:

https://localhost:8102/user/

We krijgen iets terug zoals:

[
  {
    "userId": "5a5f28cc3178058b0fafe1dd",
    "name": "Shubham",
    "creationDate": 1516165830856,
    "userSettings": {
      "bike" : "pulsar"
    }
  }
]

Als je hierboven de UserController-klasse ziet, hebben we MongoTemplate niet gekoppeld om te worden gebruikt. Onderstaand codefragment toont de vereiste wijzigingen om MongoTemplate te gebruiken voor het lezen van gebruikersinstellingen.

//definieer Data Access Layer object
private final UserDAL userDAL;

//initialiseer DAL object via constructor autowiring
public UserController(UserRepository userRepository, UserDAL userDAL) {
	this.userRepository = userRepository;
	this.userDAL = userDAL;
}

//verander de implementatie van de methode om DAL en dus MongoTemplate te gebruiken
@RequestMapping(value = "/settings/{userId}", method = RequestMethod.GET)
public Object getAllUserSettings(@PathVariable String userId) {
    User user = userRepository.findOne(userId);
    if (user != null) {
        return userDAL.getAllUserSettings(userId);
    } else {
        return "User not found.";
    }
}

//verander de implementatie van de methode om DAL en dus MongoTemplate te gebruiken
@RequestMapping(value = "/settings/{userId}/{key}", method = RequestMethod.GET)
public String getUserSetting(
        @PathVariable String userId, @PathVariable String key) {
    return userDAL.getUserSetting(userId, key);
}

Herstart de app en voer scenario’s uit om alle gebruikersinstellingen te krijgen en om een specifieke sleutel te krijgen. Onderstaande afbeelding toont de uitvoer van de Postman app.

MongoTemplate vs MongoRepository

  • MongoTemplate biedt veel meer controle als het gaat om het opvragen van gegevens en welke gegevens uit de database gehaald moeten worden.
  • Spring Data repositories geven ons een handig overzicht van hoe gegevens op te halen.
  • MongoTemplate is afhankelijk van de database. Dit betekent dat je met Spring Data repositories eenvoudig kunt overschakelen naar een andere database door simpelweg een ander Spring Data repository te gebruiken voor MySQL, Neo4J of iets anders. Dit is niet mogelijk met MongoTemplate.

Samenvatting Spring Boot MongoDB

In deze les hebben we bekeken hoe MongoTemplate ons meer controle kan geven over Spring Data repositories, maar het kan ook wat gecompliceerder zijn wanneer er diepere queries bij betrokken zijn. Dus, het is helemaal aan jou wat je kiest bij het ontwikkelen van je idee. Voel je vrij om hieronder opmerkingen achter te laten. Download de broncode van onderstaande link. Zorg ervoor dat je de MongoDB referenties wijzigt voordat je de meegeleverde app uitvoert.

Download Spring Boot MongoDB Voorbeeldproject

Source:
https://www.digitalocean.com/community/tutorials/spring-boot-mongodb