Spring a MongoDB

 data-srcset
 data-srcset

Pokoušeli jste se napojit Spring [1] aplikaci na MongoDB [2] databázi a nepodařilo se Vám to? Přišel Vám tutoriál od Springu nepřehledný nebo jste nechtěli trávit čas dlouhým pročítáním návodu? Ani pro nás to nebyla procházka růžovou zahradou. Nicméně strasti jsme překonali a v tomto článku si prozradíme celý postup.

Anotace:

Have you ever tried to connect MongoDB to Spring application and was unsuccessful? Was the Spring tutorial too confusing or you did not want to invest your free time with great amount of time by reading the tutorials? It was not easy for us too. But we have solved the downfalls and in this article, we will reveal the secret of successful approach.

Příprava a integrace MongoDB

Prvním a velmi důležitým bodem je stažení a instalace MongoDB databáze. MongoDB je open-source NoSQL dokumentová databáze ukládající data ve formátu BSON (Binary JSON)[3]. Dalším neméně důležitým bodem je vytvoření nového Maven projektu. Oba tyto body jsou nad rámec tohoto článku a nebudu je zde popisovat. Když máme nainstalovanou správnou verzi MongoDB a vytvořen Maven projekt, je vhodný čas začít se samotnou integrací. Můžeme si vybrat ze dvou možností, jak pokračovat.

Spring Boot, první (a rychlejší) možnost, která umožňuje velmi rychlé vytvoření standalone aplikaceve formátu JAR[4]. Také obsahuje nejčastější projekty jako závislosti již v sobě a má vyřešenou kompatibilitu jednotlivých verzí, takže je ideální v případě nové, nezávislé aplikace. Pokud ale chcete napojit již existující aplikaci (například webovou) na MongoDB, budete muset závislosti vyřešit ručně a v takovém případě je třeba velmi důrazně dbát na správnost a kompatibilitu verzí. Jedná se hlavně o následující dvě závislosti:

<dependency>
 <groupId>org.mongodb</groupId>
 <artifactId>mongo-java-driver</artifactId>
</dependency>
<dependency>
 <groupId>org.springframework.data</groupId>
 <artifactId>spring-data-mongodb</artifactId>
</dependency>

V ukázce nejsou záměrně uvedeny verze, protože se budou velmi lišit v závislosti na verzi nainstalované MongoDB. Verze mongo-java-driver by měla být shodná s verzí nainstalované MongoDB, jinak může dojít ke zvláštnímu chování (jako například prázdný seznam existujících kolekcí, I když tam nějaké jsou). Verze spring-data-mongodb by měla být kompatibilní s verzí mongo-java-driver a zde už poradí buď stránky Springu nebo Google. Já se v ukázce rozhodl pro první, tedy rychlejší variantu, použití spring-boot.

Veškeré zdrojové kódy jsou přiloženy k této stránce a můžete si je stáhnout z odkazu pod článkem.

Entita

Vytvoříme si databázovou entitu, nazveme ji například Customer. Tato entita bude mít pro jednoduchost jen 3 atributy – identifikátor, křestní jméno a příjmení. Identifikátor, v případě, že ho anotujeme @Id (pozor na import, správný je org.springframework.data.annotation.Id), bude generován automaticky. Dále vytvoříme konstruktor, do kterého bude vstupovat křestní jméno a příjmení a vygenerujeme gettery. Tímto postupem jsme zajistili, že Customer je immutable a tím pádem i thread-safe. Ještě pro úplnost a přehlednost výpisu vygenerujeme metodu toString().

DAO

Nyní se pustíme do tvorby DAO vrstvy (tzv. Repository). Vytvoříme interface CustomerRepository, který bude extendovat MongoRepository, jehož první typový parametr je typ entity, se kterou tento repository bude manipulovat a druhým je datový typ atributu pro identifikaci (@Id). Díky interface MongoRepository se nám pro entitu Customer zpřístupnily CRUD operace a není proto nutné je explicitně vytvářet.

@Repository
public interface CustomerRepository extends MongoRepository<Customer, String>

Jednodušší custom queries

V případě, že bychom chtěli nějaké custom dotazy, je zde ještě jedna hezká feature. Pokud se jedná o jednoduché dotazy, například vyhledání Customer podle firstName a lastName, můžeme do tohoto interface vložit metodu s následující signaturou:

Customer findByFirstNameAndLastName(String firstName, String lastName);

a Spring nám zařídí implementaci této metody automaticky, není třeba ji tudíž definovat. Seznam všech těchto možných patternů pro metody naleznete zde: http://docs.spring.io/spring-data/data-mongo/docs/1.9.3.RELEASE/reference/html/#mongodb.repositories.queries

Složitější custom queries

Pokud budete potřebovat vytvořit o něco složitější dotazy, je vhodné vytvořit další interface a pojmenovat ho například CustomerRepositoryCustomQueries. Do tohoto interface zadefinovat metodu (v příkladu findAllCustomersSortedByIdDesc):

List<Customer> findAllCustomersSortedByIdDesc();

a zařídit, aby CustomerRepository extendoval i tento náš nový interface.

@Repository
public interface CustomerRepository extends MongoRepository<Customer, String>, CustomerRepositoryCustomQueries

Dalším krokem bude, jak Vás určitě napadlo, implementace této custom query. Vytvoříme tedy CustomerRepositoryImpl (pozor, třída se musí jmenovat přesně takto, jinak budeme dostávat podivné výjimky a debug takovýchto výjimek zabere trochu času – řádově klidně i hodiny a to není zábavná práce J) a necháme tuto třídu implementovat interface CustomerRepositoryCustomQueries.

public class CustomerRepositoryImpl implements CustomerRepositoryCustomQueries

Do této implementace si injectneme pomocí @Autowired anotace Springu MongoTemplate a už můžeme psát dotaz.

Spuštění aplikace a dokončení integrace Springu s MongoDB

Vytvoříme třídu, kterou trefně nazveme například Application a anotujeme ji @SpringBootApplication aby Spring poznal, že tato třída spouští aplikaci a nainicializoval kontext apod. Dále tato třída musí implementovat rozhraní CommandLineRunner (v případě, že chceme aplikaci mít commandline). Celá signatura včetně anotací vypadá takto:

@SpringBootApplication
public class Application implements CommandLineRunner

V této třídě vytvoříme standardní main metodu, která bude obsahovat pouze příkaz ke spuštění Spring aplikace:

public static void main(String[] args) {
 SpringApplication.run(Application.class, args);
}

Tímto se spustí metoda run, která je předepsána rozhraním CommandLineRunner. Nyní už jen stačí v této třídě inject CustomerRepository a integrace Springu s MongoDB databází bylo úspěšně dokončeno.

Možnosti konfigurace ve Springu

Spring jako vždy myslí i na jednoduchou možnost konfigurace. Pokud bychom chtěli změnit URL, port nebo databázi pro připojení k MongoDB, vytvoříme na classpath (nejlépe v src/main/resources) property soubor application.properties. V tomto souboru můžeme měnit různá nastavení Springu a mimo jiné i údaje pro připojení k MongoDB databázi. Pro tento případ Spring připravil následující property:

Název propertyVýchozí hodnotaVysvětlení
spring.data.mongodb.hostlocalhosthostname (URL) k MongoDB databázi
spring.data.mongodb.port27017port k MongoDB databázi
spring.data.mongodb.usernameusername uživatele MongoDB
spring.data.mongodb.passwordheslo uživatele MongoDB
spring.data.mongodb.databasetestdatabáze MongoDB

Výčet veškerých standardizovaných názvů properties (nejen pro MongoDB) naleznete na http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html

Nic ale nebrání tomu vytvořit si vlastní Spring kontext a ten importovat do hlavního kontextu vytvářeného ze třídy Application. Je to jen na Vás.

Závěr

Projekt Spring data pro připojení k MongoDB je velmi hezké zjednodušení práce a nabízí rychlý start Vašeho projektu nebo aplikace. Na druhou stranu je nutné zvážit fakt, že veškeré akce (implementace standardně pojmenovaných metod, inicializace Spring contextu apod.) jsou takový black-box. V případě, že bychom chtěli pochopit, jak vnitřně funguje tento projekt pro účely nějakého ladění, musíme si vyhradit hodně volného času, což na reálných projektech většinou není možné.

[1] Spring logo. Spring Framework forum [online]. [cit. 2017-02-03]. Dostupné z: http://forum.spring.io/core/image.php?userid=38939&dateline=1378757183

[2] MongoDB logo. Theodo – Agile web and mobile development – JS and Symfony experts [online]. [cit. 2017-02-03]. Dostupné z: http://www.theodo.fr/uploads/blog/2015/11/mongodb.png

[3] https://docs.mongodb.com/manual/

[4] http://projects.spring.io/spring-boot/

Zpět

Posuňte s námi své služby dál.

Nasměrujeme vás správným směrem!

Kontakujte nás