openplanning

Hướng dẫn sử dụng Spring Boot và MongoDB

  1. Tạo dự án Spring Boot
  2. Cấu hình MongoDB
  3. Spring Data MongoDB
  4. Controller
  5. Chạy ứng dụng
Trong bài học này tôi sẽ hướng dẫn bạn tạo một ứng dụng Spring Boot kết nối vào cơ sở dữ liệu MongoDB. Và tìm hiểu về Spring data MongoDB.

1. Tạo dự án Spring Boot

Trên Eclipse tạo một dự án Spring Boot.
pom.xml
<?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>org.o7planning</groupId>
    <artifactId>SpringBootMongoDB</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>SpringBootMongoDB</name>
    <description>Spring Boot +MongoDB</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.0.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>

2. Cấu hình MongoDB

Để Spring Boot có thể kết nối vào cơ sở dữ liệu MongoDB bạn cần cấu hình các thuộc tính (properity) trong tập tin applications.properties.
application.properties
#mongodb
spring.data.mongodb.host=192.168.254.129
spring.data.mongodb.port=27017
spring.data.mongodb.database=mydatabase

#logging
logging.level.org.springframework.data=debug
logging.level.=error
Trong ứng dụng này, tôi kết nối vào "mydatabase" của MongoDB, bạn không phải lo lắng, nếu "mydatabase" không tồn tại nó sẽ tự động được tạo ra.

3. Spring Data MongoDB

Spring Data MongoDB là một thư viện của Spring, nó giúp bạn dễ dàng làm việc với MongoDB. Chẳng hạn bạn có một Collection T và bạn muốn tạo một Class có 4 chức năng truy vấn, thêm, sửa, xóa trên Collection này? Rất đơn giản!

Theo quy tắc của Spring Data MongoDB bạn chỉ cần định nghĩa một interface mở rộng interface MongoRepository<T,ID>, và khai báo các phương thức để thao tác với dữ liệu của Collection này. Spring Data MongoDB sẽ tự tạo một lớp thi hành (implements) interface đó cho bạn. Tất nhiên, tên của các phương thức phải theo một quy tắc mà Spring Data MongoDB đề ra.
Chẳng hạn trên database chúng ta có collection Employee, nó tương ứng với lớp Employee của Java. Các trường (field) của collection này sẽ tương ứng với các trường (field) của lớp Employee. Trường ID là khóa chính (primary key).
Employee.java
package org.o7planning.sbmongodb.document;

import java.util.Date;

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

@Document(collection = "Employee")
public class Employee {

    @Id
    private Long id;

    @Indexed(unique = true)
    @Field(value = "Emp_No")
    private String empNo;

    @Field(value = "Full_Name")
    private String fullName;

    @Field(value = "Hire_Date")
    private Date hireDate;

    public Long getId() {
        return id;
    }

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

    public String getEmpNo() {
        return empNo;
    }

    public void setEmpNo(String empNo) {
        this.empNo = empNo;
    }

    public String getFullName() {
        return fullName;
    }

    public void setFullName(String fullName) {
        this.fullName = fullName;
    }

    public Date getHireDate() {
        return hireDate;
    }

    public void setHireDate(Date hireDate) {
        this.hireDate = hireDate;
    }

    @Override
    public String toString() {
        return "id:" + this.id + ", empNo: " + empNo //
                + ", fullName: " + this.fullName + ", hireDate: " + this.hireDate;
    }
}
Interface EmployeeRepository mở rộng (extends) interface MongoRepository<Employee, Long>, nó có các phương thức để thao tác với collection Employee. Spring Data MongoDB sẽ tự động tạo một lớp thi hành (implements) interface này tại thời điểm chạy của ứng dụng.
EmployeeRepository.java
package org.o7planning.sbmongodb.repository;

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

import org.o7planning.sbmongodb.document.Employee;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;

// This is an Interface.
// No need Annotation here
public interface EmployeeRepository extends MongoRepository<Employee, Long> { // Long: Type of Employee ID.

    Employee findByEmpNo(String empNo);

    List<Employee> findByFullNameLike(String fullName);

    List<Employee> findByHireDateGreaterThan(Date hireDate);

    // Supports native JSON query string
    @Query("{fullName:'?0'}")
    List<Employee> findCustomByFullName(String fullName);

}
Spring Data MongoDB sẽ tự động tạo các phương thức thực hiện các phương thức trừu tượng của Interface. Dưới đây là danh sách các từ khóa được hỗ trợ cho các phương thức truy vấn dữ liệu:
GreaterThan
findByAgeGreaterThan(int age)
{"age" : {"$gt" : age}}
LessThan
findByAgeLessThan(int age)
{"age" : {"$lt" : age}}
Between
findByAgeBetween(int from, int to)
{"age" : {"$gt" : from, "$lt" : to}}
IsNotNull, NotNull
findByFirstnameNotNull()
{"age" : {"$ne" : null}}
IsNull, Null
findByFirstnameNull()
{"age" : null}
Like
findByFirstnameLike(String name)
{"age" : age} ( age as regex)
(No keyword)
findByFirstname(String name)
{"age" : name}
Not
findByFirstnameNot(String name)
{"age" : {"$ne" : name}}
Near
findByLocationNear(Point point)
{"location" : {"$near" : [x,y]}}
Within
findByLocationWithin(Circle circle)
{"location" : {"$within" : {"$center" : [ [x, y], distance]}}}
Within
findByLocationWithin(Box box)
{"location" : {"$within" : {"$box" : [ [x1, y1], x2, y2]}}}
Ngoài ra bạn cũng có thể tạo các interface với các phương thức tùy biến. Trong trường hợp này bạn phải tự viết lớp thi hành (implements) interface đó.
EmployeeRepositoryCustom.java
package org.o7planning.sbmongodb.repository;

import java.util.Date;

public interface EmployeeRepositoryCustom {

    public long getMaxEmpId();
    
    public long updateEmployee(String empNo, String fullName, Date hireDate);
    
}
EmployeeRepositoryCustomImpl.java
package org.o7planning.sbmongodb.repository;

import java.util.Date;

import org.o7planning.sbmongodb.document.Employee;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
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.mongodb.client.result.UpdateResult;

@Repository
public class EmployeeRepositoryCustomImpl implements EmployeeRepositoryCustom {

    @Autowired
    MongoTemplate mongoTemplate;

    public long getMaxEmpId() {
        Query query = new Query();
        query.with(new Sort(Sort.Direction.DESC, "id"));
        query.limit(1);
        Employee maxObject = mongoTemplate.findOne(query, Employee.class);
        if (maxObject == null) {
            return 0L;
        }
        return maxObject.getId();
    }

    @Override
    public long updateEmployee(String empNo, String fullName, Date hireDate) {
        Query query = new Query(Criteria.where("empNo").is(empNo));
        Update update = new Update();
        update.set("fullName", fullName);
        update.set("hireDate", hireDate);

        UpdateResult result = this.mongoTemplate.updateFirst(query, update, Employee.class);

        if (result != null) {
            return result.getModifiedCount();
        }

        return 0;
    }

}

4. Controller

SpringBootMongoDbApplication.java
package org.o7planning.sbmongodb;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;

@SpringBootApplication
public class SpringBootMongoDbApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootMongoDbApplication.class, args);
    }

    @Bean
    public MongoTemplate mongoTemplate(MongoDbFactory mongoDbFactory, MongoMappingContext context) {

        MappingMongoConverter converter = new MappingMongoConverter(new DefaultDbRefResolver(mongoDbFactory), context);
        converter.setTypeMapper(new DefaultMongoTypeMapper(null));

        MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory, converter);

        return mongoTemplate;

    }
    
}
MainController.java
package org.o7planning.sbmongodb.controller;

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

import org.o7planning.sbmongodb.document.Employee;
import org.o7planning.sbmongodb.repository.EmployeeRepository;
import org.o7planning.sbmongodb.repository.EmployeeRepositoryCustom;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class MainController {

    private static final String[] NAMES = { "Tom", "Jerry", "Donald" };

    @Autowired
    private EmployeeRepositoryCustom employeeRepositoryCustom;

    @Autowired
    private EmployeeRepository employeeRepository;

    @ResponseBody
    @RequestMapping("/")
    public String home() {
        String html = "";
        html += "<ul>";
        html += " <li><a href='/testInsert'>Test Insert</a></li>";
        html += " <li><a href='/showAllEmployee'>Show All Employee</a></li>";
        html += " <li><a href='/showFullNameLikeTom'>Show All 'Tom'</a></li>";
        html += " <li><a href='/deleteAllEmployee'>Delete All Employee</a></li>";
        html += "</ul>";
        return html;
    }

    @ResponseBody
    @RequestMapping("/testInsert")
    public String testInsert() {
        Employee employee = new Employee();

        long id = this.employeeRepositoryCustom.getMaxEmpId() + 1;
        int idx = (int) (id % NAMES.length);
        String fullName = NAMES[idx] + " " + id;

        employee.setId(id);
        employee.setEmpNo("E" + id);
        employee.setFullName(fullName);
        employee.setHireDate(new Date());
        this.employeeRepository.insert(employee);

        return "Inserted: " + employee;
    }

    @ResponseBody
    @RequestMapping("/showAllEmployee")
    public String showAllEmployee() {

        List<Employee> employees = this.employeeRepository.findAll();

        String html = "";
        for (Employee emp : employees) {
            html += emp + "<br>";
        }

        return html;
    }

    @ResponseBody
    @RequestMapping("/showFullNameLikeTom")
    public String showFullNameLikeTom() {

        List<Employee> employees = this.employeeRepository.findByFullNameLike("Tom");

        String html = "";
        for (Employee emp : employees) {
            html += emp + "<br>";
        }

        return html;
    }

    @ResponseBody
    @RequestMapping("/deleteAllEmployee")
    public String deleteAllEmployee() {

        this.employeeRepository.deleteAll();
        return "Deleted!";
    }

}

5. Chạy ứng dụng

Các hướng dẫn Spring Boot

Show More