Monday, February 24, 2014

Spring & MongoTemplate

To keep up with Spring templates theme, I will show you how to use MongoTemplate to access MongoDB. Assuming you are already familiar with MongoDB and the fact that it's a document centric datastore, the first thing we should do is define objects representing documents. In this tutorial, my application will manage books in a MongoDB database. Here is the definition of a book stored as a document.
package com.noushin.spring.monspr.model;

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

/**
 * This class represents a book as a MongoDB document.
 * 
 * @author nbashir
 * 
 */
@Document
public class Book {

   @Id
   private String id;

   @Indexed
   private String name;

   private String author;

   public Book(String id, String name, String author) {
      super();
      this.id = id;
      this.name = name;
      this.author = author;
   }

   public String getId() {
      return id;
   }

   public void setId(String id) {
      this.id = id;
   }

   public String getName() {
      return name;
   }

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

   public String getAuthor() {
      return author;
   }

   public void setAuthor(String author) {
      this.author = author;
   }
}
Now I need a class to access books in MongoDB. This is where I will utilize MongoTemplate.
package com.noushin.spring.monspr.dao;

import java.util.List;

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

import com.noushin.spring.monspr.model.Book;

/**
 * This class handles accessing books in MongoDB.
 * 
 * @author nbashir
 *
 */
@Repository
public class BookRepositroy {
   
   @Autowired
   MongoTemplate mongoTemplate;
      
   public void save(Book book) {
      mongoTemplate.save(book);
   }
   
   public void save(List<Book> books) {
      mongoTemplate.save(books);
   }

   public Book get(String id) {
      return mongoTemplate.findById(id, Book.class);
   }
   
   public List<Book> getAll() {
      return mongoTemplate.findAll(Book.class);
   }
   
   public void delete(Book book) {
      mongoTemplate.remove(book);
   }
}
And a typical class to place in the service layer:
package com.noushin.spring.monspr.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.noushin.spring.monspr.dao.BookRepositroy;
import com.noushin.spring.monspr.model.Book;

/**
 * This class handles any business logic related to handling books.
 * 
 * @author nbashir
 *
 */
@Component
public class BookService {

   @Autowired 
   BookRepositroy bookRepo;
   
   public void save(Book book) {
      bookRepo.save(book);
   }
   
   public void save(List<Book> books) {
      bookRepo.save(books);
   }

   public Book get(String id) {
      return bookRepo.get(id);
   }
   
   public List<Book> getAll() {
      return bookRepo.getAll();
   }
   
   public void delete(Book book) {
      bookRepo.delete(book);
   }
}
And last, but not least, a class to load Spring context and do some basic data access operations in regards to our books example:
package com.noushin.spring.monspr;

import java.util.ArrayList;
import java.util.UUID;

import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.noushin.spring.monspr.model.Book;
import com.noushin.spring.monspr.service.BookService;

/**
 * Main class to demonstrate accessing MongoDB with Spring Data and MongoTemplate.
 * 
 * @author nbashir
 *
 */
public class MongoDbMain {

   final static Logger logger = Logger.getLogger(MongoDbMain.class);

   public static void main(String[] args) {
      try {
         ApplicationContext ctx = new ClassPathXmlApplicationContext("application-context.xml");
         if (ctx != null) {
            logger.info(ctx.getApplicationName() + "MongoDbMain successfuly started. ");
            BookService service = ctx.getBean(BookService.class);
                       
            Book book;
            book = new Book(UUID.randomUUID().toString(), "Ragtime", "E.L. Doctrow");
            service.save(book);
            book = new Book(UUID.randomUUID().toString(), "The March", "E.L. Doctrow");
            service.save(book);
            book = new Book(UUID.randomUUID().toString(), "Andrew's Brain", "E.L. Doctrow");
            service.save(book);
            book = new Book(UUID.randomUUID().toString(), "Wild: From Lost to Found on the Pacific Crest Trail ",
                  "Cheryl Strayed");
            service.save(book);

            ArrayList<Book> books = (ArrayList<Book>) service.getAll();
            for (int i = 0; i < books.size(); i++)
               System.out.println("Book " + i + " : " + books.get(i).getId() + " - " + books.get(i).getName());
            
            for (int i = 0; i < books.size(); i++)
               service.delete(books.get(i));
      
            ArrayList<Book> deltedBooks =  (ArrayList<Book>) service.getAll();
            if (deltedBooks.size() > 0 ) {
               for (int i = 0; i < deltedBooks.size(); i++)
                  System.out.println("Book " + i + " : " + deltedBooks.get(i).getId() + " - " + deltedBooks.get(i).getName());
            }
            else
               System.out.println("All book are successfully removed.");

         }
      }
      catch (Exception ex) {
         logger.error("MongoDbMain encountered an error and ended.", ex);
      }
   }
}
Now that we have the basic Java code in place, we need to configure our app, so it knows how to access the datastore. As with any other Spring application, configuration details are in application-context.xml.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <!-- Activate annotation configured components -->
    <context:annotation-config />

    <!-- Scan components for annotations within the configured package -->
    <context:component-scan base-package="com.noushin.spring.monspr" />

    <!-- Mongo config -->
    <!-- Factory bean that creates the Mongo instance -->

    <bean id="mongo" class="org.springframework.data.mongodb.core.MongoFactoryBean">
        <property name="host" value="[your-mongodb-host]" />
    </bean>

    <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
        <constructor-arg name="mongo" ref="mongo" />
        <constructor-arg name="databaseName" value="nbdb" />
    </bean>
</beans>
In the above configuration, my app will be connecting to "nbdb" database, with MongoDB running on a server specified by "host" property of MongoFactoryBean.

To complete this example, here is my pom.xml where application dependecies are listed:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.noushin.spring</groupId>
  <artifactId>monspr</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>
  <name>monspr</name>
  <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <junit.version>4.11</junit.version>
        <log4j.version>1.2.17</log4j.version>
        <spring.version>3.2.4.RELEASE</spring.version>
        <spring.data.version>1.3.4.RELEASE</spring.data.version>
    </properties>

    <dependencies>
        <!-- Test -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
            <scope>test</scope>
        </dependency>
        
        <!-- Logging -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>${log4j.version}</version>
        </dependency>
            
        <!-- Spring Data -->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-mongodb</artifactId>
            <version>${spring.data.version}</version>
        </dependency>
        
        <!-- Spring Context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
    </dependencies>
</project>

No comments:

Post a Comment