[몽고DB, 스프링부트] Springboot, MongoDB 연동
스프링부트 몽고DB 연결
이번 포스팅에선 스프링부트에 스프링 데이터 몽고디비를 사용하여 DB를 연결하고, 간단한 api를 구현하여 연결이 잘 되었는지 테스트해보는 내용에 대해 다뤄보겠습니다.
아직 몽고DB에 관하여 공부가 더 필요하기 때문에 우선 간단한 내용과 연결 방법을 소개하고 다음 포스팅에서 몽고디비에 관한 내용만을 다루는 포스팅을 작성하겠습니다.
바로 시작하겠습니다.
:: Mongo DB ::
MongoDB의 기본적인 데이터 구조는 데이터베이스, 컬렉션, 도큐먼트 단위로 관리된다.
MongoDB 장점
- Schema-less 구조
- 다양한 형태의 데이터 저장 가능
- 데이터 모델의 유연한 변화 가능(데이터 모델 변경, 필드 확장 용이) - Read/Write 성능이 뛰어남
- Scale Out 구조
- 많은 데이터 저장이 가능
- 장비 확장이 간단함 - JSON 구조 : 데이터를 직관적으로 이해 가능 (JSON 형식의 데이터 구조로 문서(Document)에 저장한다.)
- 사용 방법이 쉽고, 개발이 편리함
위는 몽고DB에 저장된 예시 데이터의 JSON구조이다.
MongoDB 단점
- 데이터 업데이트 중 장애 발생 시, 데이터 손실 가능
- 많은 인덱스 사용 시, 충분한 메모리 확보 필요
- 데이터 공간 소모가 RDBMS에 비해 많은(비효율적인 Key 중복 입력)
- 복잡한 JOIN 사용시 성능 제약이 따름
- 트랜잭션 지원이 RDBMS 대비 미약함
- 제공되는 MapReduce 작업이 Hadoop에 비해 성능이 떨어짐
:: 몽고DB 설치(MacOS) ::
$ brew update # homebrew 업데이트
$ brew tap mongodb/brew # mongoDB 설치 공간 확보
$ brew install mongodb-community # mongoDB 최신버전 설치
$ brew services start mongodb-community # mongoDB 실행
# mongoDB Compass 설치
$ brew --cask install mongodb-compass (만약 cask가 설치가 안되었다면 "$ brew install cask" 수행)
:: 몽고DB & 스프링부트 연결 ::
1. MongoDB 연결
이 글은 로컬 환경(localhost)을 기준으로 설명한다.
MongoDB Compass를 실행후 다음과 같은 URI를 입력해준 후 좌측 하단에 Connect 버튼을 클릭하여 DB에 연결한다.
좌측 Databases의 + 버튼을 클릭하여 사용할 Database를 만든다.
사용할 DB이름과 기본 컬렉션(테이블)을 입력하여 하나의 데이터베이스를 생성한다.
그럼 이렇게 customer라는 컬렉션을 가진 test 데이터베이스가 만들어진다.
이제 Spring에 연결해보자
2. application.yml 설정
spring:
data:
mongodb:
host: localhost
port: 27017
authentication-database: admin
database: test
#uri: mongodb://localhost:27017/test
- mogodb.host : 접속할 db의 ip 주소
- mongodb.port : 접속할 db의 port 번호
- mongodb.authentication-database : 접속할 계정이 위치한 db의 이름
- mongodb.database : 접속할 database 이름
- mongodb.username : 접속할 계정 이름
- mongodb.password : 접속할 계정 비밀번호
3. build.grade Implement
mongoDB만 사용할 때
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb
mongoDB 외에 다른 db도 사용하고 싶다면
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb-reactive
주의점!!
mongoDB만 사용할 때 mongodb-reactive를 사용하면 스프링 빈 생성 오류가 발생할 수 있다.
4. Test를 위한 Collection, Controller, Service, Repository 생성
4-1. Model 객체 생성
유저의 성(firstName)과 이름(lastName)을 갖는 Customer 도큐먼트를 정의합시다. DB에 저장될 document의 이름은 @Documemt 애노테이션을 통하여 지정해줍니다. MongoDB의 모든 도큐먼트는 반드시 _id라는 주키를 갖게 됩니다. @Id 애노테이션은 해당 필드에 대해 주키로 지정하겠다는 의미를 가집니다.
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import studymongodbnosql.springmongo.dto.CustomerResponseDto;
@Document(collection = "customer")
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class Customer {
@Id
private String id;
private String firstName;
private String lastName;
public Customer(StringfirstName, StringlastName) {
this.firstName =firstName;
this.lastName =lastName;
}
public CustomerResponseDto toDto() {
return new CustomerResponseDto(id, firstName, lastName);
}
}
Spring-Data-JPA 사용 시 @Entity, @Table(name = "테이블명")를 통해 Table과 연결하였지만
Spring-Data-MongoDB 사용 시 @Document(collection= "컬렉션명") 을 통해 Collection과 연결한다.
이번 과정에선 아까 MongoDB Compass에서 Database생성 시 collection명을 customer로 생성했기 때문에 collection=”customer” 로 설정한다.
4-2. DTO 생성
CustomerRequestDto
@Getter
@Setter
@AllArgsConstructor
public class CustomerRequestDto {
private String firstName;
private String lastName;
public Customer toEntity() {
return new Customer(firstName, lastName);
}
}
CustomerResponseDto
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
public class CustomerResponseDto {
private String id;
private String firstName;
private String lastName;
}
아무리 테스트이지만 역할을 확실히 분리하여 구현하기 위해 DTO도 구현해주었다.
5. Repository 클래스 생성
CustomerRepository
import org.springframework.data.mongodb.repository.MongoRepository;
import studymongodbnosql.springmongo.domain.Customer;
import java.util.List;
public interface CustomerRepository extends MongoRepository<Customer, String> {
List<Customer> findByFirstName(String firstName);
}
MongoTemplate와 MongoRepository
몽고DB는 MongoTemplate 또는 MongoRepository를 사용하여 연동할 수 있다.
MongoTemplate는 MongoRepository보다 더 세부적인 질의가 가능하지만
현재 프로젝트에선 편의성을 고려하여 MongoRepository를 사용하여 구현한다.
MongoRepository 인터페이스
생성한 Repository 인터페이스에 MongoRepository<T, ID> 를 extends한다.
제네릭을 뜻하는 T에는 레포지토리와 연결할 Class가 들어가고, ID는 컬렉션에 @Id로 설정한 변수의 자료형이 들어가는데 몽고DB의 Key,Value는 JSON형태로 이루어져 있어서 평균적으로 String이 사용된다.
JpaRepository와 마찬가지로 extends 시에 자동으로 Bean에 등록되기 때문에 @Repository 애노테이션이 필요하지 않다.
DB select 테스트를 위해 MongoRepository의 메서드 naming convention에 맞춰 findByFirstName 메서드를 구현하였다.
6. Service 클래스 생성
CustomerService 객체
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import studymongodbnosql.springmongo.domain.Customer;
import studymongodbnosql.springmongo.dto.CustomerRequestDto;
import studymongodbnosql.springmongo.dto.CustomerResponseDto;
import studymongodbnosql.springmongo.repository.CustomerRepository;
import java.util.ArrayList;
import java.util.List;
@RequiredArgsConstructor
@Service
public class CustomerService {
private final CustomerRepository customerRepository;
public CustomerResponseDto saveCustomer(CustomerRequestDtocustomerRequestDto) {
CustomersavedCustomer= customerRepository.save(customerRequestDto.toEntity());
returnsavedCustomer.toDto();
}
public List<CustomerResponseDto> findCustomerByFirstName(StringfirstName) {
List<Customer>customerList= customerRepository.findByFirstName(firstName);
List<CustomerResponseDto>result= new ArrayList<>();
customerList.stream().forEach(c-> {
result.add(c.toDto());
});
returnresult;
}
}
DB에 Customer를 저장하는 saveCustomer 메서드와
FirstName으로 Customer를 select하는 findCustomerByFirstName 메서드를 구현하였다.
save 메서드는 MongoRepository에서 기본적으로 지원한다.
컨트롤러에서 클라이언트에게 데이터를 전달할 때 DTO로 전달해야하기 떄문에 Customer 컬렉션에 toDto 메서드를 구현하여 쉽게 ResponseDto로 변환할 수 있도록 하였다.
7. Controller 클래스 구현
CustomerController 객체
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import studymongodbnosql.springmongo.dto.CustomerRequestDto;
import studymongodbnosql.springmongo.dto.CustomerResponseDto;
import studymongodbnosql.springmongo.service.CustomerService;
import java.util.List;
@RestController
@RequiredArgsConstructor
@RequestMapping("/customer")
public class CustomerController {
private final CustomerService customerService;
@PostMapping("/save")
public ResponseEntity<?> saveCustomer(@RequestBody CustomerRequestDtocustomerRequestDto) {
try {
System.out.println("customerRequestDto = " +customerRequestDto.getFirstName());
CustomerResponseDtocustomerResponseDto= customerService.saveCustomer(customerRequestDto);
return new ResponseEntity<>(customerResponseDto, HttpStatus.OK);
} catch (Exceptione) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
}
@GetMapping("/find/{firstName}")
public ResponseEntity<?> findCustomerByFirstName(@PathVariable StringfirstName) {
try {
List<CustomerResponseDto>customerResponseDtoList= customerService.findCustomerByFirstName(firstName);
return new ResponseEntity<>(customerResponseDtoList, HttpStatus.OK);
} catch (Exceptione) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
}
}
위 코드로 컨트롤러를 통해 save와 find RestAPI를 구현하였다.
8. PostMan으로 Test
save API 테스트
db에 확실히 저장된 것을 확인할 수 있다.
select API 테스트
firstName을 통해 방금 insert한 데이터를 불러온 것을 확인할 수 있다.
references
https://ckddn9496.tistory.com/100
https://freedeveloper.tistory.com/341
https://tychejin.tistory.com/349