Spring Boot MongoDB

ようこそSpring Boot MongoDB の例へ。Spring Bootは素早くSpringプロジェクトを立ち上げる最も簡単な方法であり、MongoDBは最も人気のあるNoSQLデータベースです。SpringをMongoDBデータベースと統合する方法を見てみましょう。

Spring Boot MongoDB

Spring BootとMongoDBデータベースを操作するためには、以下のAPIが必要です。

  • Spring Data MongoDB
  • Spring Boot

MongoDBデータベースに接続するためには、MongoRepositoryMongoTemplateの2つのアプローチがあります。私たちは、どちらのAPIが他よりも優れているか、およびどちらをどのようなユースケースに選択すべきかを確立しようとします。Spring Initializrツールを使用してプロジェクトを迅速にセットアップします。さあ、始めましょう。

Spring Boot MongoDBプロジェクトのセットアップ

Spring Initializrツールを使用してプロジェクトを迅速にセットアップします。以下に示すように、2つの依存関係のみを使用します:プロジェクトをダウンロードして解凍します。次に、お好きなIDE(EclipseまたはIntelliJ IDEA)にインポートします。

Mavenの依存関係

ツールを使って設定を完了しましたが、手動でセットアップする場合は、このプロジェクトに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 Central から使用してください。

Spring Boot MongoDBモデルクラス

私たちは単純なモデルクラス 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;
	}
}

Spring Boot MongoDBのAPI

アプリケーション内で以下の機能とデータベースの相互作用があります。

  • すべてのユーザーを取得
  • 特定のIDを持つユーザーを取得
  • ユーザーの設定を取得
  • マップから特定のキーを取得
  • ユーザーの設定を追加/更新

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インスタンスに接続します。 認証が有効になっていないローカルインスタンスがある場合は、構成の最初の3行を削除するだけです。

Springコントローラーの定義

最後に、Controllerクラスを作成してみましょう。

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

私たちはちょうどリポジトリインターフェースの依存関係をAutowiredし、次にこれを使用します。

APIの定義

私たちが言及した機能について、今後はAPIを作成し、内部的にSpring Data MongoRepository APIを使用するuserRepository依存関係にアクセスします。Spring Dataがすべてを私たちのために行うので、インターフェースにはデータベースとのやり取りコードを書く必要がないことに注意してください。

すべてのユーザーを取得する

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

findAll()は、Spring Data MongoRepositoryが内部的に提供するメソッドです。

IDでユーザーを取得する

では、特定の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()は、IDでオブジェクトを取得するためにSpring Data MongoRepositoryが内部的に提供するメソッドです。

新しいユーザーを追加する

以下の関数に新しいユーザーを追加します。

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

ユーザー設定を取得する

今、DBにサンプルデータを追加したので、その一部を抽出しようとしています。

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

上記のクエリで、ユーザーオブジェクトを取得し、完全なSettingマップ(1000個以上のオブジェクトを含む可能性があります)を抽出し、最終的に自分の値を取得しました。これは、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.";
	}
}

書いたすべてのコードを考えると、リポジトリインターフェースを定義し、依存関係を自動配線する以外に、データベースにアクセスするためのコードを一行も書かなくてもよいことが明らかです。これは Spring Data の MongoRepository API が提供する利便性ですが、いくつかの欠点もあります。これについては、MongoTemplate バージョンを定義した後に詳しく説明します。それでは、それも始めましょう。

Spring Data MongoDB – MongoTemplate

ここで MongoTemplate データベースクエリを定義します。MongoTemplate を使用すると、クエリや結果に含まれるデータをより詳細に制御できることがわかります。

データアクセスレイヤーの DAL インターフェースを定義する

データベースアクセスレイヤーでの契約を提供するために、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);
}

DAL インターフェースの実装

これらのメソッドを定義してみましょう。

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);
		// 今、ユーザーオブジェクトには ID も含まれます
		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 クエリです。上記で何が起こったかを理解しましょう:

  • クエリを構築し、等しさを確認するための基準を備えました。
  • includeメソッドは、DBから抽出される結果に含まれる必要があるフィールド名を含みます。 これは、この場合、userSettingsキーが抽出され、不要なデータを取得する必要がなくなります
  • また、ユーザーとマップキーの両方でクエリを実行しました。 それらのいずれかが見つからない場合、必要なキーが見つからなかったということで空のデータを返します。 これにより、必要なキーが存在しない場合は、ユーザーオブジェクトを全く取得しなくても済みます

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;

//コンストラクタのオートワイヤリングを使用してDALオブジェクトを初期化する
public UserController(UserRepository userRepository, UserDAL userDAL) {
	this.userRepository = userRepository;
	this.userDAL = userDAL;
}

//メソッドの実装をDALおよび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.";
    }
}

//メソッドの実装をDALおよび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