Spring Mongo [Test Drive]

Okay, lets play a little bit with Spring+Mongo. In future we will be replacing our MySQL backend by Mongo DB. Spring has APIs to interact with Mongo and lets give a try here.

We will create a simple project names MongoSpring, where we will try to implement the same functionalities as in the previous project. Instead of a Web project, this project will be a java application only (jar). So, lets create a simple maven project using eclipse. The project structure is shown below,
MongoSpring_Project_Structure

Step 1. Installing MongoDB

First go to the MongoDB download page and according to your operational system, download the correct version of it. Installation process is simple for Windows. Just click the .msi file and click next and next and you are done. Just to verify, open a command prompt and type   mongo –version. If you can see something like MongoDB shell version: 3.0.6 your installation is successful.

Now, in case of Linux (I use Linux Mint), I downloaded the proper MongoDB for linux and extracted it and had to modify the PATH variable. it´s simple. Just do the following things.

  1. Open a terminal window and navigate to the etc directory.
  2. Type the following command, ls -a bash.*
  3. You should see something like bash.bashrc and something I do not remember right now.
  4. You have to modify this bash.bashrc to add the PATH to your MongoDB.
  5. Type the following command, sudo gedit bash.bashrc.
  6. At the end of the file, add the following line export PATH=$PATH:/home/mongodb/bin. 
  7. Thats it. Close all terminals and now open a terminal and type the command mongo –version. If you can see something like MongoDB shell version: 3.0.6 your installation is successful. 

Step 2. Add dependencies for Spring+Mongo

Here goes the complete pom.xml

<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.anupam</groupId>
	<artifactId>MongoSpring</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>4.2.2.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>4.2.2.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>4.2.2.RELEASE</version>
		</dependency>
		
		<!-- Spring + Mongo data -->
		<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-mongodb</artifactId>
			<version>1.8.0.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-core</artifactId>
			<version>4.3.7.Final</version>
		</dependency>
	</dependencies>
	<build>
		<finalName>MongoSpring</finalName>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

Step 3. Configure Mongo in Spring

I have configured Spring programatically in a java class. But of course no harm if would like to configure in pure xml file. So here goes my configuration.

com.anupam.config.SpringConfig

package com.anupam.config;

import java.net.UnknownHostException;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;

import com.mongodb.MongoClient;

@Configuration
public class SpringConfig
{

    @Bean
    public MongoDbFactory dbFactory() throws UnknownHostException
    {
	MongoClient mc = new MongoClient("localhost", 9999);
	return new SimpleMongoDbFactory(mc, "mydb");
    }

    @Bean
    public MongoTemplate mongoTemplate() throws UnknownHostException
    {
	MongoTemplate template = new MongoTemplate(dbFactory());
	return template;
    }
}

In this code, we are just configuring the mongo database factory and a mongo template to use later.

Step 4. Create VOs

Let’s create some VOs

com.anupam.vo.TbPostVO

package com.anupam.vo;

import java.io.Serializable;
import java.util.Date;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.DBRef;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;

@Document(collection="posts")
public class TbPostVO implements Serializable
{

    private static final long serialVersionUID = 1L;
    @Id
    private Integer postID;

    @Field
    private String scrap;

    @Field
    private Date date;

    @DBRef
    private TbUserVO userVO;

    public Integer getPostID()
    {
	return postID;
    }

    public void setPostID(Integer postID)
    {
	this.postID = postID;
    }

    public String getScrap()
    {
	return scrap;
    }

    public void setScrap(String scrap)
    {
	this.scrap = scrap;
    }

    public Date getDate()
    {
	return date;
    }

    public void setDate(Date date)
    {
	this.date = date;
    }

    public TbUserVO getUserVO()
    {
	return userVO;
    }

    public void setUserVO(TbUserVO userVO)
    {
	this.userVO = userVO;
    }

}

com.anupam.vo.TbUserVO

package com.anupam.vo;

import java.io.Serializable;

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

@Document(collection="users")
public class TbUserVO implements Serializable
{

    private static final long serialVersionUID = 1L;

    @Id
    private Integer userID;
    @Field
    private String firstName;
    @Field
    private String lastName;
    @Field
    private String login;
    @Field
    private String password;
    @Field
    private String email;

    public Integer getUserID()
    {
	return userID;
    }

    public void setUserID(Integer userID)
    {
	this.userID = userID;
    }

    public String getFirstName()
    {
	return firstName;
    }

    public void setFirstName(String firstName)
    {
	this.firstName = firstName;
    }

    public String getLastName()
    {
	return lastName;
    }

    public void setLastName(String lastName)
    {
	this.lastName = lastName;
    }

    public String getLogin()
    {
	return login;
    }

    public void setLogin(String login)
    {
	this.login = login;
    }

    public String getPassword()
    {
	return password;
    }

    public void setPassword(String password)
    {
	this.password = password;
    }

    public String getEmail()
    {
	return email;
    }

    public void setEmail(String email)
    {
	this.email = email;
    }

}

com.anupam.vo.Counter : The purpose of this VO is to generate the sequential IDs. I will explain about this a little bit later.It is necessary to create a counters collection the MongoDB with the command db.createCollection(“counters”).

package com.anupam.vo;

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

@Document(collection = "counters")
public class Counter
{
    @Id
    private String id;

    @Field
    private Long seq;

    public String getId()
    {
	return id;
    }

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

    public Long getSeq()
    {
	return seq;
    }

    public void setSeq(Long seq)
    {
	this.seq = seq;
    }

}

Step 5. Create DAOs

com.anupam.dao.PostDAO

package com.anupam.dao;



import java.util.List;

import com.anupam.vo.TbPostVO;

public interface PostDAO
{
   
    public Integer savePost(TbPostVO postVO)throws Exception;
   
    public List<TbPostVO> getAllPosts() throws Exception;
    
}

com.anupam.dao.PostDAOImpl

package com.anupam.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.anupam.vo.TbPostVO;

@Repository
public class PostDAOImpl implements PostDAO
{

    @Autowired
    private MongoTemplate template;

    @Override
    public Integer savePost(TbPostVO postVO) throws Exception
    {
	template.save(postVO);
	return postVO.getPostID();
    }

    @Override
    public List<TbPostVO> getAllPosts() throws Exception
    {
	List<TbPostVO> list = template.findAll(TbPostVO.class);
	return list;
    }

}

com.anupam.dao.UserDAO

package com.anupam.dao;

import com.anupam.vo.TbUserVO;

public interface UserDAO
{
    public TbUserVO getUserByID(Integer userID) throws Exception;
    public Integer saveUser(TbUserVO userVO) throws Exception;
}

com.anupam.dao.UserDAOImpl

package com.anupam.dao;

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.anupam.vo.TbUserVO;

@Repository
public class UserDAOImpl implements UserDAO
{

    @Autowired
    private MongoTemplate template;

    @Override
    public TbUserVO getUserByID(Integer userID) throws Exception
    {
	Query query = new Query(Criteria.where("_id").is(userID));
	TbUserVO userVO = template.findOne(query, TbUserVO.class);
	return userVO;
    }

    @Override
    public Integer saveUser(TbUserVO userVO) throws Exception
    {
	template.save(userVO);
	System.out.println("User saved...");
	return userVO.getUserID();
    }

}

com.anupam.dao.CommonDAO

package com.anupam.dao;

public interface CommonDAO
{

    public Long getNextID(String key)throws Exception;
}

com.anupam.dao.CommonDAOImpl: Here in this class, the method getNextID(String) just calculates the next ID that we will be using while saving our entities.

package com.anupam.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.FindAndModifyOptions;
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.data.mongodb.core.query.Update;
import org.springframework.stereotype.Repository;

import com.anupam.vo.Counter;

@Repository
public class CommonDAOImpl implements CommonDAO
{

    @Autowired
    private MongoTemplate template;

    @Override
    public Long getNextID(String key) throws Exception
    {
	Query query = new Query(Criteria.where("_id").is(key));
	Update update = new Update();
	update.inc("seq", 1);
	FindAndModifyOptions options = new FindAndModifyOptions();
	options.returnNew(true);

	Counter counter = template.findAndModify(query, update, Counter.class);

	return counter.getSeq();
    }

}

Step 6. Creating Services

com.anupam.service.PostSRV

package com.anupam.service;

import java.util.List;

import com.anupam.vo.TbPostVO;

public interface PostSRV
{

    public void savePost(String scrap) throws Exception;
    public List<TbPostVO> getAllPosts() throws Exception;
}

com.anupam.service.PostSRVImpl

In the savePost() method, we are invoking the getNextID() method of the CommonDAO and we are passing a parameter named posts. The method getNextID() will look for an object (CounterVO) with _id=posts when when found it will just increment the seq value and return the object. Note that it is necessary to create an initial object of CounterVO in the database.

CounterVO={
_id:'posts',
seq:0
}

And the class goes as below,

package com.anupam.service;

import java.util.Date;
import java.util.List;

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

import com.anupam.dao.CommonDAO;
import com.anupam.dao.PostDAO;
import com.anupam.dao.UserDAO;
import com.anupam.vo.TbPostVO;

@Service
public class PostSRVImpl implements PostSRV
{
    @Autowired
    private CommonDAO cd;

    @Autowired
    private UserDAO userDAO;

    @Autowired
    private PostDAO postDAO;

    @Override
    public void savePost(String scrap) throws Exception
    {
	TbPostVO postVO = new TbPostVO();
	postVO.setPostID(cd.getNextID("posts").intValue());
	postVO.setDate(new Date());
	postVO.setScrap(scrap);
	postVO.setUserVO(userDAO.getUserByID(1));
	postDAO.savePost(postVO);

    }

    @Override
    public List<TbPostVO> getAllPosts() throws Exception
    {
	return postDAO.getAllPosts();
    }

}

com.anupam.service.UserSRV

package com.anupam.service;

public interface UserSRV
{

    void saveUser(String firstName, String lastName, String login,
	    String password, String email) throws Exception;

}

com.anupam.service.UserSRVImpl

In the saveUser() method, we are invoking the getNextID() method of the CommonDAO and we are passing a parameter named users. The method getNextID() will look for an object (CounterVO) with _id=users and when found it will just increment the seq value and return the object. Note that it is necessary to create an initial object of CounterVO in the database.

CounterVO={
_id:'users',
seq:0
}

And the class goes as below,

package com.anupam.service;

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

import com.anupam.dao.CommonDAO;
import com.anupam.dao.UserDAO;
import com.anupam.vo.TbUserVO;

@Service
public class UserSRVImpl implements UserSRV
{
    @Autowired
    private CommonDAO cd;
    @Autowired
    private UserDAO userDAO;

    @Override
    public void saveUser(String firstName, String lastName, String login,
	    String password, String email) throws Exception
    {
	TbUserVO userVO = new TbUserVO();
	userVO.setUserID(cd.getNextID("users").intValue());
	userVO.setFirstName(firstName);
	userVO.setLastName(lastName);
	userVO.setLogin(login);
	userVO.setPassword(password);
	userVO.setEmail(email);
	userDAO.saveUser(userVO);
    }
}

And now finally the runner class. runner.Runner

package runner;



import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.anupam.config.SpringConfig;
import com.anupam.service.PostSRV;
import com.anupam.service.UserSRV;

public class Runner
{

    public static void main(String[] a) throws Exception
    {
	// Create context.
	AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
	ctx.scan("com.anupam.*");

	// Save User.
	UserSRV us=ctx.getBean(UserSRV.class);
	us.saveUser("Anupam", "Gogoi", "agogoi", "password", "anupam.gogoi@email.com");
	
	// Save Post.
	PostSRV ps = ctx.getBean(PostSRV.class);
	ps.savePost("Hello world !!!!");
	
	// Close context.
	ctx.close();
    }

   
}

And you are done. When you run the code you should see the user data saved in MongoDB.Note that in the TbPostVO, there is an entity relationship with TbUserVO marked with the @DbRef annotation. So, when you save TbPostVO, it saves the TbUserVO info also along with it. Check the savePost(String scrap) method in PostSRVImpl.java.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s