Spring Boot 및 MongoDB를 사용하여 REST API 구축하기 - 회원 가입,탈퇴,조회

Spring Boot와 MongoDB를 공부하기 위해 사이드 프로젝트를 시작하려고 마음먹은 지 오래되었지만 막상 혼자서 공부하려니 너무 막연하고 주제도 못 정하고 있었습니다. 때문에 모든 사이트의 기본인 회원 관련 API부터 구현해보기로 마음먹고 첫발을 내딛습니다.

 

[기술 스택]

  • Gradle 7.4.2
  • Spring Boot 2.7.1
  • openJDK 18.0.1.1
  • mongoDB 4.4

 

(본문에서 다루는 모든 패키지는 com.kimmingyu.aws 하위에 선언하고 있기 때문에 본인의 프로젝트에 맞게 수정합니다.)


1. Gradle 필요 의존성 주입

  • 아래 2개의 dependencies는 필수로 추가합니다.
  • modelmapper를 사용하여 Object에서 Obejct로 값을 옮길때 번거롭게 getter, setter 사용지 않게 해 줍니다.
dependencies {
    implementation group: 'org.modelmapper', name: 'modelmapper', version: '2.3.8'
    implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'
}

 

2. Member Model 생성

  • model 패키지를 생성하고 하위에 Member Class를 만듭니다
  • 위에서 추가한 mongodb starter를 활용하여 Document로 지정합니다.
package com.kimmingyu.aws.model;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

@Document(collection = "members")
public class Member {
    @Id
    private String id;
    private String name;
    private String email;
    private String password;
    private String phone;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    @Override
    public String toString() {
        return "Member{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", email='" + email + '\'' +
                ", password=" + password +
                ", phone=" + phone +
                '}';
    }
}

 

3. MemberDTO 생성하기

  • dto 패키지를 만든 후, 하위에 MemberDTO Class를 생성합니다.
package com.kimmingyu.aws.dto;

public class MemberDTO {

    private String id;
    private String name;
    private String email;
    private String password;
    private String phone;

    public MemberDTO() {

    }

    public MemberDTO(String id, String name, String email, String password, String phone) {
        this.id = id;
        this.name = name;
        this.email = email;
        this.password = password;
        this.phone = phone;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }
}

 

4. MemberRepository Interface 생성하기

  • repository 패키지를 생성한 후, 하위에 MongoRepository를 상속받은 MemberRepository Interface를 생성합니다.
package com.kimmingyu.aws.repository;

import com.kimmingyu.aws.model.Member;
import org.springframework.data.mongodb.repository.MongoRepository;

import java.util.List;

public interface MemberRepository extends MongoRepository<Member, String> {

    Member findByEmail(String email);
    Member findByPhone(String phone);


    List<Member> findAllByOrderByNameDesc();
}

 

5. MemberService Interface 생성하기

  • Member관련 Service를 제공하기 위한 사전 명세서를 작성합니다.
  • 꼭 구현해야 하는 기능들 (CRUD) 위주로 서술합니다.
package com.kimmingyu.aws.service;

import com.kimmingyu.aws.model.Member;

import java.util.List;

public interface MemberService {

    List<Member> findAll();

    Member findByEmail(String email);

    Member findByPhone(String phone);

    List<Member> findAllByOrderByNameDesc();

    Member saveOrUpdateMember(Member member);

    void deleteMemberById(String id);
}

 

6. MemberServiceImpl Class 생성하기

  • 위의 MemberService Interface를 구현하여 정말 실제로 사용할 Service Class를 생성합니다.
  • 위에서 명세만 하였던 기능들을 실제로 구현합니다.
package com.kimmingyu.aws.service.impl;

import com.kimmingyu.aws.model.Member;
import com.kimmingyu.aws.repository.MemberRepository;
import com.kimmingyu.aws.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class MemberServiceImpl implements MemberService {

    @Autowired
    private MemberRepository memberRepository;

    @Override
    public List<Member> findAll() {
        return memberRepository.findAll();
    }

    @Override
    public Member findByEmail(String email) {
        return memberRepository.findByEmail(email);
    }

    @Override
    public Member findByPhone(String phone) {
        return memberRepository.findByPhone(phone);
    }

    @Override
    public List<Member> findAllByOrderByNameDesc() {
        return memberRepository.findAllByOrderByNameDesc();
    }

    @Override
    public Member saveOrUpdateMember(Member member) {
        return memberRepository.save(member);
    }

    @Override
    public void deleteMemberById(String id) {
        memberRepository.deleteById(id);
    }
}

 

7. ObjectMapperUtils Class 생성하기

  • service 패키지 하위에 util패키지를 만듭니다. (각자 패키지 관리하는 형식으로 알아서 하시면 됩니다.)
  • ModelMapper를 활용하여 각 객체 간 유연하게 값을 주고받을 수 있는 ObjectMapperUtils Class를 생성합니다.
package com.kimmingyu.aws.service.util;

import org.modelmapper.ModelMapper;
import org.modelmapper.convention.MatchingStrategies;

import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

public class ObjectMapperUtils {

    private static final ModelMapper modelMapper;


    static {
        modelMapper = new ModelMapper();
        modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
    }

    
    private ObjectMapperUtils() {
    }

    
    public static <D, T> D map(final T entity, Class<D> outClass) {
        return modelMapper.map(entity, outClass);
    }

    
    public static <D, T> List<D> mapAll(final Collection<T> entityList, Class<D> outCLass) {
        return entityList.stream()
                .map(entity -> map(entity, outCLass))
                .collect(Collectors.toList());
    }

    
    public static <S, D> D map(final S source, D destination) {
        modelMapper.map(source, destination);
        return destination;
    }
}

 

8. MemberController 생성하기

  • RestController 어노테이션을 사용하여 실제 Member를 컨트롤할 수 있는 Controller를 생성합니다.
  • 위에서 생성 및 구현하였던 모든 기능들을 사용하여 사용 가능한 API를 만듭니다.
package com.kimmingyu.aws.controller;

import com.kimmingyu.aws.dto.MemberDTO;
import com.kimmingyu.aws.model.Member;
import com.kimmingyu.aws.service.impl.MemberServiceImpl;
import com.kimmingyu.aws.service.util.ObjectMapperUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/members")
public class MemberController {

    @Autowired
    private MemberServiceImpl memberService;

    @GetMapping(value = "/")
    public List<MemberDTO> getAllMembers() {
        return ObjectMapperUtils.mapAll(memberService.findAll(), MemberDTO.class);
    }

    @GetMapping(value = "/byEmail/{email}")
    public MemberDTO getMemberByEmail(@PathVariable("email") String email) {
        return ObjectMapperUtils.map(memberService.findByEmail(email),MemberDTO.class);
    }

    @GetMapping(value = "/byPhone/{phone}")
    public MemberDTO getMemberByPhone(@PathVariable("phone") String phone) {
        return ObjectMapperUtils.map(memberService.findByPhone(phone),MemberDTO.class);
    }

    @GetMapping(value = "/orderByName")
    public List<MemberDTO> findAllByOrderByNameDesc() {
        return ObjectMapperUtils.mapAll(memberService.findAllByOrderByNameDesc(),MemberDTO.class);
    }

    @PostMapping(value = "/save")
    public ResponseEntity<?> saveOrUpdateMember(@RequestBody MemberDTO memberDTO) {
        // 이메일 체크
        Member member = memberService.findByEmail(memberDTO.getEmail());
        String responseMessage = "Member added success";
        if(member != null && member.getId() != null && member.getId().length() > 0) {
            responseMessage = "This Email already Exist";
        } else {
            memberService.saveOrUpdateMember(ObjectMapperUtils.map(memberDTO, Member.class));
        }
        return new ResponseEntity(responseMessage, HttpStatus.OK);
    }

    @PostMapping(value = "/delete/{email}")
    public ResponseEntity<?> deleteMemberByEmail(@PathVariable String email) {
        // 이메일 중복 체크
        Member member = memberService.findByEmail(email);
        String responseMessage = "Member Deleted success";
        if(member != null && member.getId() != null && member.getId().length() > 0) {
            memberService.deleteMemberById(memberService.findByEmail(email).getId());
        } else {
            responseMessage = "This Email Dose Not exist our Member List";
        }
        return new ResponseEntity(responseMessage, HttpStatus.OK);
    }

}

 

9. PostMan을 사용하여 TEST 하기

  • 본인은 API 개발할 때, PostMan을 주로 사용합니다.
  • localhost:8080/members/ URL로 접근합니다.
  • 멤버 추가 : [POST] localhost:8080/members/save

멤버 추가 및 동일 메일 가입 방지

  • 멤버 조회 :
    • [GET] localhost:8080/members/
    • [GET] localhost:8080/members/orderByName

멤버 조회 및 멤버 이름 내림차순 조회