Olá pessoal! Bem-vindos ao artigo desta semana.
Você pode consultar os artigos anteriores aqui e o código está disponível no meu GitHub, basta acessar aqui.
A API que criamos está funcionando bem, mas tem um pequeno problema: toda vez que reiniciamos a aplicação, os dados cadastrados são perdidos. Isso não é prático nem reflete o que acontece numa aplicação do mundo real. Para resolver isso, vamos adicionar um banco de dados.
Na API do TV Show Buddy, vamos optar por um banco não relacional e usar o MongoDB Atlas, que é um serviço de banco de dados em nuvem. Ele facilita muito a vida de quem está começando, pois não é necessário instalar nada, e a versão gratuita já é suficiente para este projeto.
Para começar, crie uma conta no site do MongoDB Atlas e configure um cluster gratuito conforme prints abaixo.
IMPORTANTE: Lembre-se de liberar o seu IP atual para conseguir se conectar ao banco de dados dentro de “Network Access”.
Cluster criado? Show! Agora é só adicionar a dependência do MongoDB no pom.xml conforme abaixo:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
Essa dependência permite que o Spring Boot se conecte ao MongoDB e use diversas funcionalidades que facilitam o trabalho com banco de dados. Além de salvar, buscar e deletar documentos, ela também oferece recursos como consultas personalizadas, paginação (Vou voltar nesse assunto futuramente) - tudo isso sem precisar escrever muitos códigos manualmente.
E temos que adicionar uma nova classe que será responsável pela conexão com o banco. Essa é uma classe genérica e pode ser adaptada para ser utilizada em outros projetos.
@Slf4j
@Configuration
public class MongoConfig {
@Value("${mongo.user}")
private String mongoUser;
@Value("${mongo.password}")
private String mongoPassword;
@Value("${mongo.host}")
private String mongoHost;
@Bean
public MongoClient mongoClient() {
String connectionString = String.format(
"mongodb+srv://%s:%s@%s",
mongoUser, mongoPassword, mongoHost
);
log.info("Trying to connect to MongoDB.");
try {
MongoClient mongoClient = MongoClients.create(connectionString);
log.info("Connection to MongoDB successful!");
return mongoClient;
} catch (Exception e) {
log.error("Failed to connect to MongoDB: {}", e.getMessage(), e);
throw e;
}
}
}
E atualizar o application.properties
spring.application.name=tvshowbuddy
mongo.user=${MONGO_USER:}
mongo.password=${MONGO_PASSWORD:}
mongo.host=${MONGO_HOST:}
Para rodar a API, basta preencher as variáveis de ambiente diretamente no Intellij, adicionar o valor MONGO_USER={{seu_usuario}};MONGO_PASSWORD={{sua_senha}};MONGO_HOST={{seu_host}}
O valor do seu host pode ser obtido na opção "Connect" do seu cluster.
O próximo passo é ajustar a classe Series que criamos anteriormente para que ela represente o documento que será salvo no banco de dados.
Um documento é um registro com todas as informações que queremos guardar. Exemplo: ano de lançamento, nome da série etc.
Alteração na classe Series
A anotação @Document(collection = "series") indica que a classe Series representa um documento. O atributo collection = "series" especifica que os dados dessa classe serão armazenados na coleção chamada series. Pense na coleção como o equivalente a uma tabela em um banco de dados relacional, mas no MongoDB ela armazena documentos no formato JSON.
Já a anotação @Id marca o campo id como o identificador único do documento. No MongoDB, cada documento precisa de um identificador chamado "_id", que serve para diferenciá-lo dos demais (E usaremos ele para buscar uma série específica). No nosso caso, o id que será gerado automaticamente.
Lembra que comentei sobre o Repository?
Chegou a hora de criar a interface SeriesRepository que estende a interface genérica do MongoRepository, uma interface do Spring Data que fornece operações básicas para manipulação de documentos no MongoDB de forma simplificada e com isso já podemos utilizar os métodos abaixo:
save: Salva ou atualiza uma série no banco.
findById: Busca uma série pelo seu id.
findAll: Lista todas as séries.
deleteById: Deleta uma série pelo id.
Interface SeriesRepository
public interface SeriesRepository extends MongoRepository<Series, String> {
}
Como mostrado no código acima, ao extender o MongoRepository, devemos passar dois parâmetros:
Series: Indica que essa interface está lidando com a classe Series, ou seja, cada documento na coleção series será representado por um objeto Series.
String: Especifica que o tipo do identificador único (id) de cada documento é uma String.
E por fim vamos alterar a classe SeriesService , removendo a lista que simulava o banco de dados e adicionando a SeriesRepository que será responsável por realizar as operações no banco.
@Service
@RequiredArgsConstructor
public class SeriesService {
private final SeriesRepository seriesRepository;
public Series createANewSeries(Series series) {
return seriesRepository.save(series);
}
public List<Series> listAllSeries() {
return seriesRepository.findAll();
}
public Optional<Series> findById(String id) {
return seriesRepository.findById(id);
}
public Optional<Series> updateSeries(String id, Series updatedSeries) {
return seriesRepository.findById(id)
.map(existingSeries -> {
if (updatedSeries.getName() != null && !updatedSeries.getName().trim().isEmpty()) {
existingSeries.setName(updatedSeries.getName());
}
if (updatedSeries.getGenre() != null && !updatedSeries.getGenre().trim().isEmpty()) {
existingSeries.setGenre(updatedSeries.getGenre());
}
if (updatedSeries.getReleaseYear() > 0) {
existingSeries.setReleaseYear(updatedSeries.getReleaseYear());
}
if (updatedSeries.getSeasons() != null && !updatedSeries.getSeasons().isEmpty()) {
if (existingSeries.getSeasons() == null) {
existingSeries.setSeasons(new ArrayList<>());
}
for (Season updatedSeason : updatedSeries.getSeasons()) {
Optional<Season> existingSeason = existingSeries.getSeasons()
.stream()
.filter(s -> s.getSeasonNumber() == updatedSeason.getSeasonNumber())
.findFirst();
if (existingSeason.isPresent()) {
Season seasonToUpdate = existingSeason.get();
if (updatedSeason.getEpisodes() > 0) {
seasonToUpdate.setEpisodes(updatedSeason.getEpisodes());
}
} else {
if (updatedSeason.getSeasonNumber() > 0 && updatedSeason.getEpisodes() > 0) {
existingSeries.getSeasons().add(updatedSeason);
}
}
}
existingSeries.getSeasons().sort(Comparator.comparingInt(Season::getSeasonNumber));
}
return seriesRepository.save(existingSeries);
});
}
public void deleteSeries(String id) {
seriesRepository.deleteById(id);
}
}
Por hoje é isso!
Se ficou com alguma dúvida, deixe nos comentários.
Nos vemos no próximo post! 👋