SpringBoot로 MBTI테스트 만들기

함배·2023년 5월 16일
2
post-thumbnail

SpringBoot를 혼자 공부를 하던 중 대학 동기 언니에게 온 은밀한 제안..

평소 mbti 과몰입러인 나에게는 너무 흥미로운 주제였고 바로 '콜'을 외쳤다.

스프링부트의 로직 이해와 웹기획+배포까지의 과정을 경험하기 위해 언니와 함께 MBTI테스트를 만들어보기로 하였다!


💭 기획 과정

평소 창의적인 것과 거리가 먼 우리 둘에게 가장 어려웠던 기획 과정...😭

1. mbti테스트 알고리즘 조사

mbti테스트가 어떤 식으로 구성되는지부터 조사했다.
복잡한 알고리즘은 아니었다!

​ 1) MBTI 네가지 척도인 E,I / N,S / T,F / P,J를 결정하는 문제를 만든다.
2) 각 척도마다 과반수로 나온 쪽으로 값이 결정된다.
3) 과반수로 나온 값들을 나열한 것이 최종 결과 값이 된다!

2. 현존하는 mbti테스트 조사 & 주제 선정

그 다음으로는 이미 있는 mbti테스트가 뭐가 있는지, 어떤 질문들로 구성되어 있는지, 어떤 결과들이 나오는지 조사하기 시작했다.

꽃,과자,포켓몬,열대과일,연예인,커피,짱구,업무용 부캐,한복,술버릇,향,강아지,
내 무의식에 살고있는 동물,남들이 보는 나,고양이,동계스포츠,무인도 생존,만두,
동물,직장캐릭터,명품 브랜드,공룡,채소 등

유행인지라 웬만한건 다 있었던 mbti테스트.....😶

유행했던 테스트들을 몇 개 꼽아 질문과 답변을 분석하였다.
질문에서 MBTI 척도 네 가지 중 어떤 것을 결정하는 답변인지 분석하고 mbti별 특징을 뽑아내기 시작했다.

그렇게 mbti테스트 분석과 공부를 마치고 고심하다 우리가 정한 주제는
.
.
.
"이상한 아이스크림의 마을-나는 어떤 아이스크림일까?"였다.


💻 개발 과정(백엔드-SpringBoot부분)

이번 프로젝트는 일주일 정도 넉넉히 기간을 잡고 개발을 하였다.

1. 개발 환경

스프링부트를 쓰지 않아도 충분히 더 간단하게 할 수 있는 프로젝트였지만
나의 목적은 스프링부트 공부였기 때문에!!! 스프링부트를 사용하여 개발하였다.

Spring Boot 3.0.6
Java 17
MariaDB
Spring Data JPA

2. 동작 과정

백엔드에서 할 일은 클라이언트로부터 데이터를 받아서 mbti 결과를 계산하고, 나온 mbti결과를 DB에 저장해야한다는 것은 알겠는데...
그걸 어떻게 구현해야 할 지 정말 막막했다.🤯

동작 원리를 제대로 공부하지 못하고 시작했던 터라 이해하는데 시간이 많이 소요됐던 것 같다.
.
.
개발 과정은 다음과 같다.

1. 테이블 생성

먼저 사용자들이 mbti테스트를 완료하면 결과와 검사한 시간을 확인할 수 있도록 테이블을 하나 만들어줬다.

// 📂entity > MbtiResult.java 코드 중 일부
public class MbtiResult {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column
    private String result;

    @CreationTimestamp
    private Timestamp createDate;
}

그럼 다음과 같이 DB에 컬럼이 생성된 것을 확인할 수 있다.

.
.

API 개발 과정은 다음과 같다.
.
.

2. 클라이언트로부터 MBTI테스트 질문 시 선택한 결과를 받는다.

먼저 클라이언트로부터 데이터를 받아서 mbti결과를 계산하여 return해주는 기능을 구현해야 한다.

프론트에서 mbti테스트 질문 12개 중 E,I / N,S / T,F / P,J가 각각 몇 번씩 선택됐는지에 대한 데이터를 받는다.

다음은 실제 프론트에서 넘겨주는 데이터이다.

let mbti = JSON.stringify({
        E : document.getElementById("E").value,
        I : document.getElementById("I").value,
        S : document.getElementById("S").value,
        N : document.getElementById("N").value,
        T : document.getElementById("T").value,
        F : document.getElementById("F").value,
        P : document.getElementById("P").value,
        J : document.getElementById("J").value
    });

< Dto >
Controller는 프론트에서 보낸 데이터를 객체에 담아 받는다. 그 객체가 DTO이다.

//📂dto > MbtiDto.java 중 일부
public class MbtiDto {
    private int E,I,N,S,T,F,P,J;
}

받을 데이터인 E, I, N, S, T, F, P, J 속성을 받는 데이터가 E가 나온 개수, I가 나온 개수 등을 받는 것이니 int로 선언해준다.

그 후 controller를 다음과 같이 구현해준다.

< Controller >

//📂controller > MbtiController.java 중 일부
@RequestMapping("/mbti")
public class MbtiController {
    @PostMapping(value = "/result")
    public String calmbti(@RequestBody MbtiDto mbtiDto){
        String t1 = "E : " + mbtiDto.getE();
        String t2 = "\nI : " + mbtiDto.getI();
        String t3 = "\nN : " + mbtiDto.getN();
        String t4 = "\nS : " + mbtiDto.getS();
        String t5 = "\nT : " + mbtiDto.getT();
        String t6 = "\nF : " + mbtiDto.getF();
        String t7 = "\nP : " + mbtiDto.getP();
        String t8 = "\nJ : " + mbtiDto.getJ();

        return t1 + t2 + t3 + t4 + t5 + t6 + t7 + t8;
    }
}
  1. @RequestMapping()을 이용해 공통적으로 사용할 URL을 "/mbti"로 지정해준다.
  2. 그 후 @PostMapping()으로 request메소드 값을 POST형식으로 지정해주고,
  3. data를 반환해야 하기 때문에 @ResponseBody 어노테이션을 통해 json을 전달할 것이다.
  4. dto 객체로 매핑하여 데이터가 잘 받아져 왔는지 postman으로 테스트 해본다.

< 결과 >

성공적으로 결과가 반환되는 것 을 확인할 수 있다.

3. 정해진 알고리즘에 의해 결과를 도출한다.

E,I / N,S / T,F / P,J가 각각 몇 번씩 선택됐는지에 대한 데이터를 받았으니
이제 받은 데이터를 비교하여 MBTI 네 가지 척도(ex: E인지 I인지)를 결정할 것 이다.

< Dto >
우선 아까 작성했던 dto에 추가적으로 네 가지 척도를 결정해 저장해 둘 속성 mbti1,mbti2,mbti3,mbti4를 String타입으로 선언한다.

그 후 네 가지 척도를 합쳐 mbti를 저장할 속성 result를 String타입으로 선언한다.

//📂dto > MbtiDto.java 중 일부
public class MbtiDto {
  private int E,I,N,S,T,F,P,J;
  private String mbti1,mbti2,mbti3,mbti4;
  private String result;
}

< Controller >
dto객체로 받아온 데이터를 조건문으로 따져 E vs I/ N vs S / T vs F / P vs J 값을 비교하여 차례대로 mbti1, mbti2, mbti3, mbti4에 저장한다.
저장된 mbti1, mbti2, mbti3, mbti4를 합쳐 result에 저장하고 result 값을 리턴한다.

//📂controller > MbtiController.java 중 일부
  public String postMemberDto(@RequestBody MbtiDto mbtiDto){

      if(mbtiDto.getE() > mbtiDto.getI()){
          mbtiDto.setMbti1("E");
      }else{
          mbtiDto.setMbti1("I");
      }
      if(mbtiDto.getN() > mbtiDto.getS()){
          mbtiDto.setMbti2("N");
      }else{
          mbtiDto.setMbti2("S");
      }
      if(mbtiDto.getT() > mbtiDto.getF()){
          mbtiDto.setMbti3("T");
      }else{
          mbtiDto.setMbti3("F");
      }
      if(mbtiDto.getP() > mbtiDto.getJ()){
          mbtiDto.setMbti4("P");
      }else{
          mbtiDto.setMbti4("J");
      }
      String result = mbtiDto.setResult(mbtiDto.getMbti1() + mbtiDto.getMbti2() + mbtiDto.getMbti3() + mbtiDto.getMbti4());

	  return result;
  }

< 결과 >

알맞게 mbti결과 데이터가 반환된다.

.
.

그런데 여기서 문제점!

위 코드에서는 서비스 로직(mbti를 계산하는 로직)을 controller에서 구현했다.
근데 과연 이게 좋은 방법일까?
.
.
여기서 다시 살펴봐야 하는 스프링부트의 패키지구조!

1) Client가 Request를 보내면
2) Request URL에 알맞은 Controller가 수신을 받는다.
3) 여기서 Controller는 넘어온 요청을 처리하기 위해 Service를 호출한다!
4) 그럼 Service가 알맞은 정보를 가공하여 Controller에게 데이터를 다시 넘기면
5) Controller는 Service의 결과물을 Client에게 전달해주는 것이다.
.
.
우린 여기서 Controller와 Service의 역할을 구분해야한다.
로직을 Service에 담는 이유는 비슷한 처리를 서로 다른 페이지에서 요청할 경우 각각 컨트롤러에 중복 코드가 생길 수 있는 문제를 해결하기 위함이다.

이러한 이유로 서비스 로직을 Service에 다시 작성하여 코드를 수정하였다.

< Service >

public String calResult(MbtiDto mbtiDto) {
	if (mbtiDto.getE() > mbtiDto.getI()) {
		mbtiDto.setMbti1("E");
	} else {
		mbtiDto.setMbti1("I");
    }
    if (mbtiDto.getN() > mbtiDto.getS()) {
        mbtiDto.setMbti2("N");
    } else {
        mbtiDto.setMbti2("S");
    }
    if (mbtiDto.getT() > mbtiDto.getF()) {
        mbtiDto.setMbti3("T");
    } else {
        mbtiDto.setMbti3("F");
    }
    if (mbtiDto.getP() > mbtiDto.getJ()) {
        mbtiDto.setMbti4("P");
    } else {
        mbtiDto.setMbti4("J");
    }
	String result = mbtiDto.getMbti1() + mbtiDto.getMbti2() + mbtiDto.getMbti3() + mbtiDto.getMbti4();
	mbtiDto.setResult(result);

	return result; 
}

controller에 있던 로직을 Service로 가져온다.

< Controller >

@PostMapping(value = "/result")
public String calmbti(@RequestBody MbtiDto mbtiDto){
  
	String result = mbtiService.calResult(mbtiDto);

    return result;
}

dto로 받아온 데이터로 service에 있는 mbti를 계산로직을 불러오고, 결과 값을 받아옴.

반환 값은 동일하다.


4. 결과를 통계 디비에 저장한다.

위에서 계산된 mbti 결과 값을 디비에 저장하는 로직을 작성해보자.

Dto를 Controller로 보내 Entity로 변환한 후, Repository한테 Entity를 DB안에 저장하도록 할 것이다.

< Dto >

public MbtiResult toEntity() {
	return new MbtiResult(null, result, null);
}

dto파일에서 toEntity메서드를 정의한다.


< Controller >

// Dto를 Entity화
MbtiResult mbtiResult = mbtiDto.toEntity();
    
// Service한테 넘겨서 Repository한테 Entity를 DB안에 저장하게 함.
mbtiService.save(mbtiResult);

Dto를 Entity로 변환한 메서드를 호출하여 dto를 entity화 시키고 그 값을 mbtiService의 save()메서드로 넘긴다.

< Service >

public void save(MbtiResult mbtiResult){
	MbtiResult saved = mbtiRepository.save(mbtiResult);
}

Service에서 Controller부터 entity로 변환된 dto를 받아 Repository에게 Entity를 DB안에 저장하도록 한다.

5. 클라이언트로 결과를 반환한다.

< Controller >

@PostMapping(value = "/result")
    public String calmbti(@RequestBody MbtiDto mbtiDto){
        // dto로 받아온 데이터로 service한테 mbti를 계산하게 하고, 결과 값을 받아옴.
        String result = mbtiService.calResult(mbtiDto);

        // Dto를 Entity화
        MbtiResult mbtiResult = mbtiDto.toEntity();

        // Service한테 넘겨서 Repository한테 Entity를 DB안에 저장하게 함.
        mbtiService.save(mbtiResult);

        return result;
    }

mbti결과를 클라이언트에 반환하고, DB에 자동으로 생성된 기본키와 결과값 그리고 클라이언트로부터 데이터를 받은 시간까지 성공적으로 들어간 것을 확인할 수 있다.


😁 결과물

SNS홍보 만으로 배포 후 일주일 동안 사용자 1000명 달성!!! 역시...바이럴👍


🎤 소감

기획-개발-배포까지 모두 경험을 해보니 드는 생각은...'문이과의 융합이 이래서 중요하구나'였다..😂

기획과 마케팅 쪽에 너무 소질도 없고 무지하다 보니 기획과 디자인 그리고 배포 과정에서 어려움을 많이 느꼈던 것 같다.

하지만 나의 목표는 스프링부트 공부와 웹기획과 배포까지의 과정을 경험하는 것이었기 때문에 목표는 성공적으로 이뤘다고 생각한다!!

이 프로젝트 덕분에 이론으로 이해하지 못했던 스프링부트의 로직을 이해하게 되었고, 배포까지의 과정을 경험한 것이 다른 프로젝트를 하는 데에도 많은 도움이 되었다.😊

- 끝 -

[출처]
기획 과정 - mbti테스트 알고리즘 조사
https://velog.io/@solk553/MBTI-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EA%B0%9C%EB%B0%9C%EC%9D%BC%EC%A7%80-1
스프링부트 패키지구조
https://velog.io/@agugu95/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%8C%A8%ED%84%B4%EA%B3%BC-DAO-DTO-Repository
Create로직
https://youtu.be/ZGgf_1OXcAY

profile
아둥바둥 개발자

1개의 댓글

comment-user-thumbnail
2023년 11월 19일

안녕하세요! 바쁘신 시간에 죄송합니다!
글을 읽고 문의를 드리고 싶어 댓글을 남깁니다...!
지금까지 본 MBTI 개발 글들중에서 유일하게 JS가 아닌 JAVA를 사용하여 개발을 진행하신 것을 보고 프로젝트를 공부해보기 위해 따라서 만들어 보려고 소스코드를 작성해보고 있는데 막히는 부분이 있어서 혹시나 위 프로젝트에 대한 소스코드가 담겨진 github같은 주소가 있는지에 대해 문의를 드리고 싶습니다ㅠㅠㅠ

답글 달기