Spring Data MongoDB with Spring MVC

Below is the steps to create a Spring MVC application with MongoDB
1. Create MongoDB Entity
2. Define MongoDB DataSource
3. Define MongoDBTemplate
4. Create MongoDB Repository interface
5. Implement MongoDB Repository interface
6. Define your MongoDB Controller
7. Test MongoDB DataSource
8. Test MongoDBTemplate
9. Test MongoDB Repository

Create MongoDB Entity

package com.example.model;

import java.math.BigInteger;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@Entity
@Table(name="CustomerActivity")
public class CustomerActivity implements java.io.Serializable {
	
	private static final long serialVersionUID = 1L;

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name="id", nullable=false, unique=true)
	private BigInteger id;
	
	@Column(name="customerId", nullable=false)
	private String customerId;
	
	@Column(name="activityDescription") 
	private String activityDescription;
	
	@Temporal(TemporalType.TIMESTAMP)
	@Column(name="activityTime")
	private Date activityTime;
	
	@Column(name="activityType")
	private String activityType; //ActivityType
	
	@Column(name="systemName")
	private String systemName;
	
	@Column(name="systemUrl")
	private String systemUrl;

	public CustomerActivity(String customerId, String activityDescription, Date activityTime, String activityType, String systemName, String systemUrl) {
		this.customerId = customerId;
		this.activityDescription = activityDescription;
		this.activityTime = activityTime;
		this.activityType = activityType;
		this.systemName = systemName;
		this.systemUrl = systemUrl;
	}

	public BigInteger getId() {
		return id;
	}

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

	public String getCustomerId() {
		return customerId;
	}

	public void setCustomerId(String customerId) {
		this.customerId = customerId;
	}

	public String getActivityDescription() {
		return activityDescription;
	}

	public void setActivityDescription(String activityDescription) {
		this.activityDescription = activityDescription;
	}

	public Date getActivityTime() {
		return activityTime;
	}

	public void setActivityTime(Date activityTime) {
		this.activityTime = activityTime;
	}

	public String getActivityType() {
		return activityType;
	}

	public void setActivityType(String activityType) {
		this.activityType = activityType;
	}

	public String getSystemName() {
		return systemName;
	}

	public void setSystemName(String systemName) {
		this.systemName = systemName;
	}

	public String getSystemUrl() {
		return systemUrl;
	}

	public void setSystemUrl(String systemUrl) {
		this.systemUrl = systemUrl;
	}
}

Define MongoDB DataSource

package com.example.config;

import javax.inject.Inject;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;

import com.mongodb.Mongo;

@PropertySource("classpath:services.properties")
@Configuration
@Profile("default")
public class MongoDataSourceConfiguration {
	
	    @Inject Environment environment;
	    
	    @Bean(name="local")
	    public MongoDbFactory mongoDbFactoryLocal() throws Exception {
	        String dbName = environment.getProperty("mongo.db");
	        String host = environment.getProperty("mongo.host");
	        Mongo mongo = new Mongo(host);
	        return new SimpleMongoDbFactory(mongo, dbName);
	    }
}

Define MongoDBTemplate

package com.example.mongo;

import javax.inject.Inject;
import javax.inject.Named;

import org.springframework.context.annotation.*;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;

import com.example.config.MongoDataSourceConfiguration;

/**
 * @author Thys Michels
 */
@Configuration
@Import( { MongoDataSourceConfiguration.class })
@EnableMongoRepositories
public class MongoRepositoryConfiguration {
	
    @Inject @Named("local") private MongoDbFactory mongoDbFactoryLocal;
	
    @Bean
    public MongoTemplate mongoTemplate() throws Exception {
        return new MongoTemplate(mongoDbFactoryLocal);
    }

    @Bean
    public GridFsTemplate gridFsTemplate(MongoDbFactory mongoDbFactory, MongoTemplate mongoTemplate) throws Exception {
        return new GridFsTemplate(mongoDbFactory, mongoTemplate.getConverter());
    }
}

Create MongoDB Repository interface

package com.example.service;

import java.math.BigInteger;
import java.util.Collection;
import java.util.Date;
import java.util.List;

import com.example.model.CustomerActivity;

public interface CustomerActivityRepository {
	void updateCustomerActivity(BigInteger id, String customerId, String activityDescription, String activityType, String systemName, String systemUrl);
    void updateCustomerActivities(List<CustomerActivity> customersToUpdate);
    CustomerActivity getCustomerActivityById(BigInteger customerId);
    Collection<CustomerActivity> getAllCustomerActivities();
    void createCustomerActivity(String customerId, String activityDescription, Date activityTime, String activityType, String systemName, String systemUrl);
    void deleteCustomerActivity(BigInteger customerId);
    void createCustomerActivity(CustomerActivity newCustomer);
    void bulkCreateCustomerActivity(List<CustomerActivity> customers);
    List<CustomerActivity> findCustomerActivityByQuery(String query);
    void deleteCustomerActivities(List<CustomerActivity> customerToDelete);
    List<CustomerActivity> getPaginatedCustomerActivities(Integer currentPage, Integer totalPerPage);
    int getTotalRecords();
	List<String> getPaginationSequence();
	List<CustomerActivity> findCustomerActivityByCustomerId(String customerid);
}

Implement MongoDB Repository interface

package com.example.service;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;

import javax.inject.Inject;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Import;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
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 org.springframework.transaction.annotation.Transactional;

import com.example.model.CustomerActivity;
import com.example.mongo.MongoRepositoryConfiguration;

@Repository
@Import( { MongoRepositoryConfiguration.class })
@Qualifier("mongoRepository")
public class CustomerActivityRepositoryImpl implements CustomerActivityRepository{	
	
	@Inject MongoTemplate mongoTemplate;
	
	Class<CustomerActivity> entityClass = CustomerActivity.class;
	
	Collection<CustomerActivity> customerActivity = new ArrayList<CustomerActivity>();
	
	@Override
	public void updateCustomerActivity(BigInteger id, String customerId, String activityDescription,  String activityType, String systemName, String systemUrl) {
		CustomerActivity updateCustomerActivity = this.getCustomerActivityById(id);
		updateCustomerActivity.setCustomerId(customerId);
		updateCustomerActivity.setActivityDescription(activityDescription);
		
		updateCustomerActivity.setActivityType(activityType);
		updateCustomerActivity.setSystemName(systemName);
		updateCustomerActivity.setSystemUrl(systemUrl);
		mongoTemplate.save(updateCustomerActivity);
	}

	@Override
	public void updateCustomerActivities(List<CustomerActivity> customerActivitiesToUpdate) {
		for (CustomerActivity customerActivity : customerActivitiesToUpdate){
			Update updateCustomerActivity = new Update();
			updateCustomerActivity.push("customerId", customerActivity.getCustomerId());
			updateCustomerActivity.push("activityDescription", customerActivity.getActivityDescription());
			updateCustomerActivity.push("activityTime", customerActivity.getActivityTime());
			updateCustomerActivity.push("activityType", customerActivity.getActivityType());
			updateCustomerActivity.push("systemName", customerActivity.getSystemName());
			updateCustomerActivity.push("systemUrl", customerActivity.getSystemUrl());
			mongoTemplate.updateFirst(new Query(Criteria.where("Id").is(customerActivity.getId())), updateCustomerActivity, CustomerActivity.class);
		}
	}

	@Override
	public CustomerActivity getCustomerActivityById(BigInteger id) {
		return mongoTemplate.findById(id, CustomerActivity.class);
	}

	@Override
	public Collection<CustomerActivity> getAllCustomerActivities() {
		try {
			 List<CustomerActivity> allCustomers = mongoTemplate.findAll(entityClass);
			 return allCustomers;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	@Override
	public void createCustomerActivity(String customerId, String activityDescription, Date activityTime, String activityType, String systemName, String systemUrl) {
		try {
			customerActivity.add(new CustomerActivity(customerId, activityDescription, activityTime, activityType, systemName, systemUrl));
			mongoTemplate.insert(customerActivity, entityClass);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public BigInteger findLastIdInCollection(){
		return mongoTemplate.findOne(new Query().with(new Sort(Direction.DESC,"id")), CustomerActivity.class).getId();
	}
	
	@Override
	public void deleteCustomerActivity(BigInteger customerId) {
		mongoTemplate.remove(this.getCustomerActivityById(customerId));
	}
	

	@Override
	public void createCustomerActivity(CustomerActivity newCustomer) {
		customerActivity.add(newCustomer);
		mongoTemplate.insert(customerActivity, entityClass);
	}


	@Override
	public void bulkCreateCustomerActivity(List<CustomerActivity> customerActivities) {
		for (CustomerActivity newcustomerActivity : customerActivities){
			customerActivity.add(new CustomerActivity(newcustomerActivity.getCustomerId(), newcustomerActivity.getActivityDescription(), newcustomerActivity.getActivityTime(), newcustomerActivity.getActivityType(), newcustomerActivity.getSystemName(), newcustomerActivity.getSystemUrl()));
		}
		mongoTemplate.insert(customerActivity, entityClass);
	}

	@Override
	public List<CustomerActivity> findCustomerActivityByQuery(String query) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	@Transactional
	public void deleteCustomerActivities(List<CustomerActivity> customerActivitiesToDelete) {
		for (CustomerActivity customerActivityToDelete : customerActivitiesToDelete){
			mongoTemplate.remove(new Query(Criteria.where("customerId").is(customerActivityToDelete.getCustomerId().toString())), CustomerActivity.class);
		}
	}

	@Override
	public List<CustomerActivity> getPaginatedCustomerActivities(Integer currentPage, Integer totalPerPage) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public int getTotalRecords() {
		return getAllCustomerActivities().size();
	}

	@Override
	public List<String> getPaginationSequence() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public List<CustomerActivity> findCustomerActivityByCustomerId(String customerId) {
		return mongoTemplate.find(new Query(Criteria.where("customerId").is(new Long(customerId).toString())), CustomerActivity.class);
	}
}

Define your MongoDB Controller

package com.example.controller;

import java.math.BigInteger;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import com.example.model.CustomerActivity;
import com.example.service.CustomerActivityRepositoryImpl;

@Controller
@RequestMapping("/activity")
public class MongoController {

	@Autowired
	@Qualifier("mongoRepository")
	CustomerActivityRepositoryImpl mongoCustomerService;
 	
	@RequestMapping("")
	public String returnMongoView(Map<String, Object> map){
		map.put("mongoCustomerList", mongoCustomerService.getAllCustomerActivities());
		return "mongo";
	}
	
	@RequestMapping(value="/insert")
	public String insertCustomersView(){
		return "insertmongo";
	}
	
	@RequestMapping(value="/insert", method=RequestMethod.POST)
	public String insertCustomers(@RequestParam("customerId") String customerId, 
			@RequestParam("activityDescription") String activityDescription,
			@RequestParam("activityTime") String activityTime,
			@RequestParam("activityType") String activityType, 
			@RequestParam("systemName") String systemName,
			@RequestParam("systemUrl") String systemUrl) {
		mongoCustomerService.createCustomerActivity(customerId, activityDescription, new Date(), activityType, systemName, systemUrl);
		return "mongo";
	}
	
	@RequestMapping(value="/delete/{id}", method=RequestMethod.POST)
	public String deleteCustomer(@PathVariable("id") String id, Map<String, Object> map){
		mongoCustomerService.deleteCustomerActivity(new BigInteger(id));
		return "mongo";
	}
	
	@RequestMapping(value="/update/{id}", method=RequestMethod.GET)
	public String viewUpdateCustomer(@PathVariable("id") String id, Map<String, Object> map){
		List<CustomerActivity> customer = Arrays.asList(mongoCustomerService.getCustomerActivityById(new BigInteger(id)));
		map.put("mongoList", customer);
		return "updatemongo";
	}
	
	@RequestMapping(value="/update/{id}", method=RequestMethod.POST)
	public String updateCustomer(@PathVariable("id") String id, 
			@RequestParam("customerId") String customerId, 
			@RequestParam("activityDescription") String activityDescription,
			@RequestParam("activityType") String activityType, 
			@RequestParam("systemName") String systemName,
			@RequestParam("systemUrl") String systemUrl) {
		mongoCustomerService.updateCustomerActivity(new BigInteger(id), customerId, activityDescription, activityType, systemName,systemUrl);
		return "mongo";
	}
}

Test MongoDB DataSource

package com.example.mongo;

import static org.junit.Assert.*;

import javax.inject.Inject;
import javax.inject.Named;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;

import com.example.config.MongoDataSourceConfiguration;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader=AnnotationConfigContextLoader.class, classes={MongoDataSourceConfiguration.class})
public class LocalMongoConfigurationTest {

	@Inject MongoDbFactory mongoDbFactory;
	
	@Test
	public void testMongoDbFactoryConnection() {
		assertTrue(mongoDbFactory.getDb().getMongo().getConnector().isOpen());
	}
}

Test MongoDB Template

package com.example.mongo;

import static org.junit.Assert.*;

import javax.inject.Inject;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader=AnnotationConfigContextLoader.class, classes={MongoRepositoryConfiguration.class})
public class MongoTemplateTest {

	@Inject MongoTemplate mongTemplate;
	
	@Test
	public void testMongoTemplate() {
		assertEquals(mongTemplate.getCollection("lc-activity-service").getName(), "lc-activity-service");
	}
}

Test MongoDB Repository

package com.example.service;

import static org.junit.Assert.*;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import javax.inject.Inject;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;

import com.example.model.CustomerActivity;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader=AnnotationConfigContextLoader.class, classes={CustomerActivityRepositoryImpl.class})
public class CustomerActivityServiceTest {

	@Inject CustomerActivityRepository customerActivityService;
	
	@Test
	public void testCreateCustomerActivity() {
		Calendar cal = Calendar.getInstance();
		customerActivityService.createCustomerActivity("123", "Email Sent For Customer", cal.getTime(), "Email Received", "Salesforce", "http://salesforce.com/123213");
		assertNotNull(customerActivityService.findCustomerActivityByCustomerId("123"));
	}
	
	@Test
	public void testUpdateCustomerActivity(){
		List<CustomerActivity> updatecas = new ArrayList<CustomerActivity>();
		List<CustomerActivity> cas = customerActivityService.findCustomerActivityByCustomerId("123");
		for (CustomerActivity ca :cas){
			ca.setActivityDescription("SMS Sent from Customer");
			updatecas.add(ca);
		}
		customerActivityService.updateCustomerActivities(updatecas);
	}
	
	@Test
	public void deleteAllCustomerActivity(){
		customerActivityService.deleteCustomerActivity(new BigInteger("123"));
	}
	
	@Test
	public void testGetAllCustomerActivities(){
		for (CustomerActivity customerActivities : customerActivityService.getAllCustomerActivities()){
			System.out.println(customerActivities.getId() + " | " + customerActivities.getCustomerId()
			+ " | " +  customerActivities.getActivityDescription() + " | " +  customerActivities.getActivityTime()
			+ " | " + customerActivities.getActivityType() + " | " + customerActivities.getSystemName() + " | " +
			customerActivities.getSystemUrl());
		}
		assertTrue(customerActivityService.getAllCustomerActivities().size()>=0);
	}
}

Setup Postgres, Mongodb and Redis on Heroku

Below is the instruction to setup Postgres, Mongodb and Redis on Heroku:

Setup Postgres

heroku addons:add heroku-postgresql:dev

package com.example.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import javax.sql.DataSource;
import java.net.URI;

/**
 * @author Thys Michels
 */
@Configuration
@Profile("default")
public class LocalDataSourceConfiguration implements DataSourceConfiguration {
	
	@Bean
        public DataSource dataSource() throws Exception {
    	   final URI dbUrl = new URI(System.getenv("DATABASE_URL"));
           final DriverManagerDataSource dataSource = new DriverManagerDataSource();
           dataSource.setDriverClassName("org.postgresql.Driver");
           dataSource.setUrl("jdbc:postgresql://" + dbUrl.getHost() + dbUrl.getPath());
           dataSource.setUsername(dbUrl.getUserInfo().split(":")[0]);
           dataSource.setPassword(dbUrl.getUserInfo().split(":")[1]);
        return dataSource;
    }
}

Setup MongoDB

heroku addons:add mongohq:sandbox

package com.example.mongo;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.core.env.Environment;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;

import com.mongodb.Mongo;
import com.mongodb.MongoURI;

@Configuration
@Profile("default")
public class LocalMongoConfiguration {
	
	    @Bean
	    public MongoDbFactory mongoDbFactory1(Environment environment) throws Exception {
	    	MongoURI mongoURI = new MongoURI(System.getenv("MONGOHQ_URL"));
	        Mongo mongo = new Mongo(mongoURI);
	        return new SimpleMongoDbFactory(mongo, mongoURI.getDatabase());
	    }
}

Setup Redis

heroku addons:add rediscloud:20

package com.example.redis;

import java.net.URI;
import java.net.URISyntaxException;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;

import redis.clients.jedis.Protocol;

@Configuration
@Profile("default")
public class LocalRedisConfiguration {
	
    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
    	
		try {
			URI redisUri = new URI(System.getenv("REDISCLOUD_URL"));
			JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory();
			redisConnectionFactory.setHostName(redisUri.getHost());
			redisConnectionFactory.setPort(redisUri.getPort());
			redisConnectionFactory.setTimeout(Protocol.DEFAULT_TIMEOUT);
			redisConnectionFactory.setPassword(redisUri.getUserInfo().split(":",2)[1]);
			
                        return redisConnectionFactory;
		} catch (URISyntaxException e) {
			e.printStackTrace();
			return null;
		}
    }
}