on
[SpringBoot/AWS EC2] MongoDB (Auto-Generated Field)
[SpringBoot/AWS EC2] MongoDB (Auto-Generated Field)
본격적으로 개발을 앞서 오늘 사용 할 환경정보이다.
JAVA 1.8 springBoot 2.1.9.RELEASE gradle 7.1 spring data jpa 2.4.5 // 주석처리 mongodb version v3.6.3
딱히 명시를 안한 의존성들은 springboot 2.1.9의 default 버전을 사용한다.
게시판의 요구사항은 다음과 같다.
게시판 기능 회원 기능 게시글 조회 구글/네이버 로그인 게시글 등록 로그인 한 사용자 글 작성 권한 게시글 수정 본인 작성 글에 대한 관리 게시글 삭제
gradle의 의존성을 주입한다.
gradle dependencies는 아래의 사이트에서 검색해서 사용자가 많은 버전 골라서 쓰면 된다.
https://mvnrepository.com/
MongoDB를 처음 사용해보는 것이여서 스프링 공식 문서와 baeldung 글을 읽고 시작했다.
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'
의존성 추가
spring.data.mongodb.uri=mongodb://[ip 정보]:[port 정보] spring.data.mongodb.database=[데이터베이스 이름]
/src/main/resource 밑에 application.properties 파일을 생성하고 위의 코드를 추가한다.
domain 패키지를 생성한다.
도메인을 담을 패키지이다. 도메인은 게시글, 댓글, 회원, 정산, 결제 등 소프트웨어에 대한 요구사항 혹은 문제영역을 말한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package com.example.springboot.domain.posts; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; @Getter @NoArgsConstructor // 기본 생성자 자동 추가 @Document(collection = "posts" ) public class Posts { @Id private Long id; private String title; private String content; private String author; @Builder public Posts( String title, String content, String author){ this .title = title; this .content = content; this .author = author; } } Colored by Color Scripter cs
이렇게 생성했더니
Cannot autogenerate id of type java.lang.Long for entity of type com.example.springboot.domain.posts.Posts!
오류가 났다. rdbms처럼 id가 자동증가가 되는 것이 아닌 모양..
https://www.baeldung.com/spring-boot-mongodb-auto-generated-field
이 사이트를 참고해서 자동생성
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package com.example.springboot.domain.posts; import lombok.Getter; import lombok.Setter; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; @Getter @Setter //getters and setters omitted @Document(collection = "database_sequences" ) //AUTO INCREMENT 연속성 정보 저장 컬렉션 public class DatabaseSequence { @Id private String id; private long seq; } Colored by Color Scripter cs
domain.posts 패키지 안에 DatabaseSequence.java 파일을 생성한다.
Posts.java로 돌아가서
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 package com.example.springboot.domain.posts; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import org.springframework.data.annotation.Id; import org.springframework.data.annotation.Transient; import org.springframework.data.mongodb.core.mapping.Document; @Getter @NoArgsConstructor // 기본 생성자 자동 추가 @Document(collection = "posts" ) public class Posts { @Transient // 영속성 필드 제외 public static final String SEQUENCE_NAME = "users_sequence" ; // 자동 증가 시퀀스에 대해 참조하는 SEQUENCE_NAME 선언 @Id private Long id; private String title; private String content; private String author; public void setId(Long id){ this .id = id; } @Builder public Posts( String title, String content, String author){ this .title = title; this .content = content; this .author = author; } } Colored by Color Scripter cs
SEQUENCE_NAME을 static으로 선언한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package com.example.springboot.service.SequenceGenerator; import com.example.springboot.domain.posts.DatabaseSequence; import lombok.RequiredArgsConstructor; import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.core.query.Update; import org.springframework.stereotype.Service; import java.util.Objects; import static org.springframework.data.mongodb.core.FindAndModifyOptions.options; import static org.springframework.data.mongodb.core.query.Criteria.where; import static org.springframework.data.mongodb.core.query.Query.query; @RequiredArgsConstructor @Service public class SequenceGeneratorService { private final MongoOperations mongoOperations; public long generateSequence( String seqName) { DatabaseSequence counter = mongoOperations.findAndModify(query(where( "_id" ).is(seqName)), new Update().inc( "seq" , 1 ), options().returnNew( true ).upsert( true ), DatabaseSequence. class ); return ! Objects.isNull(counter) ? counter.getSeq() : 1 ; } } Colored by Color Scripter cs
자동으로 증가시켜줄 수 있는 클래스인 SequenceGeneratorService.java를 생성한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package com.example.springboot.events; import com.example.springboot.domain.posts.Posts; import com.example.springboot.service.SequenceGenerator.SequenceGeneratorService; import lombok.RequiredArgsConstructor; import org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener; import org.springframework.data.mongodb.core.mapping.event.BeforeConvertEvent; import org.springframework.stereotype.Component; @RequiredArgsConstructor @Component public class PostsModelListener extends AbstractMongoEventListener < Posts > { private final SequenceGeneratorService sequenceGenerator; @Override public void onBeforeConvert(BeforeConvertEvent < Posts > event) { // if (event.getSource().getId() < 1) {// null point error event.getSource().setId(sequenceGenerator.generateSequence(Posts.SEQUENCE_NAME)); // } } } Colored by Color Scripter cs
새로운 Posts가 추가될때마다 반응할 PostsModelListener.java를 생성한다.
mongoDB에 사용할 document를 만든다.
1 2 3 4 5 6 7 package com.example.springboot.domain.posts; import org.springframework.data.mongodb.repository.MongoRepository; public interface PostsRepository extends MongoRepository < Posts,Long > { } Colored by Color Scripter cs
MongoRepository를 extends한 인터페이스 PostsRepository를 작성한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 package com.example.springboot.web.domain.posts; import static org.assertj.core.api.Assertions.assertThat; import com.example.springboot.domain.posts.Posts; import com.example.springboot.domain.posts.PostsRepository; import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.util.List; @RunWith(SpringRunner. class ) @SpringBootTest public class PostsRepositoryTest { @Autowired PostsRepository postsRepository; @After // 단위테스트가 끝날 때마다 수행되는 메소드 public void cleanup(){ postsRepository.deleteAll(); } @Test public void 게시글저장_불러오기(){ //given String title = "테스트 게시글" ; String content = "테스트 본문" ; postsRepository.save(Posts.builder() .title(title) .content(content) .author( "작성자" ) .build()); //when - 포스트 테이블 모두 조회 List < Posts > postsList = postsRepository.findAll(); //then Posts posts = postsList.get( 0 ); assertThat(posts.getTitle()).isEqualTo(title); assertThat(posts.getContent()).isEqualTo(content); } } Colored by Color Scripter cs
Test를 시도하면
deleteAll을 진행해서 post는 남지 않지만, database_sequences는 증가한 것을 확인할 수 있다.
from http://hjkongkong.tistory.com/11 by ccl(A) rewrite - 2021-12-09 00:00:36