- Sản phẩm & Dịch vụSản phẩm & Dịch vụ
- Giải phápGiải pháp
- Bảng giáBảng giá
- Công tyCông ty
- Tài liệuTài liệu
vi
vi
Chuyên mục với các bài viết hướng dẫn, nghiên cứu và phân tích chi tiết về kỹ thuật, các xu hướng công nghệ mới nhất dành cho lập trình viên.
Web Developer
I’m passionate about web development and sharing my insights through articles, with over 8 years of experience. I hope these sharings inspire you and help build a strong web development community. @#@ Tôi đam mê phát triển web và chia sẻ những hiểu biết của mình thông qua các bài viết, với hơn 8 năm kinh nghiệm. Tôi hy vọng những chia sẻ này sẽ truyền cảm hứng cho các bạn và giúp xây dựng một cộng đồng phát triển web mạnh mẽ.
Thảo luận (0)
Đăng nhập để thảo luận
Spring Boot là cách đơn giản nhất để khởi tạo nhanh một dự án Spring, còn MongoDB là cơ sở dữ liệu NoSQL phổ biến nhất hiện nay. Trong bài viết này, chúng ta cùng tìm hiểu cách tích hợp Spring Boot với MongoDB.

Chúng ta cần các API sau để làm việc với Spring Boot và cơ sở dữ liệu MongoDB:
Có hai cách tiếp cận để kết nối với cơ sở dữ liệu MongoDB: MongoRepository và MongoTemplate.
Chúng ta sẽ tìm hiểu xem mỗi API cung cấp những gì, ưu điểm của từng cách, và khi nào nên sử dụng chúng tùy theo từng trường hợp cụ thể.
Chúng ta sẽ sử dụng công cụ Spring Initializr để thiết lập dự án một cách nhanh chóng.
Giờ thì bắt đầu thôi!
Chúng ta sẽ sử dụng công cụ **Spring Initializr** để thiết lập dự án một cách nhanh chóng. Trong dự án này, chúng ta chỉ sử dụng hai dependency như được hiển thị bên dưới:

Tải dự án xuống và giải nén. Sau đó, nhập dự án vào IDE yêu thích của bạn – **Eclipse** hoặc **IntelliJ IDEA**.
Mặc dù chúng ta đã thiết lập dự án bằng công cụ Spring Initializr, nếu bạn muốn cấu hình thủ công, dự án này sử dụng hệ thống xây dựng Maven và dưới đây là các dependency được sử dụng:
<?xml version="1.0" encoding="UTF-8"?> <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>com.journaldev.spring</groupId> <artifactId>spring-boot-mongodb</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>spring-boot-mongodb</name> <description>Spring Boot MongoDB Example</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.9.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build></project>
Hãy đảm bảo sử dụng phiên bản ổn định của Spring Boot từ Maven Central.
Chúng ta có một lớp model đơn giản là User.java.
package com.journaldev.bootifulmongodb.model;import java.util.Date; import java.util.HashMap; import java.util.Map;
import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document;
@Document public class User {
@Id private String userId; private String name; private Date creationDate = new Date(); private Map<String, String> userSettings = new HashMap<>(); public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Date getCreationDate() { return creationDate; } public void setCreationDate(Date creationDate) { this.creationDate = creationDate; } public Map<String, String> getUserSettings() { return userSettings; } public void setUserSettings(Map<String, String> userSettings) { this.userSettings = userSettings; }}
Ứng dụng của chúng ta sẽ có các chức năng và tương tác với cơ sở dữ liệu như sau:
Bây giờ chúng ta sẽ sử dụng Spring Data MongoDB Repository để truy cập dữ liệu. MongoRepository trong Spring Data cung cấp sẵn các chức năng phổ biến mà chúng ta có thể dễ dàng tích hợp và sử dụng. Giờ hãy định nghĩa interface Repository của chúng ta.
package com.journaldev.bootifulmongodb.dal;import org.springframework.data.mongodb.repository.MongoRepository; import org.springframework.stereotype.Repository;
import com.journaldev.bootifulmongodb.model.User;
@Repository public interface UserRepository extends MongoRepository<User, String> { }
Định nghĩa các thuộc tính kết nối MongoDB
Trước khi xây dựng controller, điều quan trọng là chúng ta cần thiết lập kết nối với một phiên bản MongoDB cục bộ. Chúng ta sẽ sử dụng các thuộc tính cấu hình của Spring Boot để thực hiện điều này.
#Local MongoDB config spring.data.mongodb.authentication-database=admin spring.data.mongodb.username=root spring.data.mongodb.password=root spring.data.mongodb.database=user_db spring.data.mongodb.port=27017 spring.data.mongodb.host=localhostApp config
server.port=8102 spring.application.name=BootMongo server.context-path=/user
Vậy là ứng dụng sẽ chạy trên cổng 8102 và kết nối đến một phiên bản MongoDB local với thông tin đăng nhập được cung cấp. Nếu bạn đang sử dụng instance MongoDB local không bật xác thực, bạn chỉ cần xóa ba dòng cấu hình đầu tiên.
Định nghĩa controller trong Spring
Cuối cùng, hãy cùng tạo lớp Controller cho ứng dụng của chúng ta.
package com.journaldev.bootifulmongodb.controller;import java.util.List;
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController;
import com.journaldev.bootifulmongodb.dal.UserRepository; import com.journaldev.bootifulmongodb.model.User;
@RestController @RequestMapping(value = "/") public class UserController {
private final Logger LOG = LoggerFactory.getLogger(getClass()); private final UserRepository userRepository; public UserController(UserRepository userRepository) { this.userRepository = userRepository; }}
Chúng ta chỉ cần Autowired (tự động gán) phụ thuộc của interface repository và sẽ sử dụng nó ngay sau đây.
Đối với các chức năng đã đề cập trước đó, giờ đây chúng ta sẽ tạo các API và sử dụng dependency userRepository, đối tượng này bên trong sẽ sử dụng API của Spring Data MongoRepository.
Lưu ý rằng chúng ta không cần viết bất kỳ đoạn code tương tác cơ sở dữ liệu nào trong interface vì Spring Data đã xử lý tất cả cho chúng ta.
Lấy danh sách tất cả người dùng
@RequestMapping(value = "", method = RequestMethod.GET)
public List<User> getAllUsers() {
LOG.info("Getting all users.");
return userRepository.findAll();
}
findAll() chỉ là một phương thức được Spring Data MongoRepository cung cấp sẵn bên trong.
Lấy người dùng theo ID
Bây giờ, chúng ta sẽ lấy thông tin của một người dùng cụ thể thông qua ID.
@RequestMapping(value = "/{userId}", method = RequestMethod.GET)
public User getUser(@PathVariable String userId) {
LOG.info("Getting user with ID: {}.", userId);
return userRepository.findOne(userId);
}
findOne() chỉ là một phương thức được Spring Data MongoRepository cung cấp sẵn để lấy một đối tượng theo ID.
Thêm người dùng mới
Chúng ta sẽ thêm một người dùng mới trong hàm dưới đây.
@RequestMapping(value = "/create", method = RequestMethod.POST)
public User addNewUsers(@RequestBody User user) {
LOG.info("Saving user.");
return userRepository.save(user);
}
Lấy cài đặt của người dùng
Bây giờ khi chúng ta đã thêm dữ liệu mẫu vào cơ sở dữ liệu, hãy thử trích xuất một phần trong số đó.
@RequestMapping(value = "/settings/{userId}", method = RequestMethod.GET)
public Object getAllUserSettings(@PathVariable String userId) {
User user = userRepository.findOne(userId);
if (user != null) {
return user.getUserSettings();
} else {
return "User not found.";
}
}
Lấy một cài đặt cụ thể của người dùng
@RequestMapping(value = "/settings/{userId}/{key}", method = RequestMethod.GET)
public String getUserSetting(@PathVariable String userId, @PathVariable String key) {
User user = userRepository.findOne(userId);
if (user != null) {
return user.getUserSettings().get(key);
} else {
return "User not found.";
}
}
Lưu ý trong truy vấn trên, chúng ta lấy đối tượng người dùng, sau đó trích xuất toàn bộ Map chứa Setting (có thể chứa hàng ngàn đối tượng), và cuối cùng mới lấy được giá trị cần thiết. Đây là một điểm hạn chế của truy vấn trong Spring Data khi chúng ta sử dụng nó như một API trực tiếp.
Thêm cài đặt mới cho người dùng
Hãy thử thêm một vài dữ liệu vào một người dùng đã tồn tại:
@RequestMapping(value = "/settings/{userId}/{key}/{value}", method = RequestMethod.GET)
public String addUserSetting(@PathVariable String userId, @PathVariable String key, @PathVariable String value) {
User user = userRepository.findOne(userId);
if (user != null) {
user.getUserSettings().put(key, value);
userRepository.save(user);
return "Key added";
} else {
return "User not found.";
}
}
Với toàn bộ đoạn code mà chúng ta đã viết, có thể thấy rõ rằng chúng ta không cần viết bất kỳ dòng code nào để truy cập cơ sở dữ liệu, ngoài việc định nghĩa interface repository và tự động gán phụ thuộc (autowire dependency). Đây chính là sự tiện lợi mà Spring Data MongoRepository API mang lại cho chúng ta. Tuy nhiên, nó cũng có một số hạn chế. Chúng ta sẽ phân tích kỹ hơn về điều này sau khi triển khai phiên bản sử dụng MongoTemplate. Bây giờ, hãy cùng bắt đầu với phần đó.
Tại phần này, chúng ta sẽ định nghĩa các truy vấn cơ sở dữ liệu sử dụng MongoTemplate. Với MongoTemplate, bạn sẽ thấy rằng chúng ta có khả năng kiểm soát chi tiết hơn đối với các truy vấn và dữ liệu trả về trong kết quả.
Để cung cấp một lớp hợp đồng cho tầng truy cập dữ liệu, chúng ta sẽ bắt đầu bằng cách định nghĩa một interface hoạt động tương tự như các phương thức dựng sẵn của Spring Data.
package com.journaldev.bootifulmongodb.dal;import java.util.List;
import com.journaldev.bootifulmongodb.model.User;
public interface UserDAL {
List<User> getAllUsers(); User getUserById(String userId); User addNewUser(User user); Object getAllUserSettings(String userId); String getUserSetting(String userId, String key); String addUserSetting(String userId, String key, String value);}
Hãy tiếp tục và định nghĩa các phương thức này.
package com.journaldev.bootifulmongodb.dal;import java.util.List;
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.journaldev.bootifulmongodb.model.User;
@Repository public class UserDALImpl implements UserDAL {
@Autowired private MongoTemplate mongoTemplate; @Override public List<User> getAllUsers() { return mongoTemplate.findAll(User.class); } @Override public User getUserById(String userId) { Query query = new Query(); query.addCriteria(Criteria.where("userId").is(userId)); return mongoTemplate.findOne(query, User.class); } @Override public User addNewUser(User user) { mongoTemplate.save(user); // Now, user object will contain the ID as well return user; } @Override public Object getAllUserSettings(String userId) { Query query = new Query(); query.addCriteria(Criteria.where("userId").is(userId)); User user = mongoTemplate.findOne(query, User.class); return user != null ? user.getUserSettings() : "User not found."; } @Override public String getUserSetting(String userId, String key) { Query query = new Query(); query.fields().include("userSettings"); query.addCriteria(Criteria.where("userId").is(userId).andOperator(Criteria.where("userSettings." + key).exists(true))); User user = mongoTemplate.findOne(query, User.class); return user != null ? user.getUserSettings().get(key) : "Not found."; } @Override public String addUserSetting(String userId, String key, String value) { Query query = new Query(); query.addCriteria(Criteria.where("userId").is(userId)); User user = mongoTemplate.findOne(query, User.class); if (user != null) { user.getUserSettings().put(key, value); mongoTemplate.save(user); return "Key added."; } else { return "User not found."; } }}
Các phương thức được triển khai trong lớp trên sử dụng dependency MongoTemplate. Hãy xem cách phương thức getUserById(...) lấy thông tin người dùng – chúng ta tạo một truy vấn và truyền vào các tham số cần thiết. Điều đáng chú ý hơn chính là truy vấn trong phương thức getUserSetting. Hãy cùng phân tích điều đã xảy ra ở phần trên:
criteria để kiểm tra sự bằng nhau.include dùng để chỉ định các trường sẽ được truy xuất từ cơ sở dữ liệu. Trong trường hợp này, chỉ có khóa userSettings được lấy ra, điều này giúp tiết kiệm tài nguyên bằng cách không truy xuất những dữ liệu không cần thiết.user và map key. Nếu một trong hai không tìm thấy, dữ liệu rỗng sẽ được trả về, nghĩa là khóa cần tìm không tồn tại. Điều này giúp tránh việc truy xuất toàn bộ đối tượng User khi khóa đó không có trong cơ sở dữ liệu.Chúng ta có thể chạy ứng dụng này chỉ với một lệnh đơn giản:
mvn spring-boot:run
Sau khi ứng dụng đã khởi động, chúng ta có thể thử lưu một người dùng mới bằng cách sử dụng API sau:
<https://localhost:8102/user/create>
Vì đây là một yêu cầu POST, chúng ta sẽ gửi kèm dữ liệu dưới dạng JSON:
{
"name" : "Shubham",
"userSettings" : {
"bike" : "pulsar"
}
}
Vì chúng ta trả về phản hồi trực tiếp từ MongoDB, kết quả nhận được sẽ có dạng như sau:
{
"userId": "5a5f28cc3178058b0fafe1dd",
"name": "Shubham",
"creationDate": 1516165830856,
"userSettings": {
"bike" : "pulsar"
}
}
Bạn có thể lấy danh sách tất cả người dùng bằng cách sử dụng API dưới dạng yêu cầu GET:
<https://localhost:8102/user/>
Chúng ta sẽ nhận được kết quả tương tự như sau:
[
{
"userId": "5a5f28cc3178058b0fafe1dd",
"name": "Shubham",
"creationDate": 1516165830856,
"userSettings": {
"bike" : "pulsar"
}
}
]
Nếu bạn để ý lớp UserController ở trên, chúng ta chưa kết nối MongoTemplate để sử dụng. Đoạn mã dưới đây minh họa các thay đổi cần thiết để dùng MongoTemplate trong việc đọc cài đặt người dùng.
//define Data Access Layer object private final UserDAL userDAL;//initialize DAL object via constructor autowiring public UserController(UserRepository userRepository, UserDAL userDAL) { this.userRepository = userRepository; this.userDAL = userDAL; }
//change method implementation to use DAL and hence MongoTemplate @RequestMapping(value = "/settings/{userId}", method = RequestMethod.GET) public Object getAllUserSettings(@PathVariable String userId) { User user = userRepository.findOne(userId); if (user != null) { return userDAL.getAllUserSettings(userId); } else { return "User not found."; } }
//change method implementation to use DAL and hence MongoTemplate @RequestMapping(value = "/settings/{userId}/{key}", method = RequestMethod.GET) public String getUserSetting( @PathVariable String userId, @PathVariable String key) { return userDAL.getUserSetting(userId, key); }
Khởi động lại ứng dụng và chạy các trường hợp để lấy toàn bộ cài đặt người dùng cũng như lấy một khóa cụ thể. Hình ảnh dưới đây là kết quả trả về từ ứng dụng Postman.


MongoTemplate cung cấp nhiều quyền kiểm soát hơn khi thực hiện truy vấn dữ liệu và lựa chọn dữ liệu cần lấy từ cơ sở dữ liệu.
Các repository của Spring Data mang lại cho chúng ta một cách tiếp cận thuận tiện để truy xuất dữ liệu.
Tuy nhiên, MongoTemplate phụ thuộc chặt chẽ vào cơ sở dữ liệu cụ thể. Điều này có nghĩa là với các repository của Spring Data, bạn có thể dễ dàng chuyển sang sử dụng cơ sở dữ liệu khác như MySQL, Neo4J hoặc các hệ quản trị khác chỉ bằng cách thay đổi repository tương ứng của Spring Data. Điều này không khả thi khi sử dụng MongoTemplate.
Trong bài học này, chúng ta đã tìm hiểu cách MongoTemplate giúp cung cấp nhiều quyền kiểm soát hơn so với các repository của Spring Data, nhưng đồng thời cũng có thể phức tạp hơn khi thực hiện các truy vấn sâu. Vì vậy, việc lựa chọn sử dụng phương pháp nào hoàn toàn phụ thuộc vào bạn khi phát triển ý tưởng của mình. Hãy để lại bình luận bên dưới nếu bạn có bất kỳ câu hỏi nào hoặc muốn trao đổi thêm nhé!