Arranque de Primavera MongoDB

Bienvenido al ejemplo de Spring Boot MongoDB. Spring Boot es la forma más fácil de iniciar rápidamente un proyecto de Spring y MongoDB es la base de datos NoSQL más popular. Veamos cómo integrar Spring con la base de datos MongoDB.

Spring Boot MongoDB

Necesitamos las siguientes APIs para trabajar con Spring Boot y la base de datos MongoDB.

  • Spring Data MongoDB
  • Spring Boot

Hay dos enfoques a través de los cuales podemos conectarnos a la base de datos MongoDB: MongoRepository y MongoTemplate. Intentaremos establecer qué API ofrece una sobre la otra y cuándo deberías elegir una de ellas para tu caso de uso. Haremos uso de la herramienta Spring Initializr para configurar rápidamente el proyecto. Así que, empecemos.

Configuración del Proyecto Spring Boot MongoDB

Vamos a hacer uso de la herramienta Spring Initializr para configurar rápidamente el proyecto. Solo utilizaremos dos dependencias como se muestra a continuación: Descarga el proyecto y descomprímelo. Luego impórtalo en tu IDE favorito, ya sea Eclipse o IntelliJ IDEA.

Dependencias de Maven

Aunque ya hemos completado la configuración con la herramienta, si deseas configurarlo manualmente, utilizamos el sistema de construcción Maven para este proyecto y aquí están las dependencias que utilizamos:

<?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>

Asegúrate de usar la versión estable para Spring Boot desde el repositorio central de Maven.

Clase de Modelo de MongoDB de Spring Boot

Tenemos una clase de modelo simple 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;
	}
}

APIs de MongoDB de Spring Boot

Tendremos las siguientes funcionalidades e interacciones con la base de datos en nuestra aplicación.

  • Obtener todos los usuarios
  • Obtener un usuario con ID
  • Obtener configuraciones de usuario
  • Obtener una clave particular del mapa
  • Agregar/Actualizar configuración de usuario

Spring Data MongoDB – MongoRepository

Ahora utilizaremos el repositorio de Spring Data MongoDB para acceder a nuestros datos. Spring Data MongoRepository nos proporciona funcionalidades comunes que podemos integrar fácilmente y utilizarlas. Vamos a definir nuestra interfaz de Repositorio.

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> {
}

Definición de propiedades de MongoDB

Antes de diseñar nuestro controlador, es importante que establezcamos una conexión con una instancia local de MongoDB. Utilizaremos las propiedades de Spring Boot para hacer esto.

# Configuración de MongoDB local
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

# Configuración de la aplicación
server.port=8102
spring.application.name=BootMongo
server.context-path=/user

Por lo tanto, la aplicación se ejecutará en el puerto 8102 y se conectará a una instancia local de mongoDB con las credenciales proporcionadas. Si tiene una instancia local sin autorización habilitada, simplemente puede eliminar las primeras tres líneas de configuración.

Definición del Controlador Spring

Finalmente, pasemos a crear nuestra clase Controlador.

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;
	}
}

Acabamos de autowire la dependencia de la interfaz del repositorio y la usaremos a continuación.

Definición de las API

Para las funcionalidades que mencionamos, ahora crearemos APIs y accederemos a la dependencia del userRepository que internamente utilizará la API Spring Data MongoRepository. Nótese que no tenemos que escribir ningún código de interacción con la base de datos en la interfaz, ya que Spring Data lo hace todo por nosotros.

Obteniendo todos los usuarios

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

findAll() es solo un método que Spring Data MongoRepository proporciona internamente.

Obteniendo un usuario por ID

Ahora, obtengamos un usuario específico con un ID.

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

findOne() es solo un método que Spring Data MongoRepository proporciona internamente para obtener un objeto por un ID.

Agregando un nuevo usuario

Agregaremos un nuevo usuario en la función a continuación.

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

Obteniendo configuraciones de usuario

Ahora que hemos agregado datos de ejemplo a la base de datos, intentemos extraer alguna parte de ella.

@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.";
	}
}

Obteniendo una configuración de usuario en particular

@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.";
	}
}

Observe en la consulta anterior que obtuvimos el objeto de usuario, luego extraímos el mapa de configuración completo (que podría haber contenido miles de objetos) y finalmente obtuvimos nuestro propio valor. Este es un inconveniente de la consulta de Spring Data cuando la usamos como API directa.

Agregando una nueva configuración de usuario

Vamos a intentar agregar datos a un usuario existente:

@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.";
	}
}

Con todo el código que escribimos, está claro que no tuvimos que escribir una sola línea de código para acceder a la base de datos, aparte de definir la interfaz del repositorio y realizar la inyección de dependencias. Esto es lo que nos ofrece la facilidad de la API MongoRepository de Spring Data, pero también tiene algunos inconvenientes. Elaboraremos sobre esto cuando hayamos definido la versión con MongoTemplate. Comencemos también con eso.

Spring Data MongoDB – MongoTemplate

Aquí definiremos las consultas de la base de datos con MongoTemplate. Con MongoTemplate, verás que tenemos un control mucho más granular sobre lo que consultamos y qué datos se incluyen en los resultados.

Definiendo la interfaz de acceso a la base de datos (DAL)

Para proporcionar un contrato en la capa de acceso a la base de datos, comenzaremos definiendo una interfaz que funcione de manera similar a nuestros métodos integrados en Spring Data.

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);
}

Implementando la interfaz DAL

Sigamos y definamos estos métodos.

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);
		// Ahora, el objeto de usuario contendrá también el 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.";
		}
	}
}

Las implementaciones de los métodos en la clase anterior utilizan la dependencia de MongoTemplate. Observa cómo el método getUserById(...) obtiene al usuario. Construimos una consulta y pasamos los parámetros necesarios. Lo que te interesará más es la consulta getUserSetting. Entendamos qué sucedió arriba:

  • Construimos consultas con criterios para verificar la igualdad.
  • El método include incluye los nombres de campo que deben estar presentes en el resultado cuando se extrae de la base de datos. Esto significa que, en este caso, se extraerá la clave userSettings, lo que ahorrará mucha información que no es necesaria
  • También consultamos tanto la clave de usuario como la clave de mapa. Si no se encuentra ninguna de ellas, devolvemos datos vacíos, lo que significa que no se encontró la clave requerida. Esto evita incluso recuperar el objeto de usuario si la clave necesaria no está presente

Prueba de ejecución de Spring Data MongoDB

Podemos ejecutar esta aplicación simplemente usando un solo comando:

mvn spring-boot:run

Una vez que la aplicación esté en ejecución, podemos intentar guardar un nuevo usuario usando esta API:

https://localhost:8102/user/create

Como esto será una solicitud POST, también enviaremos datos JSON:

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

Dado que estamos devolviendo la respuesta de Mongo en sí, obtendremos algo como:

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

Puede obtener todos los usuarios utilizando la API como solicitud GET:

https://localhost:8102/user/

Obtendremos algo como:

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

Si observas la clase UserController anterior, no hemos conectado MongoTemplate para su uso. El fragmento de código a continuación muestra los cambios necesarios para usar MongoTemplate para leer la configuración del usuario.

//definir objeto de capa de acceso a datos
private final UserDAL userDAL;

//inicializar objeto DAL mediante la inyección de dependencias en el constructor
public UserController(UserRepository userRepository, UserDAL userDAL) {
	this.userRepository = userRepository;
	this.userDAL = userDAL;
}

//cambiar la implementación del método para usar DAL y, por lo tanto, MongoTemplate
@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.";
    }
}

//cambiar la implementación del método para usar DAL y, por lo tanto, MongoTemplate
@RequestMapping(value = "/settings/{userId}/{key}", method = RequestMethod.GET)
public String getUserSetting(
        @PathVariable String userId, @PathVariable String key) {
    return userDAL.getUserSetting(userId, key);
}

Reiniciar la aplicación y ejecutar escenarios para obtener todas las configuraciones de usuario y para obtener alguna clave específica. La siguiente imagen muestra la salida de la aplicación Postman.

MongoTemplate vs MongoRepository

  • MongoTemplate proporciona mucho más control cuando se trata de consultar datos y qué datos extraer de la base de datos.
  • Los repositorios de Spring Data nos brindan una perspectiva conveniente sobre cómo obtener datos.
  • MongoTemplate depende de la base de datos. Lo que esto significa es que, con los repositorios de Spring Data, puedes cambiar fácilmente a una base de datos diferente simplemente utilizando otros repositorios de Spring Data para MySQL o Neo4J o cualquier otra cosa. Esto no es posible con MongoTemplate.

Resumen de Spring Boot MongoDB

En esta lección, analizamos cómo MongoTemplate puede brindarnos un mayor control sobre los repositorios de Spring Data, pero también puede ser un poco complicado cuando se involucran consultas más profundas. Entonces, esta es completamente tu decisión de elegir cuando desarrollas tu idea. Siéntete libre de dejar comentarios a continuación. Descarga el código fuente desde el siguiente enlace. Asegúrate de cambiar las credenciales de MongoDB antes de ejecutar la aplicación proporcionada.

Descargar Proyecto de Ejemplo de Spring Boot MongoDB

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