'mongoDB'에 해당되는 글 3건


mongoDB + Spring Data JPA


지난 시간 간단하게 2개의 Collection으로 구성된 mongoDB의 Document 구조를 설계해 보았다.

하지만 많은 시스템이 그렇듯 한 번에 완결이 되는 그런 개발은 없다. 아무리 작은 개인 프로젝트라도…

물론 가능한한 완벽한 설계를 한다면 그 변경의 폭은 줄어들 수 있겠지만 아마도 계획되지 않은 진행을

완전히 막을 수는 없을 것이다.


오늘은 지난 시간에 이어 Collection 중에 Elements Collection을 조금 변경해볼 것이다.


1. 기능 목표


To-Do 기능의 추가 : 가능한한 단순한 시스템을 만들고자 했으나 목표를 정하고 그 목표를 향해

가는 시스템에서 간단하게나마 계획을 하는 부분을 제외하는 것은 무리인 듯했다. 결국 To-Do

기능을 추가하고 그와 관련하여 예정된 작업과 완료된 작업 간의 상태 이동이나 예정된 작업에서

예정일을 변경하는 기능 그리고 그와 관련된 화면 구현 등의 작업이 진행 될 것이다.


2. 기술 목표


이번까지의 목표는 mongoDB에 대해 조금 더 알아가는 것이다. 이번에는 Document 구조를

바꿔가면서 어떤 구조가 back end나 front end에서 데이터를 다루기가 더 쉬운지를 확인해 볼

것이다. 하지만 mongoDB에 대한 좀 더 심화된 내용은 없을 것이다. 아울러 데이터 처리를 위해

Spring Data JPA의 query method를 사용하는 법을 간단하게 알아볼 것이다.


3. 기술 적용 내용


mongoDB


우선 지난 포스팅에서 설계를 마쳤던 2개의 Collection 중 Profile Collection은 이름을 Profile

AndGoal로 바꾸었고 그 구조적으로는 기본 계정을 제외한 몇개의 항목을 profile이라는 이름의

Sub Document로 만들기로 했다. 우선 지난 시간 만들었던 ProfileAndGoal Collection의

Document 구조를 한 번 보자


ProfileAndGoal Collection


{

    "_id" : ObjectId("584ff54a4fe35068dc44bab4"),

    "_class" : "com.mazdah.tillsixty.account.domain.Profile",

    "name" : "우형준",

    "userId" : "mazdah",

    "password" : "w00hj8928",

    "email" : "woohj70@gmail.com",

    "facebook" : "100000967897658",

    "twitter" : "@mazdah70",

    "link" : "http://mazdah.tistory.com",

    "introduction" : "평범한 아들. 평범한 남자. 평범한 가장. 평범한 개발자. 평범한 서민. 하지만 그 '평범'이 

    너무도 싫은 한 사람",

    "goalList" : [ 

        {

            "goalId" : "584ff54a4fe35068dc44bab4_1",

            "goalTitle" : "Project Master 개발",

            "startDate" : "2016-12-13",

            "endDate" : "2017-12-31",

            "goalDescription" : "관리자와 개발자 모두 쉽게 사용할 수 있는 프로젝트 관리 툴 개발\n

  프로젝트 진행 과정을 쉽게 시각화 문서화하여 진행 상태를 직관적으로\n

  확인할 수 있도록 개발",

           "goalStatus" : "O",

           "createDate" : "2016-12-13"

        }

    ]

}


위 Document 중 email, facebook, twitter, link, imgPath, introduction 등 6개의 항목을 

Sub Document로 만들기로 하여 다음과 같은 구조로 변경하였다.


{

    "_id" : ObjectId("587e18514216afd4103453c2"),

    "_class" : "com.mazdah.tillsixty.account.domain.User",

    "name" : "우형준",

    "userId" : "mazdah",

    "password" : "w00hj8928",

    "profile" : {

        "facebook" : "100000967897658",

        "twitter" : "@mazdah",

        "link" : "http://mazdah.tistory.com",

        "introduction" : "평범한 아들. \n평범한 남자. \n평범한 가장. \n평범한 개발자. \N

    평범한 서민. \n하지만 그 '평범'이 너무도 싫은 한 사람"

    },

    "goalList" : [ 

        {

            "goalId" : "587e18514216afd4103453c2_1",

            "goalTitle" : "AI 전문가 되기",

            "startDate" : "2017-01-17",

            "endDate" : "2017-12-31",

            "goalDescription" : "TensorFolw를 시작으로 머신 러닝과 딥 러닝을 학습하여 인공 지능 

  분야의\n전문가가 될 수 있도록 함",

            "goalStatus" : "O",

            "createDate" : "2017-01-17"

        }

    ]

}


사실 사용자 계정과 Profile 정보는 명백하게 1:1의 관계이고 크게 변동이 있을만한 정보들이

아니기 때문에 굳이 Sub Document로 만들이 않아도 되었을 것이다. 하지만 분명 기본 

계정 정보와는 성격이 다른 정보들이고 추후 항목이 추가될 수도 있으며 RDBMS로의 전환을

고려한다면 일단 구조적으로도 분리시켜 놓는 것이 좋을 것이라는 판단이다.


정작 많은 고려를 해야 하는 것은 Elements쪽이었다. To-Do 기능을 추가함에 따라 하나의

Element가 상태가 변할 수도 있고 그에 따라 몇몇 정보도 같이 변화하기 때문에 이에 맞는

구조를 찾아야 하는 것이다. 그리고 그 과정에서 mongoDB의 제약 사항인 join과 transa-

ction에 대한 고려를 함께 해야 한다. 이러한 고려사항 때문에 2차례의 수정을 거쳐 마지막

구조를 만들었는데 아무래도 한 번 더 수정을 해야 할 것 같다.


처음에는 RDBMS 모델링을 하던 습관 때문인지 Element의 상태를 Sub Document로

만들었다. 구조는 다음과 같다


Elements Collection


{

    "_id" : ObjectId("58515bb94fe35068dc44bac3"),

    "_class" : "com.mazdah.tillsixty.goal.domain.Elements",

    "userId" : "584ff54a4fe35068dc44bab4",

    "goalId" : "584ff54a4fe35068dc44bab4_1",

    "elementType" : "A",

    "title" : "메인화면 구현",

    "description" : "Parallax 스타일의 메인화면 구현",

    "createDate" : "2016-12-14”,

“statusList” : [

{

“status” : “예정”,

“dueDate” : “2017-01-31”

},

{

“status” : “지연”,

“dueDate” : “2017-02-05”

},

{

“status” : “완료”,

“dueDate” : “2017-01-31”

}

]

}


이 경우 statusList를 통한 조회가 번거로워지기도 하고 또 상태 중 완료에 대한

처리가 모호해진다. 상태는 완료인데 날짜 필드를 dueDate라고 하기에도 뭔가

매칭이 안되고 그렇다고 완료의 경우에는 endDate라는 필드명을 쓰거나 아니면

endDate라는 필드를 추가하는 것도 데이터 구조의 일관성이 떨어지는 것 같다.


그래서 다시 다음과 같이 바꾸었다.


{

    "_id" : ObjectId("587e1e2b4216afd4103453c8"),

    "_class" : "com.mazdah.tillsixty.elements.domain.Elements",

    "userId" : "587e18514216afd4103453c2",

    "goalId" : "587e18514216afd4103453c2_1",

    "elementId" : NumberLong(1484660267204),

    "elementType" : "A",

    "title" : "Action ToDo 등록 테스트 2",

    "description" : "공공 데이터 중 선형회귀 분석으로 분석 가능한 데이터 구하기",

    "createDate" : "2017-01-17",

    "dueDateList" : [ 

        "2017-02-04", 

        "2017-01-31", 

        "2017-02-10"

    ],

    "endDate" : "2017-01-19",

    "status" : "완료"

}

간단해진 것은 좋으니 이 구조는 상태 이력을 파악하기가 쉽지 않다…ㅠ.ㅠ 즉, Timeline

처리가 어려워진다는 말이다. 결국은 상태가 바뀔 때마다 새로운 Document를 생성하고

같은 Element에 대해 상태별로 생성된 Document들은 group Id로 묶는 것으로 다시 

구조를 바꾸어야 할 것 같다.


중요한 것은 이렇게 Document를 바꿔나가는 동안 mongoDB쪽에는 한 일이 없다는

것이다. 이전 구조의 데이터를 삭제한 것 외에는 다른 어떤 작업도 필요 없었다. 바로

schemeless의 위력을 실감한 것이다. 하지만 바뀐 구조에 대한 프로그램 내에서의 

처리를 고려한다면 전체적인 의미에서의 작업이 단순해진 것은 아니다. 다만 DB쪽

작업이 개발쪽으로 옮겨왔을 뿐…ㅠ.ㅠ 그래도 역시 mongoDB 설계의 유연함은

상당히 만족스럽다.


Spring DATA REST


Document 구조가 바뀜에 따라 가장 크게 영향을 받는 것이 바로 REST API의 변경이

아닐까 싶다. 하지만 아직은 너무나 단순한 DB를 구현하고 있기 때문에 가장 기본적인

Query Method만으로도 충분히 처리가 가능하였다. 우선 Spring DATA REST에서

제공하는 keyword를 method 이름에 사용함으로써 웬만한 query는 다 처리가 되었다.

예를 들어 아래와 같은 REST 호출을 보자

“/rest/elements/search/findByUserIdAndGoalIdAndStatusInOrderByCreateDateAsc?” +

“UserId=” + userId + “&goalId=” + goalId + “&status=예정&status=연기


엄청 긴 API가 보인다. “findByUserIdAndGoalIdAndStatusInOrderByCreateDateAsc”

이름 만으로도 아마 충분히 짐작을 할 것이다. 이 API를 SQL Query로 바꾸면 다음과 같다.


select * from [TABLE]

where userId = [userId]

and goalId = [goalId]

and status in ([status1], [status2])

order by createDate asc


특별히 테이블 간의 join이 필요 없다면 이렇게 method이름만으로 대부분 처리가 가능하다.

mongoDB의 경우 join이 없다고 봐도 무방하므로 사용하기가 아주 편해진다.

Query method에 사용 가능한 keyword의 목록은 아래 문서에 자세히 정리되어있다.

문서에서 “Supported keywords inside method names”로 검색을 하면 keywords

테아블에서 확인 가능하다.


4. 참조 (site 또는 서적)


Spring Data JPA : http://docs.spring.io/spring-data/data-jpa/docs/current/reference/html/#repositories.single-repository-behaviour 


5. 확인 사항 (의문 사항)


지난 시간에 목표했던 내용을 아직 확인 못했다. mongoDB에서의 트랜잭션 처리와 관련하여 

$isolated라는 연산자 확인이 필요하다.


6. 평가


애초에 DB에 대한 지식이 부족한 상태이다보니 모델링 작업은 쉽지 않았다. 나름대로 여기저기서

지식을 빌어다가 모델링을 해보기는 하였지만 아직도 완성된 모습은 아니다. 이렇게 간단한 시스템

개발에도 이럴진대…ㅠ.ㅠ 마음을 비우고 공부에 전념해야겠다.


일단 Till60의 기본적인 기능은 어느정도 구현되었으니 차주부터는 js쪽 소스들에 대해 React를

적용하는 작업을 본격적으로 시작해볼 예정이다. 조급해하지 말고 한발 한발 나가보자!

블로그 이미지

마즈다

이제 반백이 되었지만 아직도 꿈을 좇고 있습니다. 그래서 그 꿈에 다가가기 위한 단편들을 하나 둘 씩 모아가고 있지요. 이 곳에 그 단편들이 모일 겁니다...^^

댓글을 달아 주세요



mongoDB 모델링을 해보자


처음 시작할 무렵의 글들에도 언급을 했지만 내가 지금 가지고 있는 지식이라고는 “몽고 디비 

완벽 가이드”라는 책 한권 읽은 것이 전부이다. 그마저도 변변한 선행 지식이 없이 읽었던 터라 

지금 기억나는 부분은 거의 없다시피 하다.


그나마 다행인 것은 내가 지금 하고자 하는 것이 mongoDB은 전반적인 내용을 알고자 하는 것이 

아니라 응용 프로그램을 위한 데이터 모델을 설계하고자 하는 것이기에 부담이 좀 덜하다는 것 

정도?


물론 읽기와 쓰기의 빈도를 고려하고 한 번에 저장할 수 있는 Document의 최대치라든지 성능을 

위한 정규와화 비정규화의 적절한 선택 등을 생각해보면 그래도 알아야 할 것들이 상당히 많다. 

그래서 조금이라도 그런 부담을 줄이기 위해 최대한 데이터 볼륨을 작게 하려고 한다(물론 

나중에는 점점 확장이 될 것이고 그 확장되는 부분도 고려해야 할 문제이긴 하다).


1. 기능 목표


전체 메뉴에 대해 Spring Rest API를 통해 mongoDB에 데이터의 CRUD 처리를 하는 

        기능을 구현한다. 대상이 되는 기능은 지난 주 작업했던 Sign-up을 제외하고 Login, 

        목표 등록, 목표 수정, 요소 등록, 상세 프로필 등록, 상세 프로필 수정 등이다.


2. 기술 목표


서두에 적었듯이 오늘은 mongoDB의 데이터 모델링을 해볼 예정이다. 이미 알고있는 바와 

        같이 mongoDB는 Document DB로 분류되어 JSON과 거의 동일한 형식으로 데이터가 저장

        되며 스키마가 없는 DB로 데이터 설계에 있어서 비교적 자유롭다는 장점이 있다. 더불어 

        mongoDB는 중첩된 Object를 가진 데이터 설계가 가능하다는 부분도 장점이다. 가능하면 

        이러한 mongoDB의 장점을 활용하는 선에서 단순하게 설계를 해보고자 한다.


3. 기술 적용 내용


본론에 들어가기 전에 먼저 mongoDB의 모델링 가이드에 대해 간단하게 살펴보고 시작

        하도록 하자.


일단 기존 RDBMS와의 용어상 차이를 보면 RDBMS의 Table은 Collection으로 Row는

        Document로 Column은 Field로 불린다. 앞서 언급한 것처럼 미리 데이터 구조를 정해놓고 

       그 구조에 맞는 데이터만 다룰 수 있는 RDBMS와는 달리 mongoDB는 매우 유연하게 

       데이터 구조를 사용할 수 있다. 심지어는 같은 Collection안에 전혀 다른 구조의 

       Document를 넣는 것도 가능하다. 그러나 당연한 얘기겠지만 같은 Collection에는 유사한 

       Document를 다루도록 하는 것이 관리상 편하다.


RDBMS는 그 이름에서도 알 수 있듯이 Table간의 관계가 매우 중요하다. RDBMS만큼은 

       아니지만 MongoDB에서도 Collection간의 관계를 적절하게 구성을 해야 성능상의 이점을 

       누릴 수가 있다. 


       이 때 중요하게 고려해야 할 것이 바로 “쓰기 작업에서의 원자성(Atomicity of 

          Write Operations)”이다. 조금 더 이해하기 쉽게 표현하자면 mongoDB는 한 번에 하나의 

       Document 또는 Collection에서만 쓰기 작업이 가능하다는 것이다. 즉, transaction이라는 

       것을 지원하지 않는다. 바로 이런 측면이 설계 상의 중요한 고려 사항이 될 것이다.


mongoDB 모델링은 크게 2가지 구조로 나눌 수 있는데 references와 embedded이다. 각각

다음과 같이 설명할 수 있다.


  • References : RDBMS의 정규화와 같은 개념으로 볼 수 있으며 Document를 다른 Collection에               배치하여 서로 참조하도록 구성하는 개념이다.


  • Embedded : 연관성이 있는 Document를 다른 Collection에 배치하지 않고 Document 내에 Sub Document로 배치하는 방법이다.




보다 자세한 내용은 공식 사이트의 문서를 참조하도록 하고 일단 이런 기본적인 사항만을 

        고려하여 Till60의 데이터 모델링을 진행해보도록 하자.


우선 RDBMS를 기준으로 Till60에 필요한 Table을 생각해보자. 아마도 아래 정도의 

        구성이 나올 것이다(컬럼은 Till60에 필요한 것 기준이다).


  • 사용자 기본 정보 (rowid, 이름, 사용자 ID, 비밀번호, 이메일 주소 등)
  • 사용자 부가 정보 (사용자 기본 정보의 rowid, 프로필 사진, SNS 계정 등)
  • 목표 정보 (사용자 기본 정보의 rowid, rowid, 목표 제목, 목표 설명, 시작일, 종료일, 목표 상태 등)
  • 요소 정보 (목표 정보의 rowid, 요소 rowid, 요소 제목, 요소 타입, 요소 설명 등)


이 내용을 기준으로 mongoDB에서의 Collection을 다음과 같이 구성해보았다.


  • 계정을 포함한 사용자 정보를 저장할 Profile Collection
  • 목표를 구성하는 각 요소를 저장할 Elements Collection


4개의 테이블을 2개의 Collection으로 바꾸었다. 이렇게 한 이유는 다음과 같다.


사용자 기본 정보와 사용자 부가 정보는 기본적으로 1 : 1의 관계이므로 사용자 부가 

        정보는 사용자 기본 정보의 Sub Document로 하여 같은 Profile Collection에 배치 하였다

(하지만 현재 상태로는 Sub Document가 아닌 같은 레벨의 field로 사용하고 있다).


다음으로 목표 정보는 사용자 정보와는 기본적으로 1 : N의 관계이다. 사실 Till60 개발

초반에는 “선택과 집중”이라는 모토 아래 사용자 1명 당 1개의 목표만을 설정할 수 

        있도록 구상을 했지만 그렇게 되면 아무리 장기 프로젝트를 위한 시스템이라지만 한 번 

        쓰고 버리는 시스템이 될 것이기에 생각을 좀 바꾸었다(하지만 아직까지는 사용자 1명 당 

        1개의 목표만을 생성할 수 있다). 이 경우 비록 1 : N이기는 하지만 N에 해당하는 목표가 

        얼마나 많이 생성 될 것인지를 생각해보면 그리 많을 것 같지는 않다. 아주 여유있게 

        예상하여 한 명의 사용가 이 시스템을 20년 정도 사용을 하고 그 기간 동안 6개월 짜리 

        목표를 꾸준히 만든다고 해도 목표는 120개 정도. 목표 자체의 정보 량이 많지 않기 

        때문에 한번에 불러오거나 메모리에 로드되기에 부담되는 양은 아니다. 이런 이유로 목표 

        정보 역시 사용자 정보의 Sub Document로 Profile Collection에 함께 배치하기로 하였다.


결국 사용자 정보, 사용자 부가정보, 목표 정보 3개의 정보가 하나의 Document로 동일한

Profile Collection에 배치되었다. 그리고 요소 정보의 경우 목표 정보와 1 : N의 관계에 

        있지만 그 증가량이 목표 정보에 비하면 상당히 많은 수이기 때문에 목표 정보에 

        embedded로 배치하기가 어렵다고 판단되어 references로 처리하여 별도의 Collection에 

        배치하게 된 것이다.


이렇게 구성된 데이터 구조를 보면 다음과 같다(앞서 말한 것과 같이 사용자 부가 정보는 

        아직 별도의 Sub Document로 분리하지 않았다).


Profile Collection


{

    "_id" : ObjectId("584ff54a4fe35068dc44bab4"),

    "_class" : "com.mazdah.tillsixty.account.domain.Profile",

    "name" : "우형준",

    "userId" : "mazdah",

    "password" : "w00hj8928",

    "email" : "woohj70@gmail.com",

    "facebook" : "100000967897658",

    "twitter" : "@mazdah70",

    "link" : "http://mazdah.tistory.com",

    "introduction" : "평범한 아들. 평범한 남자. 평범한 가장. 평범한 개발자. 평범한 서민. 하지만 그 

                                   '평범'이 너무도 싫은 한 사람",

    "goalList" : [ 

        {

            "goalId" : "584ff54a4fe35068dc44bab4_1",

            "goalTitle" : "Project Master 개발",

            "startDate" : "2016-12-13",

            "endDate" : "2017-12-31",

            "goalDescription" : "관리자와 개발자 모두 쉽게 사용할 수 있는 프로젝트 관리 툴 개발\n

                                                      프로젝트 진행 과정을 쉽게 시각화 문서화하여 진행 상태를 직관적으로

                                                      \n확인할 수 있도록 개발",

           "goalStatus" : "O",

           "createDate" : "2016-12-13"

        }

    ]

}


Elements Collection


{

    "_id" : ObjectId("58515bb94fe35068dc44bac3"),

    "_class" : "com.mazdah.tillsixty.goal.domain.Elements",

    "userId" : "584ff54a4fe35068dc44bab4",

    "goalId" : "584ff54a4fe35068dc44bab4_1",

    "elementType" : "A",

    "title" : "메인화면 구현",

    "description" : "Parallax 스타일의 메인화면 구현",

    "createDate" : "2016-12-14"

}


아직은 개발이 진행 단계이고 변경될 여지가 많이 남아있다. 당장에 현재 화면에서는 각 

        요소별 카운트가 표시되는데 많은 수의 요소가 누적된 경우 전체 카운트를 하는 것 보다 

        Profile Collection의 Sub Document의 목표 정보에 각 요소의 전체 수를 포함시키는 것이 

        어떨까 싶다. 다만 이럴 경우 트랜잭션 처리가 필요하기 때문에 아직은 고민 중이다.


어쨌든 이번 주에는 가장 기본적인 정보만을 가지고 Till60의 데이터를 모델링 해보았다.

하지만 여전히 아직 고려되지 않은 부분들이 많아 앞으로 많은 수정을 거치게 될 것이다.

오늘의 이 글은 그저 mongoDB의 모델링을 맛보기 한데 의의를 두어야 할 것 같다.


4. 참조 (site 또는 서적)


mongoDB 문서 중 모델링에 대한 부분 : 

        https://docs.mongodb.com/manual/core/data-modeling-introduction/


5. 확인 사항 (의문 사항)


mongoDB에서의 트랜잭션 처리와 관련하여 $isolated라는 연산자가 있는데 이를 어떻게 

        사용하는지 공부를 좀 해두어야 겠다.


6. 평가


사실 워낙 작은 규모의 시스템이고 필요한 데이터도 많지 않았기에 가장 기본적인 내용만 

        확인한 후 바로 작업을 진행해보았다. 하지만 앞으로 추가될 정보들(이미지나 동영상 

        등의 미디어 정보)과 성능 또는 기능 상의 문제로 변경될 구조들(요소 count 정보 처리나 

        실제 목표를 다수 등록할 수 있게 한 이후의 처리 등)을 생각해보면 아직도 진행되어야 할 

        내용이 보여진다. 우선은 이 기본 상태에서 UI를 좀 더 손본 후 본격적으로 기능적인 

        부분을 진행해야 겠다.

블로그 이미지

마즈다

이제 반백이 되었지만 아직도 꿈을 좇고 있습니다. 그래서 그 꿈에 다가가기 위한 단편들을 하나 둘 씩 모아가고 있지요. 이 곳에 그 단편들이 모일 겁니다...^^

댓글을 달아 주세요



Spring boot와 mongoDB 연동하기 그리고 REST API


새삼스러운 이야기지만 Spring boot는 프로젝트 구성이 참으로 간편하다.

처음 STS에서 프로젝트 생성 시 Dependencies를 적절하게 선택하면 필요한 모든 라이브러리들이

알아서 착착 들어와주고 우리는 그저 그 라이브러리들을 적절히 사용하기만 하면 된다.


오늘 정리할 Spring boot와 mongoDB의  연동과 이를 테스트하기 위해 필요한 REST API 구현도

마찬가지이다.


그래서 어찌 보면 오늘 내용은 달리 설명할 부분이 없는 것이나 다름 없다.

아무래도 일반적인 지식으로 내용이 채워질 것이다.



1. 기능 목표


이번 주의 목표는 Spring boot와 mongoDB를 연동하여 Sign-up 정보를 mongoDB에

저장하고 이 정보를 이용하여 Login을 하는 것까지 구현을 하게 될 것이다.


2. 기술 목표


Spring boot와 mongoDB의 연동 및 이 과정에서 필요한 Spring boot에서의 REST API

구현에 대해 알아보도록 할 것이다.


3. 기술 적용 내용


  • Spring boot와 mongoDB 연동


Spring boot와 mongoDB의 연동 및 이 과정에서 필요한 Spring boot에서의 REST API

구현에 대해 알아보도록 할 것이다. 


우선 mongoDB는 설치가 된 것을 가정하고 설명을 진행한다. 나같은 경우  OSX에서 brew로

설치를 진행하고 설치 후 변경된 내용은 없다. 즉 가장 기본적인 상태로 설치가 되어있다.

그리고 Till60라는 이름의 DB를 하나 생성하였다. (MomgoDB를 인증모드로 접근하기 위한

설정 작업들이 있기는 하였으나 mongoDB 자체에 대한 설명을 하는 자리가 아니므로

‘4. 참조 (site 또는 서적)’ 항목에 링크로 대신한다.


내용을 단순하게 하기 위해 STS에서 새로 프로젝트를 생성하였다. Spring Starter Project를 

선택하였으며 Dependencies도 단순하게MongoDBWeb만을 선택하였다. 이렇게 생성했을 때 

gradle.build 파일의 dependencies는 다음과 같다.


dependencies {

compile('org.springframework.boot:spring-boot-starter-data-mongodb')

compile('org.springframework.boot:spring-boot-starter-web')

testCompile('org.springframework.boot:spring-boot-starter-test')

}


그리고 application.properties에는 mongoDB 연결을 위한 uri를 다음과 같이 설정하였다.


spring.data.mongodb.uri=mongodb://mazdah:password@localhost:27017/Till60


사실상 설정은 이 것이 다라고 보면 된다.


  • Spring boot REST API 구현


이전의 개인프로젝트나 업무상의 작은 프로젝트에서는 주로 @RestController를 이용하여 REST API를

구현했었다. 그런데 이번에 @RepositoryRestResource라는 annotation을 새롭게 알게 되고 그

간편함에 끌러 사용하게 되었다. 물론 후에 또 어떻게 바뀔지는 모르겠지만…


우선 @RepositoryRestResource는 spring-data-rest-core 라이브러리에 정의되어있으며 이는

Spring Starter Project 생성시  Dependencies에 Rest Repositories를 선택하면 포함된다.


주의 사항

나같은 경우 현재 사무실과 집에서 Git으로 소스를 공유하면서 작업을 하고 있는데 두 곳의 STS 버전이

달라서 그런지 아니면 프로젝트 생성 후 별도로 라이브러리를 추가한 것이 꼬였는지 처음 사무실에서

@RepositoryRestResource를 사용했을 때 브라우저에서 계속 404 에러가 발생을 했다.

확인 결과 필요한 라이브러리 중 spring-data-rest-webmvc가 빠져있어서 발생을 한 문제였다.

기왕에 Spring boot를 사용하기로 했으면 필요한 라이브러리를 일일이 찾아 삽입하기 보다는

 처음 프로젝트 생성시 Dependencies를 잘 설정해주는 것이 불필요한 오류를 막는 지름길 일 것이다.


 

@RepositoryRestResources는 Repositary 인터페이스에 적용을 하게 되며 이렇게 할 경우

별다른 RestController 없이 기본적인 REST API를 자동으로 생성해준다. 이 때 자동으로 생성되는

REST API의 기본 형태는 다음과 같다.


http://domain:port/{domain}

http://domain:port/{domain}/{id}

http://domain:port/{domain}/search

http://domain:port/{domain}/search/{search query}


이 때 domain은 @Entity 또는 @Document 등으로 설정된 Domain 클래스이며 내부적으로

클래스명의 앞부분을 소문자로만든 후 뒤에 s를 붙여 사용하게 된다. 즉, Person이라는 Domain

Class를 만들었다고 한다면 {domain} 위치에는 persons로 표시된다.


{search quesry}에는 Repository 인터페이스에 선언된 쿼리 함수와 그 함수의 파라미터로 전달될

쿼리 문자열이 들어가게 된다. 만일  findByName(@Param(“name”) String name)이라는 

쿼리 함수가 선언되어있다면 {search quesry}는 다음과 같이 표현된다.


findByName?name={name}


Person domain 객체를 이용하여 이름이 “Edison”이라는 사람을 찾는다면 전체 URI는 다음과 같다.


http://domain:port/persons/search/findByName?name=Edison


참고로 URI의 구성에 영향을 미치는 요소가 2가지가 있는데 우선 REST API의 베이스 URI를

Spring boot의 application.properties에 spring.data.rest.base-path라는 항목에 값을

넣으면 된다. 만일 이 값을 api로 지정했다면 위의 URI는 다음과 같이 바뀌게 된다.


http://domain:port/api/persons/search/findByName?name=Edison


그리고 @RepositoryRestResources에 path 요소를 설정하게 되면 앞서 말한 domain 값이

path에 설정한 값으로 바뀌게 된다. 즉, @RepositoryRestResources(path=“user”)로

설정을 하게 되면 위의 URI는 다시 아래와 같이 바뀐다.


http://domain:port/api/user/search/findByName?name=Edison


이렇게 이번 주에는 가장 기본적인 설정을 통해 Spring boot와 mongoDB를 연동하고 

Sign-up과 Login 기능을 구현하게 되었다.


4. 참조 (site 또는 서적)


Spring Rest 참조

http://docs.spring.io/spring-data/rest/docs/current/reference/html/

https://brunch.co.kr/@sbcoba/3


MongoDB 관련 문서

http://blog.nekoromancer.kr/2013/12/16/mongodb-인증모드로-접속하기/

https://docs.mongodb.com/manual/reference/method/db.createUser/#db.createUser


MongoDB 관리 툴

https://docs.mongodb.com/ecosystem/tools/administration-interfaces/

https://www.humongous.io/app/


5. 확인 사항 (의문 사항)


이처음 생성하고 현재 프로젝트를 진행하고 있는 Till60 프로젝트의 경우 Run As > Spring Boot App

하여  서버 기동을 하게 되면 아래와 같은 로그가 계속 표시된다.


23:40:47.916 [cluster-ClusterId{value='584c13e54fe3502b024dca36', description='null'}-localhost:27017] DEBUG org.mongodb.driver.cluster - Checking status of localhost:27017

23:40:47.918 [cluster-ClusterId{value='584c13e54fe3502b024dca36', description='null'}-localhost:27017] DEBUG org.mongodb.driver.cluster - Updating cluster description to  {type=STANDALONE, servers=[{address=localhost:27017, type=STANDALONE, roundTripTime=1.1 ms, state=CONNECTED}]


아마도 클러스터로 구성된 mongoDB의 ping check를 하는 로그인 듯한데 얘가 어디서 출력을 하고

있는 것인지 잘 모르겠다. 로그에 찍힌 패키지명으로 추측컨대 mongo-deriver 또는 mongo-java-

Driver라는 라이브러리에서 찍히는 것 같은데 Referenced Library에는 해당 라이브러리가 포함되어

있지 않다. 아직도 기본 구조를 이해를 못하고 있어 애로 사항이 좀 있다…ㅠ.ㅠ


아마도 클러스터로 구성된 mongoDB의 ping check를 하는 로그인 듯한데 얘가 어디서 출력을 하고

있는 것인지 잘 모르겠다. 로그에 찍힌 패키지명으로 추측컨대 mongo-deriver 또는 mongo-java-

Driver라는 라이브러리에서 찍히는 것 같은데 Referenced Library에는 해당 라이브러리가 포함되어

있지 않다. 아직도 기본 구조를 이해를 못하고 있어 애로 사항이 좀 있다…ㅠ.ㅠ


6. 평가


서두에서도 말했지만 Spring boot는 우선 설정에 큰 신경을 쓰지 않아도 좋기 때문에 작업 시간을

꽤 많이 단축시켜준다. 하지만 그 구조를 이해하지 못하는 경우에는 상당한 혼란도 생길 수 있다.

모든 기술들이 그렇겠지만 우선은 그 기본적인 내용을 이해하고 사용을 해야 겠다는 생각을 새삼

하게 된다.


어쨌든 이번 주에는 어렵지 않게(물론 이해 못하는 부분이 있기는 하지만) mongoDB와 연동을

하여 기본적인 CRUD는 처리할 수 있게 되었다. 더 진도를 나가기 전에 mongoDB 모델링이

필요할 것 같다. 다음 주에는 mongoDB 모델링에 대해서 진행을 해 볼 것이다.

블로그 이미지

마즈다

이제 반백이 되었지만 아직도 꿈을 좇고 있습니다. 그래서 그 꿈에 다가가기 위한 단편들을 하나 둘 씩 모아가고 있지요. 이 곳에 그 단편들이 모일 겁니다...^^

댓글을 달아 주세요