Create the following folder structure:

pom.xml: (if using Gradle, replace pom.xml with build.gradle)
<?xml version="1.0" encoding="UTF-8"?> <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>net.maxjava</groupId> <artifactId>SpringRESTAPIMongoClient</artifactId> <version>1.0</version> <packaging>war</packaging> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>6.1.6</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.15.4</version> </dependency> <dependency> <groupId>org.mongodb</groupId> <artifactId>mongo-java-driver</artifactId> <version>3.12.14</version> </dependency> <dependency> <groupId>jakarta.annotation</groupId> <artifactId>jakarta.annotation-api</artifactId> <version>3.0.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.30</version> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.13.0</version> <configuration> <source>17</source> <target>17</target> </configuration> </plugin> </plugins> </build> </project>
plugins { id 'java' id 'war' } java { sourceCompatibility = 17 targetCompatibility = 17 } group 'net.maxjava' version '1.0' repositories { mavenCentral() } dependencies { implementation group: 'org.springframework', name: 'spring-webmvc', version: '6.1.6' implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.15.4' implementation group: 'org.mongodb', name: 'mongo-java-driver', version: '3.12.14' implementation group: 'jakarta.annotation', name: 'jakarta.annotation-api', version: '3.0.0' compileOnly group: 'org.projectlombok', name: 'lombok', version: '1.18.30' annotationProcessor group: 'org.projectlombok', name: 'lombok', version: '1.18.30' }
Some notes about pom.xml:
- spring-webmvc for necessary Spring REST controllers and its dependencies
- jackson-databind is for the java object serialization and deserialization
- mongo-java-driver is for MongoDB client libraries
- jakarta.annotation-api is needed for annotations like @PostConstruct
- lombok to remove boilerplate code like get and set
- maven-compiler-plugin is for compiling the code using source version 17 and target version 17
- A war artifact will be created for deployment to servlet containers
Some notes about build.gradle:
- spring-webmvc for necessary Spring REST controllers and its dependencies
- jackson-databind is for the java object serialization and deserialization
- mongo-java-driver is for MongoDB client libraries
- jakarta.annotation-api is needed for annotations like @PostConstruct
- lombok to remove boilerplate code like get and set
- sourceCompatibility and targetCompatibility is for compiling the code using source version 17 and target version 17
- A war artifact will be created for deployment to servlet containers
web.xml:
<web-app> <display-name>Spring REST API with MongoDB Client</display-name> <servlet> <servlet-name>SpringRESTAPIMongoDBClient</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/myApplicationContext.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>SpringRESTAPIMongoDBClient</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
Some notes about web.xml:
- org.springframework.web.servlet.DispatcherServlet is the servlet class for Spring
- /WEB-INF/myApplicationContext.xml is the location of the Spring context configuration file
myApplicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <context:component-scan base-package="controller,repository"/> <mvc:annotation-driven> <mvc:message-converters> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/> </mvc:message-converters> </mvc:annotation-driven> </beans>
Some notes about myApplicationContext.xml:
- <context:component-scan base-package="controller,repository"/> is for Spring to look for classes in specific packages to create beans
- <mvc:message-converters> is to specify library for json serialization and deserialization
This tutorial based on the Mongo DB having a database "mydb" with an user "myuser" and password "mypassword" having the "readWrite" role. The user could be created by:
db.createUser( { user: "myuser", pwd: "mypassword", roles: [ { role: "readWrite", db: "mydb" } ] });
Create a collection "mycollection" if not exists:
db.createCollection("mycollection");
and the index:
db.mycollection.createIndex({"lastName":1});
MyController.java:
package controller; import model.Customer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import repository.MongoDBRepository; import java.util.List; @RestController @RequestMapping("/myapp") public class MyController { @Autowired MongoDBRepository mongoDBRepository; @PostMapping("/customer") public void insertCustomer(@RequestBody Customer customer) { mongoDBRepository.insertCustomer(customer); } @PutMapping("/customer") public void updateCustomerByLastName(@RequestBody Customer customer) { mongoDBRepository.updateCustomerByLastName(customer); } @GetMapping("/customer") public List<Customer> getCustomerByLastName(@RequestParam("lastName") String lastName) { List<Customer> customerList = mongoDBRepository.getCustomerByLastName(lastName); return customerList; } @DeleteMapping("/customer") public void deleteCustomerByLastName(@RequestParam("lastName") String lastName) { mongoDBRepository.deleteCustomerByLastName(lastName); } }
Some notes about MyController.java:
- This is Spring REST API which putting @RestController will do the trick (and make sure the package of this class got scanned in bean creation)
- Autowires MongoDBRepository which is the bean to interact with the database.
- This class provides insertCustomer, updateCustomerByLastName, getCustomerByLastName and deleteCustomerByLastName functions to show some basic operations on data
Customer.java:
package model; import lombok.Data; @Data public class Customer { private String _id; private String lastName; private String firstName; private Address address; private String phone; private String email; }
Some notes about Customer.java:
- This is the object used in the request body and response body of the REST APIs
Address.java:
package model; import lombok.Data; @Data public class Address { private String street; private String city; private String state; private Integer zipCode; }
Some notes about Address.java:
- This is used in the Customer class
MongoDBRepository.java:
package repository; import com.mongodb.*; import com.mongodb.client.*; import com.mongodb.client.MongoClient; import model.Address; import model.Customer; import org.bson.conversions.Bson; import org.springframework.stereotype.Repository; import org.bson.Document; import jakarta.annotation.PostConstruct; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import static com.mongodb.client.model.Filters.eq; import static com.mongodb.client.model.Updates.*; @Repository public class MongoDBRepository { private MongoCollection<Document> mongoCollection; @PostConstruct public void init() { char[] password = {'m', 'y', 'p', 'a', 's', 's', 'w', 'o', 'r', 'd'}; MongoCredential credential = MongoCredential.createCredential("myuser", "mydb", password); ConnectionString connectionString = new ConnectionString("mongodb://localhost:27017/?connectTimeoutMS=5000&serverSelectionTimeoutMS=20000"); MongoClientSettings settings = MongoClientSettings.builder().applyConnectionString(connectionString).credential(credential).build(); MongoClient mongoClient = MongoClients.create(settings); MongoDatabase mongoDatabase = mongoClient.getDatabase("mydb"); mongoCollection = mongoDatabase.getCollection("mycollection"); } public void insertCustomer(Customer customer) { Document documentCustomer = new Document() .append("lastName", customer.getLastName()) .append("firstName", customer.getFirstName()) .append("email", customer.getEmail()) .append("phone", customer.getPhone()); if (customer.getAddress() != null) { Document documentAddress = new Document() .append("street", customer.getAddress().getStreet()) .append("city", customer.getAddress().getCity()) .append("state", customer.getAddress().getState()) .append("zipCode", customer.getAddress().getZipCode()); documentCustomer.append("address", documentAddress); } mongoCollection.insertOne(documentCustomer); } public void updateCustomerByLastName(Customer customer) { Bson bsonFilter = eq("lastName", customer.getLastName()); List<Bson> bsonList = new ArrayList<>(); if (customer.getFirstName() != null) { bsonList.add(set("firstName", customer.getFirstName())); } if (customer.getEmail() != null) { bsonList.add(set("email", customer.getEmail())); } if (customer.getPhone() != null) { bsonList.add(set("phone", customer.getPhone())); } if (customer.getAddress() != null) { Document bsonAddress = new Document() .append("street", customer.getAddress().getStreet()) .append("city", customer.getAddress().getCity()) .append("state", customer.getAddress().getState()) .append("zipCode", customer.getAddress().getZipCode()); bsonList.add(set("address", bsonAddress)); } Bson bsonUpdate = combine(bsonList); mongoCollection.updateMany(bsonFilter, bsonUpdate); } public List<Customer> getCustomerByLastName(String lastName) { List<Customer> customerList = new ArrayList<>(); Iterator<Document> it = mongoCollection.find(new Document("lastName", lastName)).iterator(); while (it.hasNext()) { Document documentCustomer = it.next(); Document documentAddress = (Document)documentCustomer.get("address"); Address address = new Address(); address.setStreet(documentAddress.get("street").toString()); address.setCity(documentAddress.get("city").toString()); address.setState(documentAddress.get("state").toString()); address.setZipCode((Integer)documentAddress.get("zipCode")); Customer customer = new Customer(); customer.set_id(documentCustomer.get("_id").toString()); customer.setLastName(documentCustomer.get("lastName").toString()); customer.setFirstName(documentCustomer.get("firstName").toString()); customer.setPhone(documentCustomer.get("phone").toString()); customer.setEmail(documentCustomer.get("email").toString()); customer.setAddress(address); customerList.add(customer); } return customerList; } public void deleteCustomerByLastName(String lastName) { mongoCollection.deleteMany(new Document("lastName", lastName)); } }
Some notes about MongoDBRepository.java:
- @Repository to specify the class as Spring bean
- @PostConstruct to specify init() to run when the class is initiated, which is to create the mongoCollection object
- This class supports insertCustomer, updateCustomerByLastName, getCustomerByLastName and deleteCustomerByLastName
- Assume MongoDB is at localhost 27017, otherwise please use corresponding values
Sample requests and responses(assume the war file is deployed to <CONTEXT_PATH>):
- Add a new record:
curl --request POST '<CONTEXT_PATH>/myapp/customer' --header 'Content-Type: application/json' --data-raw ' { "lastName": "Smith", "firstName": "Ethan", "email": "ethan.smith@maxjava.net", "phone": "650-123-1234", "address": { "street": "54321 Doyle Rd", "city": "Lexington", "state": "KY", "zipCode": 56789 } }'
- Retrieve the record by last name
Response:curl --request GET '<CONTEXT_PATH>/myapp/customer?lastName=Smith'[ { "_id": "62ad3907b7a6aa67e211fc12", "lastName": "Smith", "firstName": "Ethan", "address": { "street": "54321 Doyle Rd", "city": "Lexington", "state": "KY", "zipCode": 56789 }, "phone": "650-123-1234", "email": "ethan.smith@maxjava.net" } ] - Update the record by using the last name
curl --request PUT '<CONTEXT_PATH>/myapp/customer' --header 'Content-Type: application/json' --data-raw '{ "lastName": "Smith", "phone": "669-123-1234" }'
- Retrieve the record by same last name again
Response:curl --request GET '<CONTEXT_PATH>/myapp/customer?lastName=Smith'[ { "_id": "62ad3907b7a6aa67e211fc12", "lastName": "Smith", "firstName": "Ethan", "address": { "street": "54321 Doyle Rd", "city": "Lexington", "state": "KY", "zipCode": 56789 }, "phone": "669-123-1234", "email": "ethan.smith@maxjava.net" } ] - Deleting records by the last name
curl --request DELETE '<CONTEXT_PATH>/myapp/customer?lastName=Smith'
- Retrieve the record by same last name again
Response:curl --request GET '<CONTEXT_PATH>/myapp/customer?lastName=Smith'[]