スプリングブートモンゴDB
「Spring Boot MongoDBの例へようこそ。Spring Bootは、スプリングプロジェクトを素早く立ち上げるための最も簡単な方法であり、MongoDBは最も人気のあるNoSQLデータベースです。では、SpringとMongoDBデータベースをどのように統合するか見てみましょう。」
スプリングブートのモンゴDB
スプリングブートとMongoDBデータベースを使用するために、以下のAPIが必要です。
- Spring Data MongoDB
- Spring Boot
MongoDBデータベースに接続するための2つのアプローチがあります – MongoRepositoryとMongoTemplateです。一つAPIが他より提供するものと、どちらを選ぶべきかを確認します。プロジェクトの素早い設定のためにSpring Initializrツールを使用します。さあ、始めましょう。
春のブートMongoDBプロジェクトのセットアップ
メイブンの依存関係
ツールを使ってセットアップは既に完了しましたが、手動でセットアップする場合は、このプロジェクトでは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.scdev.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>
Mavenの中央リポジトリからSpring Bootの安定版を使用するようにしてください。
スプリングブートのMongoDBモデルクラス
私たちには、簡単なモデルクラスUser.javaがあります。
package com.scdev.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のAPI
私たちは、アプリ内で以下の機能とデータベースの相互作用を提供します。
- Get all users
- Get a user with ID
- Get user settings
- Get a particular key from the Map
- Add/Update user setting
Spring Data MongoDB – MongoRepositoryは、MongoDBデータベースへのアクセスを容易にするためのSpring Dataのコンポーネントです。
今回は、Spring Data MongoDB リポジトリを使用してデータにアクセスします。Spring Data MongoRepository は、簡単にプラグインして使用できる共通の機能を提供してくれます。では、リポジトリのインターフェースを定義しましょう。
package com.scdev.bootifulmongodb.dal;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;
import com.scdev.bootifulmongodb.model.User;
@Repository
public interface UserRepository extends MongoRepository<User, String> {
}
MongoDBプロパティの定義
私たちがコントローラを展開する前に、MongoDBのローカルインスタンスとの接続を確立することが重要です。これにはSpring Bootのプロパティを使用します。
#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=localhost
# App config
server.port=8102
spring.application.name=BootMongo
server.context-path=/user
ですので、アプリはポート8102で実行され、提供された認証情報でローカルのmongoDBインスタンスに接続します。認証が有効化されていないローカルインスタンスがある場合は、設定の最初の3行を削除するだけで構いません。
春のコントローラを定義する
最終的には、私たちのControllerクラス作成に移りましょう。
package com.scdev.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.scdev.bootifulmongodb.dal.UserRepository;
import com.scdev.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を作成し、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() は、Spring Data MongoRepository が内部的に提供するメソッドであり、ID によってオブジェクトを取得するために使われます。
新しいユーザーを追加する
以下の機能に新しいユーザーを追加します。
@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.";
}
}
上記のクエリで、ユーザーオブジェクトを取得し、完全な設定マップ(数千のオブジェクトを含む可能性があります)を抽出し、最終的に自分の値を取得しました。これは、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バージョンを定義した後で、これについて詳しく説明します。それでは、MongoTemplateのバージョン定義から始めましょう。
Spring Data MongoDBは、MongoTemplateを使用します。
ここでは、MongoTemplateのデータベースクエリを定義します。MongoTemplateを使用すると、クエリする内容や結果に含まれるデータを細かく制御できることがわかります。
DALインタフェースの定義
データベースアクセス層で契約を提供するために、私たちはSpring Dataの組み込みメソッドと同様に動作するインターフェースを定義して始めます。
package com.scdev.bootifulmongodb.dal;
import java.util.List;
import com.scdev.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.scdev.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.scdev.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.";
}
}
}
上記のクラスのメソッド実装は、MongoTemplateの依存関係を使用しています。getUserById(…)メソッドがユーザーを取得する方法を見てみましょう。クエリを構築し、必要なパラメーターを渡しました。さらに興味深いのは、getUserSettingクエリです。上記で何が起こったのかを理解しましょう。
- We constructed queries with criteria to check equality.
- The include method includes the field names which the result should include when it is extracted from DB. This means, in this case, userSettings key will be extracted which will save a lot of data to be fetched which is not needed
- Also, we queried upon both user and the map key. Id any of it isn’t found, we return empty data meaning the required key wasn’t found. This saves from even fetching the User object at all if the required key was not present
Spring Data MongoDBのテストラン
単一のコマンドを使用するだけで、このアプリを簡単に実行することができます。
mvn spring-boot:run
アプリが実行されている状態で、このAPIを使用して新しいユーザーを保存することができます。
https://localhost:8102/user/create
このリクエストはPOSTメソッドを使用するため、JSONデータも送信します。
{
"name" : "Shubham",
"userSettings" : {
"bike" : "pulsar"
}
}
モンゴレスポンス自体を返すため、以下のようなものが得られます。
{
"userId": "5a5f28cc3178058b0fafe1dd",
"name": "Shubham",
"creationDate": 1516165830856,
"userSettings": {
"bike" : "pulsar"
}
}
https://localhost:8102/user/
私たちは何かを受け取ることになります。
[
{
"userId": "5a5f28cc3178058b0fafe1dd",
"name": "Shubham",
"creationDate": 1516165830856,
"userSettings": {
"bike" : "pulsar"
}
}
]
//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);
}
MongoTemplateとMongoRepositoryの比較
- MongoTemplate provides a lot more control when it comes to querying data and what data to pull from database.
- Spring Data repositories provide us a convenient outlook on how to fetch data.
- MongoTemplate is database dependent. What this means is, with Spring Data repositories, you can easily switch to a different database altogether by simply using a different Spring Data repositories for MySQL or Neo4J or anything else. This is not possible with MongoTemplate.
春のブートMongoDB概要
このレッスンでは、MongoTemplateがSpring Dataリポジトリよりもコントロールが多くなる一方で、より深いクエリが含まれる場合には少し複雑になることを見てきました。したがって、アイデアを開発する際には完全にあなたの判断に委ねられます。以下のリンクからソースコードをダウンロードしてください。提供されたアプリを実行する前に、MongoDBの認証情報を変更することを忘れずにしてください。
スプリングブートMongoDBのサンプルプロジェクトをダウンロードしてください。