Spring Boot MongoDB

Bem-vindo ao exemplo do Spring Boot com MongoDB. O Spring Boot é a maneira mais fácil de iniciar rapidamente um projeto Spring, e o MongoDB é o banco de dados NoSQL mais popular. Vamos ver como integrar o Spring com o banco de dados MongoDB.

Spring Boot MongoDB

Para trabalhar com o Spring Boot e o banco de dados MongoDB, precisamos das seguintes APIs.

  • Spring Data MongoDB
  • Spring Boot

Há duas abordagens para se conectar ao banco de dados MongoDB – MongoRepository e MongoTemplate. Vamos tentar entender o que cada API oferece e quando você deve escolher uma delas para o seu caso de uso. Vamos usar a ferramenta Spring Initializr para configurar rapidamente o projeto. Então, vamos começar.

Configuração do Projeto Spring Boot MongoDB

Vamos usar a ferramenta Spring Initializr para configurar rapidamente o projeto. Vamos usar apenas duas dependências, como mostrado abaixo: Baixe o projeto e descompacte-o. Em seguida, importe-o para o seu IDE favorito – Eclipse ou IntelliJ IDEA.

Dependências do Maven

Embora já tenhamos concluído a configuração com a ferramenta, se você quiser configurá-la manualmente, usamos o sistema de compilação Maven para este projeto e aqui estão as dependências 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>

Certifique-se de usar a versão estável para o Spring Boot do repositório central do Maven.

Classe de Modelo do MongoDB para Spring Boot

Temos uma classe de modelo simples 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 do MongoDB para Spring Boot

Teremos as seguintes funcionalidades e interações com o banco de dados em nosso aplicativo.

  • Obter todos os usuários
  • Obter um usuário pelo ID
  • Obter configurações do usuário
  • Obter uma chave específica do Mapa
  • Adicionar/Atualizar configuração do usuário

Spring Data MongoDB – MongoRepository

Agora vamos usar o repositório do Spring Data MongoDB para acessar nossos dados. O Spring Data MongoRepository nos fornece funcionalidades comuns que podemos facilmente conectar e utilizar. Vamos definir nossa interface de Repositório.

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

Definindo propriedades do MongoDB

Antes de prosseguirmos com nosso controlador, é importante que façamos uma conexão com uma instância local do MongoDB. Vamos usar as propriedades do Spring Boot para fazer isso.

#Configuração do 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

# Configuração do aplicativo
server.port=8102
spring.application.name=BootMongo
server.context-path=/user

Então, o aplicativo será executado na porta 8102 e se conectará a uma instância local do mongoDB com as credenciais fornecidas. Se você tiver uma instância local sem autorização ativada, pode simplesmente remover as três primeiras linhas de configuração.

Definindo o Controlador Spring

Vamos finalmente passar para a criação de nossa classe de 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 Autowired a dependência da interface do repositório e a utilizaremos a seguir.

Definindo as APIs

Para as funcionalidades mencionadas, agora estaremos criando APIs e acessando a dependência do userRepository, que internamente utilizará a API Spring Data MongoRepository. Observe que não precisamos escrever nenhum código de interação com o banco de dados na interface, pois o Spring Data faz tudo para nós.

Obtendo todos os usuários

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

findAll() é apenas um método que o Spring Data MongoRepository fornece internamente.

Obtendo um usuário por ID

Agora, vamos obter um usuário específico com um 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() é apenas um método que o Spring Data MongoRepository fornece internamente para obter um objeto por um ID.

Adicionando um novo usuário

Vamos adicionar um novo usuário na função abaixo.

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

Obtendo configurações do usuário

Agora que adicionamos dados de exemplo no banco de dados, vamos tentar extrair uma parte deles.

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

Obtendo uma configuração de usuário específica

@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 na consulta acima que obtemos o objeto do usuário, depois extraímos o mapa de Configuração completo (que poderia conter milhares de objetos) e, finalmente, obtivemos nosso próprio valor. Isso é uma desvantagem para a consulta do Spring Data quando a usamos como API direta.

Adicionando uma nova configuração de usuário

Vamos tentar adicionar alguns dados a um usuário 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.";
	}
}

Com todo o código que escrevemos, está claro que não precisamos escrever uma única linha de código para acessar o banco de dados, além de definir a interface do repositório e injetar a dependência automaticamente. Esta é a facilidade que a API Spring Data MongoRepository nos oferece, mas também tem algumas desvantagens. Vamos elaborar isso quando tivermos definido a versão do MongoTemplate também. Vamos começar com isso também.

Spring Data MongoDB – MongoTemplate

Aqui vamos definir as consultas do banco de dados usando o MongoTemplate. Com o MongoTemplate, você verá que temos um controle muito mais granular sobre o que consultamos e quais dados estão incluídos nos resultados.

Definindo a interface de acesso aos dados

Para fornecer um contrato na camada de acesso ao banco de dados, começaremos definindo uma interface que funciona exatamente como nossos métodos internos do 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 a interface de acesso aos dados

Vamos seguir em frente e definir esses 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);
		// Agora, o objeto do usuário conterá também o 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.";
		}
	}
}

As implementações dos métodos na classe acima estão usando a dependência do MongoTemplate. Veja como o método getUserById(...) obtém o usuário. Construímos uma consulta e passamos os parâmetros necessários. O que mais vai te interessar é a consulta getUserSetting. Vamos entender o que aconteceu acima:

  • Construímos consultas com critérios para verificar igualdade.
  • O método include inclui os nomes dos campos que o resultado deve conter quando é extraído do banco de dados. Isso significa, neste caso, a chave userSettings será extraída o que economizará muitos dados para serem buscados, o que não é necessário.
  • Também consultamos tanto o usuário quanto a chave do mapa. Se algum deles não for encontrado, retornamos dados vazios, o que significa que a chave necessária não foi encontrada. Isso economiza até mesmo a busca pelo objeto User se a chave necessária não estiver presente.

Execução de Teste do Spring Data MongoDB

Podemos executar este aplicativo simplesmente usando um único comando:

mvn spring-boot:run

Assim que o aplicativo estiver em execução, podemos tentar salvar um novo usuário usando esta API:

https://localhost:8102/user/create

Como este será uma solicitação POST, também estaremos enviando dados JSON:

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

Como estamos retornando a resposta do Mongo em si, obteremos algo como:

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

Você pode obter todos os usuários usando a API como uma solicitação GET:

https://localhost:8102/user/

Receberemos algo como:

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

Se você observar a classe UserController acima, não conectamos o MongoTemplate para ser usado. O trecho de código abaixo mostra as alterações necessárias para usar o MongoTemplate para ler as configurações do usuário.

//define objeto de camada de acesso a dados
private final UserDAL userDAL;

//inicialize o objeto DAL via injeção de dependência no construtor
public UserController(UserRepository userRepository, UserDAL userDAL) {
	this.userRepository = userRepository;
	this.userDAL = userDAL;
}

//altere a implementação do método para usar o DAL e, portanto, o 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.";
    }
}

//altere a implementação do método para usar o DAL e, portanto, o MongoTemplate
@RequestMapping(value = "/settings/{userId}/{key}", method = RequestMethod.GET)
public String getUserSetting(
        @PathVariable String userId, @PathVariable String key) {
    return userDAL.getUserSetting(userId, key);
}

Reinicie o aplicativo e execute cenários para obter todas as configurações do usuário e obter qualquer chave específica. A imagem abaixo mostra a saída do aplicativo Postman.

MongoTemplate vs MongoRepository

  • O MongoTemplate fornece muito mais controle quando se trata de consultar dados e quais dados buscar do banco de dados.
  • Os repositórios de dados do Spring nos fornecem uma perspectiva conveniente sobre como buscar dados.
  • O MongoTemplate depende do banco de dados. O que isso significa é que, com os repositórios de dados do Spring, você pode facilmente mudar para um banco de dados diferente simplesmente usando outros repositórios de dados do Spring para MySQL ou Neo4J ou qualquer outra coisa. Isso não é possível com o MongoTemplate.

Resumo do Spring Boot MongoDB

Nesta lição, analisamos como o MongoTemplate pode nos oferecer mais controle sobre os repositórios de dados do Spring, mas também pode ser um pouco complicado quando consultas mais profundas estão envolvidas. Portanto, essa é completamente sua decisão sobre o que escolher ao desenvolver sua ideia. Sinta-se à vontade para deixar comentários abaixo. Faça o download do código-fonte a partir do link abaixo. Por favor, certifique-se de alterar as credenciais do MongoDB antes de executar o aplicativo fornecido.

Baixe o Projeto de Exemplo do Spring Boot MongoDB

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