ספרינג בוט MongoDB

ברוך הבא לדוגמא של Spring Boot MongoDB. Spring Boot היא הדרך הקלה ביותר להתחיל פרויקט של Spring במהירות ו-MongoDB היא מסד נתונים NoSQL הפופולרי ביותר. בואו נראה איך לאינטגרציה של Spring עם מסד נתונים של MongoDB.

Spring Boot MongoDB

אנו צריכים את ה-API הבאים כדי לעבוד עם Spring Boot ומסד נתונים של MongoDB.

  • Spring Data MongoDB
  • Spring Boot

ישנם שני גישות שבאמצעותן אנו יכולים להתחבר למסד נתונים של MongoDB – MongoRepository ו-MongoTemplate. ננסה להציב מה כל אחת מה-APIs מציעה מעל לשנייה ומתי כדאי לבחור באחת מהן למקרה השימוש שלך. נשתמש בכלי Spring Initializr כדי להגדיר את הפרויקט במהירות. אז בואו נתחיל.

הגדרת פרויקט Spring Boot MongoDB

נשתמש בכלי Spring Initializr כדי להגדיר את הפרויקט במהירות. נשתמש בשני תלות כפי שמוצג למטה: הורד את הפרויקט ופתח אותו. אז ייבא אותו לתוך ה-IDE האהוב עליך – Eclipse או IntelliJ IDEA.

תלויות מייבן

למרות שכבר השלמנו את ההגדרה עם הכלי, אם ברצונך להגדיר את זה ידנית, אנו משתמשים במערכת הבנייה של Maven לפרויקט זה והנה התלויות שבהן השתמשנו:

<?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>

ודא שמשתמשים בגרסה יציבה ל-Spring Boot מהמרכז המאוון של Maven.

מחלקת מודל של MongoDB של Spring Boot

יש לנו מחלקת מודל פשוטה 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;
	}
}

ממשקי מסד נתונים של MongoDB של Spring Boot

יהיה לנו את הפונקציות הבאות והמעורביות עם מסד הנתונים באפליקציה שלנו.

  • קבל את כל המשתמשים
  • קבל משתמש עם זיהוי
  • קבל הגדרות משתמש
  • קבל מפתח מסוים מהמפה
  • הוסף/עדכן הגדרת משתמש

Spring Data MongoDB – MongoRepository

עכשיו נשתמש במאגר נתונים של Spring Data MongoDB כדי לגשת לנתונים שלנו. Spring Data MongoRepository מספק לנו פונקציונליות רגילה שנוכל להוסיף בקלות ולהשתמש בה. בואו נגדיר את ממשק ה־Repository שלנו.

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> {
}

הגדרת מאפייני MongoDB

לפני שנציג את הבקר שלנו, חשוב שנקבע חיבור עם התוכנה המקומית של MongoDB. נשתמש במאפייני Spring Boot כדי לעשות זאת.

# הגדרות MongoDB מקומיות
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=localhost

# הגדרות היישום
server.port=8102
spring.application.name=BootMongo
server.context-path=/user

לכן, היישום ירוץ על פורט 8102 ויתחבר למקומי MongoDB עם ההרשאות שסופקו. אם יש לך מקום מקומי בלי הרשאות מופעלות, תוכל פשוט להסיר את שלושת השורות הראשונות של ההגדרה.

הגדרת בקר Spring

בוא נעבור סופית ליצירת מחלקת הבקר שלנו.

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;
	}
}

אנחנו רק מבצעים כנגד את תלות הממשק של המאגר ונשתמש בזה בהמשך.

הגדרת ה- API

עבור התכונות שצוינו, ניצור כעת API ונגש לתלות במשתמש של מאגר הנתונים שישמש באופן פנימי את API ה-MongoRepository של Spring Data. שימו לב שאין צורך לכתוב קוד אינטראקציה עם מסד הנתונים בממשק מאחר ו-Spring Data עושה זאת עבורנו.

קבלת כל המשתמשים

@RequestMapping(value = "", method = RequestMethod.GET)
public List<User> getAllUsers() {
	LOG.info("Getting all users.");
	return userRepository.findAll();
}

findAll() הוא פשוט שיטה ש-Spring Data MongoRepository מספקת באופן פנימי.

קבלת משתמש לפי זיהוי

עכשיו, בואו נקבל משתמש מסוים עם זיהוי.

@RequestMapping(value = "/{userId}", method = RequestMethod.GET)
public User getUser(@PathVariable String userId) {
	LOG.info("Getting user with ID: {}.", userId);
	return userRepository.findOne(userId);
}

findOne() הוא פשוט שיטה ש-Spring Data MongoRepository מספקת באופן פנימי כדי לקבל אובייקט לפי זיהוי.

הוספת משתמש חדש

נוסיף משתמש חדש בתוך הפונקציה למטה.

@RequestMapping(value = "/create", method = RequestMethod.POST)
public User addNewUsers(@RequestBody User user) {
	LOG.info("Saving user.");
	return userRepository.save(user);
}

קבלת הגדרות משתמש

עכשיו שהוספנו נתונים לדטה בייס, בואו ננסה לחלץ חלק ממנו.

@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.";
	}
}

קבלת הגדרת משתמש מסוימת

@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.";
	}
}

שימו לב בשאילתה שלמעלה, קיבלנו את אובייקט המשתמש, אז חלצנו את המפה המלאה של ההגדרות (שיכלה להכיל אלפי אובייקטים) וסופסוף קיבלנו את הערך שלנו. זהו חסרון של שאילתת Spring Data כאשר אנו משתמשים בה כ-API ישיר.

הוספת הגדרת משתמש חדשה

שנסו להוסיף מידע למשתמש קיים:

@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.";
	}
}

עם כל הקוד שכתבנו, זה ברור שלא היינו צריכים לכתוב שורה אחת של קוד כדי לגשת למסד הנתונים, למעט בהגדרת ממשק המחזיק ובהתקנת תלות. זהו הקלות ש-API של Spring Data MongoRepository מציע לנו, אך יש לו גם צדדים מסוימים. נסביר זאת כאשר נגדיר את גרסת ה-MongoTemplate גם. בואו נתחיל גם עם זה.

Spring Data MongoDB – MongoTemplate

נגדיר כאן את שאילתות מסד הנתונים של MongoTemplate. עם MongoTemplate, תראו שיש לנו שליטה הרבה יותר דקה על מה אנו שואלים ואילו נתונים כלולים בתוצאות.

הגדרת ממשק הגישה למסד נתונים

כדי לספק חוזה בשכבת גישה למסד נתונים, נתחיל על ידי הגדרת ממשק המתנהל כמו שיטות התואמות מובנות של 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);
}

מימוש ממשק הגישה למסד נתונים

בואו נמשיך ונגדיר את השיטות הללו.

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 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);
		// כעת, אובייקט המשתמש יכיל גם את הזיהוי
		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.";
		}
	}
}

מימושי השיטות במחלקה למעלה משתמשים בתלות ב-MongoTemplate. ראו איך השיטה getUserById(...) מקבלת את המשתמש. אנו בונים שאילתא ומעבירים פרמטרים דרושים. מה שיעניין אתכם יותר הוא שאילתת ה-getUserSetting. בואו נבין מה קרה למעלה.

  • בנינו שאילתות עם קריטריונים לבדיקת שוויון.
  • שיטת הכלול כוללת את שמות השדות שבהם יש לכלול את התוצאה כאשר היא נלקחת ממסד הנתונים. זה אומר, במקרה זה, מפתח ה- userSettings יינלקח ויחסוך המון נתונים שאין צורך להביאם
  • בנוסף, שאלנו על שני מפתחות – user ו-map. אם לא נמצא אחד מתוכם, אנו מחזירים נתונים ריקים, המשמעות שהמפתח הנדרש לא נמצא. זה חוסך את הצורך בהבאת אובייקט המשתמש אפילו אם המפתח הנדרש לא היה נמצא

בדיקת ריצה של Spring Data MongoDB

אנו יכולים להפעיל את האפליקציה פשוט על ידי שימוש בפקודה יחידה:

mvn spring-boot:run

פעם שהאפליקציה רצה, נוכל לנסות לשמור משתמש חדש על ידי שימוש ב-API הזה:

https://localhost:8102/user/create

כמו שזה יהיה בבקשה POST, נשלח נתוני JSON כמו כן:

{
  "name" : "Shubham",
  "userSettings" : {
    "bike" : "pulsar"
  }
}

כיוון שאנו מחזירים את תגובת ה-Mongo עצמה, נקבל משהו דומה לזה:

{
  "userId": "5a5f28cc3178058b0fafe1dd",
  "name": "Shubham",
  "creationDate": 1516165830856,
  "userSettings": {
    "bike" : "pulsar"
  }
}

ניתן לקבל את כל המשתמשים על ידי שימוש ב-API כבקשת GET:

https://localhost:8102/user/

נקבל משהו דומה לזה:

[
  {
    "userId": "5a5f28cc3178058b0fafe1dd",
    "name": "Shubham",
    "creationDate": 1516165830856,
    "userSettings": {
      "bike" : "pulsar"
    }
  }
]

אם תראו למעלה במחלקת UserController, לא חיברנו את MongoTemplate לשימוש. הקטע הבא מראה את השינויים הנדרשים לשימוש ב-MongoTemplate לקריאת הגדרות המשתמש.

//תקבע אובייקט שכבת גישה לנתונים
private final UserDAL userDAL;

//אתחל אובייקט שכבת גישה לנתונים דרך הפעלה אוטומטית של הבנאי
public UserController(UserRepository userRepository, UserDAL userDAL) {
	this.userRepository = userRepository;
	this.userDAL = userDAL;
}

//שנה את המימוש של השיטה כך שתשתמש בשכבת גישה לנתונים ולכן ב־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.";
    }
}

//שנה את המימוש של השיטה כך שתשתמש בשכבת גישה לנתונים ולכן ב־MongoTemplate
@RequestMapping(value = "/settings/{userId}/{key}", method = RequestMethod.GET)
public String getUserSetting(
        @PathVariable String userId, @PathVariable String key) {
    return userDAL.getUserSetting(userId, key);
}

אתחל את האפליקציה מחדש והרץ תרחישים כדי לקבל את כל הגדרות המשתמש וכדי לקבל כל מפתח ספציפי. בתמונה למטה מוצגת הפלט מאפליקציית Postman.

MongoTemplate נגד MongoRepository

  • MongoTemplate מספקת שליטה הרבה יותר גדולה כאשר מדובר בשאילתת נתונים ובאילו נתונים להביא ממסד הנתונים.
  • מאגרי נתונים של Spring Data מספקים לנו מבט נוח על איך לאחזר נתונים.
  • MongoTemplate תלויה במסד הנתונים. מה שזה אומר הוא, עם מאגרי נתונים של Spring Data, אתה יכול לעבור בקלות למסד נתונים שונה לחלוטין על ידי פשוט בעזרת שימוש במאגרי נתונים של Spring Data שונים עבור MySQL או Neo4J או כל דבר אחר. זה אינו אפשרי עם MongoTemplate.

סיכום Spring Boot MongoDB

בשיעור הזה, בדקנו כיצד ניתן להשתמש ב-MongoTemplate כדי לספק לנו יותר שליטה על ספריות נתונים של Spring Data, אך זה יכול גם להיות מעט מסובך כאשר מעורבים שאילתות עמוקות יותר. אז זה לחלוטין החלטתך מה לבחור כאשר אתה מפתח את הרעיון שלך. תרגיש חופשי להשאיר הערות למטה. הורד את קוד המקור מהקישור למטה. אנא וודא ששינית את פרטי הכניסה ל-MongoDB לפני הרצת האפליקציה שנמסרה.

הורד דוגמת פרויקט Spring Boot MongoDB

Source:
https://www.digitalocean.com/community/tutorials/spring-boot-mongodb