상세 컨텐츠

본문 제목

[Spring] Spring, MongoDB 연동 (Spring Data MongoDB)

PROGRAMMING/Backend

by koharin 2022. 1. 20. 23:34

본문

728x90
반응형

MongoDB 설치


MongoDB Community Download

  • Spring Data for MongoDB를 사용하지만, 로컬에 Mo ngoDB 설치해야 CRUD 가능
  • msi 실행해서 설치하면 mongodb 사용 가능
  • MongoDB Installation

  • mongo.exe : MongoDB Client - MongoDB Shell
  • mongod.exe : MongoDB Server

 

mongo.exe 실행 : MongoDB Shell 실행

  • 디폴트로 localhost의 27017 포트를 사용한다.
  • mongo 를 실행하는 것은 mongo “mongodb://localhost:27017”과 동일하다.
  • 다른 포트에서 MongoDB instance를 실행하려면 mongo “mongodb://localhost:28015” 또는 mongo —port 28015과 같이 사용하면 된다.

이대로 설치만 하면 별도로 mongodb를 실행하지 않아도 사용하는 database를 삭제하지 않으면 데이터가 제대로 들어간다.

 

 

XML Configuration


servlet-context.xml

<mongo:mongo-client id="mongoClient" host="localhost" port="27017"/>
<mongo:db-factory id="mongoDbFactory" dbname="blood" mongo-client-ref="mongoClient"/>
  • Mongo instance 생성하기 위한 factory bean 정의
  • dbname을 꼭 줘야 해당 database 내 collection에 데이터가 제대로 들어간다.
<beans:bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
        <beans:constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
    </beans:bean>
  • template bean 정의
<beans:bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
  • @Repository annotation이 붙은 클래스에서 throw한 MongoExceptions을 해석할 post 프로세서 정의
<mongo:repositories base-package="org.smu.blood.database" mongo-template-ref="mongoTemplate"/>

 

 

Java Configuration


package org.smu.blood;

import java.util.Collection;
import java.util.Collections;

import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.config.AbstractMongoClientConfiguration;

import com.mongodb.ConnectionString;
import com.mongodb.MongoClientSettings;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;

@Configuration
public class MongoConfig extends AbstractMongoClientConfiguration{

    @Override
    protected String getDatabaseName() {
        // TODO Auto-generated method stub
        return null;
    }

    public MongoClient mongoClient() {
        ConnectionString connectionString = new ConnectionString("mongodb://localhost:27017/blood");
        MongoClientSettings mongoClientSettings = MongoClientSettings.builder().applyConnectionString(connectionString).build();
        return MongoClients.create(mongoClientSettings);
    }
    public Collection getMappingBasePackages() {
        return Collections.singleton("org.smu.blood");
    }
}
  • AbstractMongoClientConfiguration에 MongoTemplate이 정의되어 있기 때문에 XML configuration에 MongoTemplate bean 정의가 필요없다.
  • AbstractMongoClientConfiguration을 상속받지 않는 configuration도 작성 가능
@EnableMongoRepositories(basePackages = "com.baeldung.repository")

Spring Project에는 XML Configuration이나 Java Configuration 둘 중 하나만 넣어주면 된다.

 

 

pom.xml 수정

  • Spring Project 생성된 상태
  • Spring Framework version: 5.3.15
    <properties>
        <java-version>1.8</java-version>
        <org.springframework-version>5.3.15</org.springframework-version>
        <org.aspectj-version>1.6.10</org.aspectj-version>
        <org.slf4j-version>1.6.6</org.slf4j-version>
    </properties>
    [...]
    <dependencies>
        [...]
        <!-- Spring Data MongoDB -->
        <dependency>
            <groupId>org.springframework.data</groupId> 
            <artifactId>spring-data-mongodb</artifactId> 
            <version>3.3.1</version>
        </dependency>    
    </dependencies>
<!-- MongoDB Java Driver -->
        <dependency>
            <groupId>org.mongodb</groupId> 
            <artifactId>mongodb-driver-sync</artifactId> 
            <version>4.4.0</version>
        </dependency>    
    </dependencies>
  • <dependencies> 요소와 레벨이 같은 Spring Milestone repository for Maven 추가

사용 가능한 mongodb-driver-sync 버전 확인

공식 문서 상에는 mongodb-driver-core가 필수인데 해당 dependency를 사용하면 MongoClient에서 오류가 발생해서 구글링으로 mongodb-driver-sync를 사용하라는 글을 보고 해당 artifact로 변경했더니 오류가 해결되었다.

 

 

XML Schema to Configure MongoDB


<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mongo="http://www.springframework.org/schema/data/mongo"
    xsi:schemaLocation="
        http://www.springframework.org/schema/data/mongo 
        https://www.springframework.org/schema/data/mongo/spring-mongo.xsd
        http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->

    <!-- Enables the Spring MVC @Controller programming model -->
    <annotation-driven />

    <!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
    <resources mapping="/resources/**" location="/resources/" />

    <!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
    <beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <beans:property name="prefix" value="/WEB-INF/views/" />
        <beans:property name="suffix" value=".jsp" />
    </beans:bean>

    <context:component-scan base-package="org.smu.blood">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
    </context:component-scan>

    <!-- Default bean name is 'mongo' -->
    <mongo:mongo-client host="localhost" port="27017"/>


</beans:beans>
  • bean의 xlms 네임스페이스와 schemaLocation 추가
  • @Repository annotation 붙은 repository를 bean에 자동으로 추가하는 코드 추가
  • <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>

 

 

MongoDB 연동 테스트


  • spring과 android 연동하기 전, spring에서 구현한 api로 mongodb 데이터베이스에 쿼리가 제대로 처리되어 데이터가 들어가는지 확인하기 위한 과정이다.
  • src/main/java/org/smu/blood 경로에 database 폴더 생성

Spring 프로젝트 폴더 구조

 

servlet-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mongo="http://www.springframework.org/schema/data/mongo"
    xsi:schemaLocation="
        http://www.springframework.org/schema/data/mongo 
        https://www.springframework.org/schema/data/mongo/spring-mongo.xsd
        http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->

    <!-- Enables the Spring MVC @Controller programming model -->
    <annotation-driven />

    <!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
    <resources mapping="/resources/**" location="/resources/" />

    <!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
    <beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <beans:property name="prefix" value="/WEB-INF/views/" />
        <beans:property name="suffix" value=".jsp" />
    </beans:bean>

    <context:component-scan base-package="org.smu.blood">
        <!--  <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>  -->
    </context:component-scan>

    <!-- Default bean name is 'mongo' -->
  <mongo:mongo-client host="localhost" port="27017"/>
     <mongo:db-factory id="mongoDbFactory"/>
    <beans:bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
        <beans:constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
    </beans:bean>

</beans:beans>
  • MongoTemplate 사용 위해 bean에 추가

 

User 객체 생성

package org.smu.blood.database;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

/*
 * Spring Data MongoDB에서 User 클래스를 자동으로 User 이름의 collection에 매핑해서 
 * @Document annotation 사용하지 않아도 상관없음. 
 */
@Document(collection="User")
public class User {
    @Id
    private String userId; // _id로 지정
    private String password;
    private String nickname;

    public User() {}

    public User(String userId, String password, String nickname) {
        this.userId = userId;
        this.password = password;
        this.nickname = nickname;
    }
    public String getuserId() {
        return userId;
    }
    public String getpassword() {
        return password;
    }
    public String getnickname() {
        return nickname;
    }
    public String toString() {
        return String.format("User[userId:%s, password: %s, nickname: %s]", userId, password, nickname);
    }
}
  • database 폴더에 User.java 생성해서 User 클래스를 만든다.
  • User 클래스에는 userId, password, nickname, bloodType, rhType의 5가지 속성을 가진다. Id annotation은 MongoDB ID 기본 이름이다.
  • toString() 메소드는 User 정보를 출력한다.
  • MongoDB는 데이터를 collection에 저장한다. Spring Data MongoDB는 User 클래스를 User 이름의 collection에 매핑한다. 만약 collection 이름을 변경하고 싶으면, Spring Data MongoDB의 @Document annotation을 클래스에서 사용한다.

 

UserRepository 생성

package org.smu.blood.database;

import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface UserRepository extends MongoRepository<User, String>{
    // query User
    // userId는 unique한 _id(primary key)이기 때문에 userId로만 특정 User 검색 가능
    @Autowired
    public User findByUserId(String userId);
}
  • UserRepository는 MongoRepository를 상속받는 인터페이스
  • 해당 인터페이스에는 CRUD(Create, Read, Update, Delete) 연산과 같은 많은 연산을 구현할 수 있다.
  • 쿼리는 메소드 형태로 정의한다.
  • findByUserId 메소드: User 타입의 document에서 userId와 매치되는 document 찾는 쿼리
  • findByNickname 메소드: 해당 nickname 가지는 리스트 찾는 쿼리

 

UserController 생성

package org.smu.blood;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletRequest;
import org.smu.blood.database.UserRepository;
import org.smu.blood.database.User;
import static org.springframework.data.mongodb.core.query.Query.query;
import static org.springframework.data.mongodb.core.query.Criteria.where;

@Controller
public class UserController {

    @Autowired
    MongoTemplate mongoTemplate;

    @RequestMapping(value="/signIn")
    public String post(@RequestParam("userId") String userId, @RequestParam("password") String password, @RequestParam("nickname") String nickname, Model model) {
        User user = new User(userId, password, nickname);
        model.addAttribute("user", user);
        return "viewPage";
    }

    @RequestMapping(value="/goBack")
    public String goBack() {
        return "home";
    }

    @RequestMapping(value="/save")
    public String save(@ModelAttribute("user") User user, Model model) {
        mongoTemplate.insert(user, "User");
        User findUser = mongoTemplate.findOne(query(where("userId").is(user.getuserId())), User.class);
        model.addAttribute("finduser", findUser);
        return "save";
    }

}

 

viewPage.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> 
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
Welcome, ${user.nickname} <br>
userId: ${user.userId} <br>
password: ${user.password} <br>
nickname: ${user.nickname} <br> 
<a href="save">save</a>
</body>
</html>

 

save.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
saved. <br>
user id : ${finduser.userId } <br>
password : ${finduser.password } <br>
nickname : ${finduser.nickname } <br>
</body>
</html>

 

 

  • 제출하고 save 후 save.jsp에서 뭔가 보여주는데 제대로 저장이 안 된 것 같다. ObjectId를 가져오는 것 같은데.. ObjectId로 변환돼서 저장된다고 한다.
  • 계속 collection이 생성이 안 됐었는데 mongodb에 save할 때 save(user, “User”) 이 아닌 save(user)로 했기 때문이었다.
  • document를 확인해보면 원하는 field가 저장이 안 됐지만 spring을 통해 mongodb에 collection 및 document를 생성하는 것은 확인이 되었다. 
    • User 객체에서 _id로 사용하려는 필드를 제외하고는 @Indexed annotation을 붙여야 document에 해당 필드들이 제대로 들어간다.

  • collection이 제대로 생성되려면 servlet의 XML 파일에서 <mongo:db-factory id="mongoDbFactory" dbname="blood" mongo-client-ref="mongoClient"/> 에 dbname (현재 datbase 이름)을 제대로 명시해줘야 한다.

 

spring에서 보낸 데이터를 mongodb에 저장하는 것으로 연동이 제대로 되었음을 알 수 있고,

spring과 android를 연동한 이후 mongodb에 원하는 형태로 document에 데이터가 들어가도록 할 예정이다.

728x90
반응형

관련글 더보기