MongoDB Java Servlet Web Application Example Tutorial

Welcome to MongoDB Web Application example. Earlier in MongoDB Java Example we learned how to use MongoDB java driver in standalone application. Today we are moving forward to integrate MongoDB in Java Servlet web application.

MongoDB Web Application

We will create a web application where we will be manage Person data and store it in the MongoDB database. We will be able to create, read, update and delete Person records from the user interface and corresponding operations will be performed against MongoDB database.

First step is to create a dynamic web application in Eclipse and then convert it to Maven project, so that our maven based web application skeleton code is ready. Below image shows the final project structure and different components of it.

MongoDB Web Application

Let’s look into each of the components one by one.

MongoDB Web Application Maven Dependencies

Our final pom.xml file looks like below.


<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>MongoDBWebapp</groupId>
	<artifactId>MongoDBWebapp</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>
	<build>
		<plugins>
			<plugin>
				<artifactId>maven-war-plugin</artifactId>
				<version>2.3</version>
				<configuration>
					<warSourceDirectory>WebContent</warSourceDirectory>
					<failOnMissingWebXml>false</failOnMissingWebXml>
				</configuration>
			</plugin>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.1</version>
				<configuration>
					<source>1.7</source>
					<target>1.7</target>
				</configuration>
			</plugin>
		</plugins>
		<finalName>${project.artifactId}</finalName>
	</build>
	<dependencies>
		<!-- MongoDB Java Driver -->
		<dependency>
			<groupId>org.mongodb</groupId>
			<artifactId>mongo-java-driver</artifactId>
			<version>2.12.3</version>
		</dependency>
		<!-- JSTL libraries for JSP pages -->
		<dependency>
			<groupId>jstl</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>
		<dependency>
			<groupId>taglibs</groupId>
			<artifactId>standard</artifactId>
			<version>1.1.2</version>
		</dependency>
		<!-- Servlet-API jar, only for compile time -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>3.1.0</version>
			<scope>provided</scope>
		</dependency>
	</dependencies>
</project>

Notice that we have MongoDB java driver dependency to connect to MongoDB server, JSTL and standard jars are required for using JSTL tags in the JSP pages.

Deployment Descriptor

Here is our deployment descriptor web.xml file details.


<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xmlns="https://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
	id="WebApp_ID" version="3.0">
	<display-name>MongoDBWebapp</display-name>
	<context-param>
		<param-name>MONGODB_HOST</param-name>
		<param-value>localhost</param-value>
	</context-param>
	<context-param>
		<param-name>MONGODB_PORT</param-name>
		<param-value>27017</param-value>
	</context-param>
	<welcome-file-list>
		<welcome-file>persons.jsp</welcome-file>
	</welcome-file-list>
</web-app>
  • MongoDB server host and port details are configured as context parameters, rather than hardcoding them somewhere in the code.
  • We have single JSP page for view purposes, I have added it in the welcome file list to avoid empty page for web application home.

Model Bean or POJO Class

We have Person.java class as Model class, this bean will be saved as Mongo DBObject into database.

Person.java


package com.journaldev.mongodb.model;
public class Person {
	// id will be used for primary key in MongoDB
	// We could use ObjectId, but I am keeping it
	// independent of MongoDB API classes
	private String id;
	private String name;
	private String country;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getCountry() {
		return country;
	}
	public void setCountry(String country) {
		this.country = country;
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
}

Notice that it has id attribute, this will be generated by MongoDB and it won’t be editable by user. This will serve as the primary key for MongoDB object. Notice that MongoDB record primary key is stored with “_id” key and when we retrieve it, it’s returned as ObjectId instance. For loose coupling, I am using String but we can also use ObjectId type.

Since we are not using ObjectId for primary key, we need to convert it into the ObjectId and vice versa at several places.

Java Bean to MongoDB DBObject Converter

We have a helper class for converting Person object to MongoDB DBObject and vice versa.

PersonConverter.java


package com.journaldev.mongodb.converter;
import org.bson.types.ObjectId;
import com.journaldev.mongodb.model.Person;
import com.mongodb.BasicDBObjectBuilder;
import com.mongodb.DBObject;
public class PersonConverter {
	// convert Person Object to MongoDB DBObject
	// take special note of converting id String to ObjectId
	public static DBObject toDBObject(Person p) {
		BasicDBObjectBuilder builder = BasicDBObjectBuilder.start()
				.append("name", p.getName()).append("country", p.getCountry());
		if (p.getId() != null)
			builder = builder.append("_id", new ObjectId(p.getId()));
		return builder.get();
	}
	// convert DBObject Object to Person
	// take special note of converting ObjectId to String
	public static Person toPerson(DBObject doc) {
		Person p = new Person();
		p.setName((String) doc.get("name"));
		p.setCountry((String) doc.get("country"));
		ObjectId id = (ObjectId) doc.get("_id");
		p.setId(id.toString());
		return p;
	}
}

Conversion is very simple, just take a note of converting the id attribute to ObjectId and vice versa.

MongoDB DAO Implementation

We could have created a Person DAO interface and provided MongoDB implementation, but for simplicity we have simple MongoDB DAO implementation to expose different operations we can perform for Person object in MongoDB database.

MongoDBPersonDAO.java


package com.journaldev.mongodb.dao;
import java.util.ArrayList;
import java.util.List;
import org.bson.types.ObjectId;
import com.journaldev.mongodb.converter.PersonConverter;
import com.journaldev.mongodb.model.Person;
import com.mongodb.BasicDBObjectBuilder;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.MongoClient;
//DAO class for different MongoDB CRUD operations
//take special note of "id" String to ObjectId conversion and vice versa
//also take note of "_id" key for primary key
public class MongoDBPersonDAO {
	private DBCollection col;
	public MongoDBPersonDAO(MongoClient mongo) {
		this.col = mongo.getDB("journaldev").getCollection("Persons");
	}
	public Person createPerson(Person p) {
		DBObject doc = PersonConverter.toDBObject(p);
		this.col.insert(doc);
		ObjectId id = (ObjectId) doc.get("_id");
		p.setId(id.toString());
		return p;
	}
	public void updatePerson(Person p) {
		DBObject query = BasicDBObjectBuilder.start()
				.append("_id", new ObjectId(p.getId())).get();
		this.col.update(query, PersonConverter.toDBObject(p));
	}
	public List<Person> readAllPerson() {
		List<Person> data = new ArrayList<Person>();
		DBCursor cursor = col.find();
		while (cursor.hasNext()) {
			DBObject doc = cursor.next();
			Person p = PersonConverter.toPerson(doc);
			data.add(p);
		}
		return data;
	}
	public void deletePerson(Person p) {
		DBObject query = BasicDBObjectBuilder.start()
				.append("_id", new ObjectId(p.getId())).get();
		this.col.remove(query);
	}
	public Person readPerson(Person p) {
		DBObject query = BasicDBObjectBuilder.start()
				.append("_id", new ObjectId(p.getId())).get();
		DBObject data = this.col.findOne(query);
		return PersonConverter.toPerson(data);
	}
}

MongoClient instance is required for any MongoDB operations, so I have created a constructor where we need to pass it.

Our MongoDB operations setup classes are ready, we can move now to integrate it with the web application.

MongoDB ServletContextListener

MongoClient is thread safe and internally manages it’s own connection pool. Best practice is to create an instance of it and reuse it. We should close it when the application is shut down, that makes ServletContextListener implementation best choice to initialize and destroy it.

MongoDBContextListener.java


package com.journaldev.mongodb.listener;
import java.net.UnknownHostException;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import com.mongodb.MongoClient;
@WebListener
public class MongoDBContextListener implements ServletContextListener {
	@Override
	public void contextDestroyed(ServletContextEvent sce) {
		MongoClient mongo = (MongoClient) sce.getServletContext()
							.getAttribute("MONGO_CLIENT");
		mongo.close();
		System.out.println("MongoClient closed successfully");
	}
	@Override
	public void contextInitialized(ServletContextEvent sce) {
		try {
			ServletContext ctx = sce.getServletContext();
			MongoClient mongo = new MongoClient(
					ctx.getInitParameter("MONGODB_HOST"),
					Integer.parseInt(ctx.getInitParameter("MONGODB_PORT")));
			System.out.println("MongoClient initialized successfully");
			sce.getServletContext().setAttribute("MONGO_CLIENT", mongo);
		} catch (UnknownHostException e) {
			throw new RuntimeException("MongoClient init failed");
		}
	}
}

Notice that I am using @WebListener annotation to configure it as listener class, your servlet container should support it or else you will have to use XML based configurations. I am using Apache Tomcat 7 that supports Servlet API annotations, so make sure you use compatible servlet container or change the code to use XML based configurations.

We are creating instance of MongoClient and adding it as context attribute, so that it will be accessible everywhere in the application.

Servlet Classes

We have three servlet classes for CRUD operations, they have some validation logic to make sure input data is valid. If everything is fine with request parameters, then it’s using MongoDB DAO implementation to perform database operations and forward the request to the JSP page after setting correct attributes.

AddPersonServlet.java


package com.journaldev.mongodb.servlets;
import java.io.IOException;
import java.util.List;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.journaldev.mongodb.dao.MongoDBPersonDAO;
import com.journaldev.mongodb.model.Person;
import com.mongodb.MongoClient;
@WebServlet("/addPerson")
public class AddPersonServlet extends HttpServlet {
	private static final long serialVersionUID = -7060758261496829905L;
	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		String name = request.getParameter("name");
		String country = request.getParameter("country");
		if ((name == null || name.equals(""))
				|| (country == null || country.equals(""))) {
			request.setAttribute("error", "Mandatory Parameters Missing");
			RequestDispatcher rd = getServletContext().getRequestDispatcher(
					"/persons.jsp");
			rd.forward(request, response);
		} else {
			Person p = new Person();
			p.setCountry(country);
			p.setName(name);
			MongoClient mongo = (MongoClient) request.getServletContext()
					.getAttribute("MONGO_CLIENT");
			MongoDBPersonDAO personDAO = new MongoDBPersonDAO(mongo);
			personDAO.createPerson(p);
			System.out.println("Person Added Successfully with id="+p.getId());
			request.setAttribute("success", "Person Added Successfully");
			List<Person> persons = personDAO.readAllPerson();
			request.setAttribute("persons", persons);
			RequestDispatcher rd = getServletContext().getRequestDispatcher(
					"/persons.jsp");
			rd.forward(request, response);
		}
	}
}

EditPersonServlet.java


package com.journaldev.mongodb.servlets;
import java.io.IOException;
import java.util.List;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.journaldev.mongodb.dao.MongoDBPersonDAO;
import com.journaldev.mongodb.model.Person;
import com.mongodb.MongoClient;
@WebServlet("/editPerson")
public class EditPersonServlet extends HttpServlet {
	private static final long serialVersionUID = -6554920927964049383L;
	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		String id = request.getParameter("id");
		if (id == null || "".equals(id)) {
			throw new ServletException("id missing for edit operation");
		}
		System.out.println("Person edit requested with id=" + id);
		MongoClient mongo = (MongoClient) request.getServletContext()
				.getAttribute("MONGO_CLIENT");
		MongoDBPersonDAO personDAO = new MongoDBPersonDAO(mongo);
		Person p = new Person();
		p.setId(id);
		p = personDAO.readPerson(p);
		request.setAttribute("person", p);
		List<Person> persons = personDAO.readAllPerson();
		request.setAttribute("persons", persons);
		RequestDispatcher rd = getServletContext().getRequestDispatcher(
				"/persons.jsp");
		rd.forward(request, response);
	}
	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		String id = request.getParameter("id"); // keep it non-editable in UI
		if (id == null || "".equals(id)) {
			throw new ServletException("id missing for edit operation");
		}
		String name = request.getParameter("name");
		String country = request.getParameter("country");
		if ((name == null || name.equals(""))
				|| (country == null || country.equals(""))) {
			request.setAttribute("error", "Name and Country Can't be empty");
			MongoClient mongo = (MongoClient) request.getServletContext()
					.getAttribute("MONGO_CLIENT");
			MongoDBPersonDAO personDAO = new MongoDBPersonDAO(mongo);
			Person p = new Person();
			p.setId(id);
			p.setName(name);
			p.setCountry(country);
			request.setAttribute("person", p);
			List<Person> persons = personDAO.readAllPerson();
			request.setAttribute("persons", persons);
			RequestDispatcher rd = getServletContext().getRequestDispatcher(
					"/persons.jsp");
			rd.forward(request, response);
		} else {
			MongoClient mongo = (MongoClient) request.getServletContext()
					.getAttribute("MONGO_CLIENT");
			MongoDBPersonDAO personDAO = new MongoDBPersonDAO(mongo);
			Person p = new Person();
			p.setId(id);
			p.setName(name);
			p.setCountry(country);
			personDAO.updatePerson(p);
			System.out.println("Person edited successfully with id=" + id);
			request.setAttribute("success", "Person edited successfully");
			List<Person> persons = personDAO.readAllPerson();
			request.setAttribute("persons", persons);
			RequestDispatcher rd = getServletContext().getRequestDispatcher(
					"/persons.jsp");
			rd.forward(request, response);
		}
	}
}

DeletePersonServlet.java


package com.journaldev.mongodb.servlets;
import java.io.IOException;
import java.util.List;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.journaldev.mongodb.dao.MongoDBPersonDAO;
import com.journaldev.mongodb.model.Person;
import com.mongodb.MongoClient;
@WebServlet("/deletePerson")
public class DeletePersonServlet extends HttpServlet {
	private static final long serialVersionUID = 6798036766148281767L;
	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		String id = request.getParameter("id");
		if (id == null || "".equals(id)) {
			throw new ServletException("id missing for delete operation");
		}
		MongoClient mongo = (MongoClient) request.getServletContext()
				.getAttribute("MONGO_CLIENT");
		MongoDBPersonDAO personDAO = new MongoDBPersonDAO(mongo);
		Person p = new Person();
		p.setId(id);
		personDAO.deletePerson(p);
		System.out.println("Person deleted successfully with id=" + id);
		request.setAttribute("success", "Person deleted successfully");
		List<Person> persons = personDAO.readAllPerson();
		request.setAttribute("persons", persons);
		RequestDispatcher rd = getServletContext().getRequestDispatcher(
				"/persons.jsp");
		rd.forward(request, response);
	}
}

Notice the use of @WebServlet annotation for configuring the URI pattern for each of the servlets. It will be used in JSP pages to send the request to correct servlet.

JSP View Page

Final piece of the project is the view page, i am using JSTL tags for rendering the response html page.

persons.jsp


<%@ taglib uri="https://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Persons Manage Page</title>
<style>
table,th,td {
	border: 1px solid black;
}
</style>
</head>
<body>
	<%-- Person Add/Edit logic --%>
	<c:if test="${requestScope.error ne null}">
		<strong style="color: red;"><c:out
				value="${requestScope.error}"></c:out></strong>
	</c:if>
	<c:if test="${requestScope.success ne null}">
		<strong style="color: green;"><c:out
				value="${requestScope.success}"></c:out></strong>
	</c:if>
	<c:url value="/addPerson" var="addURL"></c:url>
	<c:url value="/editPerson" var="editURL"></c:url>
	<%-- Edit Request --%>
	<c:if test="${requestScope.person ne null}">
		<form action="https://www.journaldev.com/4011/<c:out value="${editURL}"></c:out>' method="post">
			ID: <input type="text" value="${requestScope.person.id}"
				readonly="readonly" name="id"><br> Name: <input
				type="text" value="${requestScope.person.name}" name="name"><br>
			Country: <input type="text" value="${requestScope.person.country}"
				name="country"><br> <input type="submit"
				value="Edit Person">
		</form>
	</c:if>
	<%-- Add Request --%>
	<c:if test="${requestScope.person eq null}">
		<form action="https://www.journaldev.com/4011/<c:out value="${addURL}"></c:out>' method="post">
			Name: <input type="text" name="name"><br> Country: <input
				type="text" name="country"><br> <input type="submit"
				value="Add Person">
		</form>
	</c:if>
	<%-- Persons List Logic --%>
	<c:if test="${not empty requestScope.persons}">
		<table>
			<tbody>
				<tr>
					<th>ID</th>
					<th>Name</th>
					<th>Country</th>
					<th>Edit</th>
					<th>Delete</th>
				</tr>
				<c:forEach items="${requestScope.persons}" var="person">
					<c:url value="/editPerson" var="editURL">
						<c:param name="id" value="${person.id}"></c:param>
					</c:url>
					<c:url value="/deletePerson" var="deleteURL">
						<c:param name="id" value="${person.id}"></c:param>
					</c:url>
					<tr>
						<td><c:out value="${person.id}"></c:out></td>
						<td><c:out value="${person.name}"></c:out></td>
						<td><c:out value="${person.country}"></c:out></td>
						<td><a
							href="https://www.journaldev.com/4011/<c:out value="${editURL}" escapeXml="true"></c:out>">Edit</a></td>
						<td><a
							href="https://www.journaldev.com/4011/<c:out value="${deleteURL}" escapeXml="true"></c:out>">Delete</a></td>
					</tr>
				</c:forEach>
			</tbody>
		</table>
	</c:if>
</body>
</html>

Recommended Read: JSTL Tutorial, JSP EL and JSP implicit objects.

MongoDB Java Web Application Test

Our application is ready for a test drive, below screenshots show some of the response pages of different CRUD operations.

Home Page

MongoDB-Web-Application-Home

Create Person Page

MongoDB-Web-Application-Create

Read Person Page

MongoDB-Web-Application-Create

Update Person Page

MongoDB-Web-Application-Create

Delete Person Page

MongoDB-Web-Application-Create

You will also find below logs in the server log file.


MongoClient initialized successfully
Person Added Successfully with id=53ea76e70364b0028f507802
Person Added Successfully with id=53ea76fd0364b0028f507803
Person edit requested with id=53ea76e70364b0028f507802
Person edited successfully with id=53ea76e70364b0028f507802
Person deleted successfully with id=53ea76fd0364b0028f507803
MongoClient closed successfully

Summary

This post was intended to provide a complete example of using MongoDB server as data storage, you learned how to use MongoDB java driver for CRUD operations and create a web application. Download the final project from below link and explore more.

By admin

Leave a Reply

%d bloggers like this: