5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

SpringBootでMongoDBを使用する

Last updated at Posted at 2022-12-21

自社でMongoDB,SpringBootを扱う機会があり、勉強のために簡単なデモコードを作成しました。
自社のメインサーバーはフレームワークを用いておらず、社内でフレームワークを用いたコードとの比較を行うための資料として作成しています。
SpringBootでMongoDBを扱う雰囲気が伝わればと思います。

まず、アプリケーションの起動時に呼ばれるApplicationクラスです。

@SpringBootApplication
@EnableMongoRepositories
class MyApplication @Autowired constructor(val groceryItemsDao: GroceryItemsDao, val usersDao: UsersDao): CommandLineRunner {

	companion object {
		@JvmStatic
		fun main(args: Array<String>) {
			runApplication<MyApplication>(*args)
		}
	}
	override fun run(vararg args: String?) {
		groceryItemsDao.insertItem(GroceryItem("Whole Wheat Biscuit", "Whole Wheat Biscuit", 5, "snacks"))
        usersDao.insertUser(User("Suzuki"))
	}
}

SpringBootにはDI機能が備わっており、以下のようなinterfaceを宣言し、そのinterfaceを実装したクラスを自動的にinjectすることができます。

  • interfaceで使いたい関数を宣言する
interface GroceryItemsDao {

    fun findItemByName(name: String): GroceryItem?

    fun insertItem(groceryItem: GroceryItem)
}
interface UsersDao {
    fun insertUser(user: User)
}
  • 上のinterfaceを実装したクラスがフレームワーク側で自動的にinsertされる
@Component
class GroceryItemsDaoImpl @Autowired constructor(
    @Qualifier("myGroceryListTemplate")
    val template: MongoTemplate,
): GroceryItemsDao {

    private val model = GroceryItem::class.java

    override fun findItemByName(name: String): GroceryItem? {
        val query = Query(Criteria.where(GroceryItem.KEY.NAME).`is`(name))
        return template.find(query, model).first()
    }

    override fun insertItem(groceryItem: GroceryItem) {
        try {
            template.insert(groceryItem)
        } catch (me: MongoException) {
            println("Unable to insert due to an error: $me")
        }
    }
}
@Component
class UsersDaoImpl @Autowired constructor(@Qualifier("userTemplate") val template: MongoTemplate): UsersDao {
    private val model = User::class.java
    override fun insertUser(user: User) {
        template.insert(user)
    }
}

今回はGroceryItemsDaoとUsersDaoは異なるデータベースに属するコレクションのDaoにしました。
複数のDatabaseへの接続は以下のようなConfigクラスを作成します。

@Configuration
class MongoConfig( @Value("\${spring.data.mongodb.uri}") private val connectionString: String) {

    @Bean
    fun mongoClient(): MongoClient {
        val connectionString = ConnectionString(connectionString)
        val settings = MongoClientSettings.builder().applyConnectionString(connectionString)
                .serverApi(ServerApi.builder().version(ServerApiVersion.V1).build()).build()
        return MongoClients.create(settings)
    }

    @Bean
    fun userTemplate(): MongoTemplate {
        return MongoTemplate(mongoClient(), "user")
    }

    @Bean
    fun myGroceryListTemplate(): MongoTemplate {
        return MongoTemplate(mongoClient(), "grocery")
    }
}
application.properties
spring.data.mongodb.uri=mongodb+srv://admin:☓☓☓☓☓☓☓☓@cluster0.☓☓☓☓☓☓.mongodb.net/?retryWrites=true&w=majority
spring.autoconfigure.exclude= org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration

これでuserTemplate()は「user」データベースの操作を行うTemplateを提供し、myGroceryListTemplate()は「grocery」データベースの操作を行うTemplateを提供します。
どのコレクションに対してのDaoなのかはModelクラスに記述します。

@Document("groceryItem")
data class GroceryItem(
    val title: String,
    val name: String,
    val quantity: Int,
    val category: String?,
    @Id
    val id: ObjectId = ObjectId()
) {
    object KEY {
        val ID = GroceryItem::id.name
        val TITLE = GroceryItem::title.name
        val NAME = GroceryItem::name.name
        val QUANTITY = GroceryItem::quantity.name
        val CATEGORY = GroceryItem::category.name
    }
}
@Document("user")
data class User(
    val name: String,
    @Id
    val id: ObjectId = ObjectId(),
) {
    object KEY {
        val ID = User::id.name
        val NAME = User::name.name
    }
}

RestAPIを作成するときは以下のように記述して作成します

@RestController
@RequestMapping("/user")
class UserController @Autowired constructor(val usersDao: UsersDao) {
    @PostMapping("/insert")
    fun insertUser(@RequestBody user: User) {
        usersDao.insertUser(user)
    }
}

アノテーションやDI機能を用いて簡潔にサーバーを作成できることがわかりました。

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?