Skip to content

tjgus027/MAT_ZIP

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

290 Commits
 
 
 
 
 
 

Repository files navigation

[팀프로젝트] 맛.JAVA - 맛.ZIP

💡 맛.ZIP은 “진짜 믿고 먹을 수 있는 맛집” 을 공유하는 플랫폼입니다.

  • 맛.JAVA 팀은 맛집 탐방에 누구보다 진심인 사람들이 뭉친 팀입니다. 🍔
  • 평소에 모두가 겪고 있던 부정한 광고, 믿을 수 없는 후기 속에서 소비자들이 믿고 방문할 수 있는 맛집을 모아 볼 수 있는 사이트의 필요성을 느꼈습니다.
  • 그래서, 영수증 2회 이상 인증된 맛집만 등록되도록 해서 신뢰도 및 만족도가 높은 맛집만 선별하여 소비자에게 제공하는 목적으로 개발을 진행했습니다.
  • 국내 운영 중인 맛집 추천 사이트, 대형 포털 지도 사이트의 사례 분석을 통해, 웹사이트 기능의 방향성을 "진정성 있는 맛집 공유"로 초점을 맞췄습니다.
  • 맛집을 좋아하는 사람들 뿐만 아니라, 맛집을 좋아하는 사람들의 방문을 원하는 요식업계 사장님들도 타켓팅한 사장님 전용 구독 서비스 및 노출 배너 광고를 BM으로 설정했습니다.

1. 제작 기간

2023년 4월 28일 ~ 6월 9일 (1개월)


2. 사용 기술

Back-end

  • Java 8
  • Spring Framework 5.0.1, Spring MVC
  • Maven
  • Mybatis
  • Eclipse

Front-end

  • HTML
  • CSS
  • JavaScript
  • JQuery 3.6.4
  • BootStrap 4.1

Database

  • MySQL 8.0.32

Collaboration

  • Git, Sourcetree
  • Slack
  • Notion

External API

  • Naver, Kakao Social Login
  • CLOVA Chatbot API

3. 기능 구현

  • [정서현] 회원가입, 로그인, 마이페이지, AI챗봇

    • 이메일 인증, 유효성 검사를 통한 회원가입
    • 일반, 간편 로그인, 임시 비밀번호 발급 가능
    • 챗봇 API를 통해 자주 묻는 질문 등록
  • [김규환] 영수증 등록, 검색기능

    • 영수증, 카드내역을 통한 또 갔던 맛집 등록기능
    • 2회 이상 등록된 맛집 검색기능
  • [최윤서] 음식점 상세페이지

    • 음식점 상세정보 CRUD 기능 및 카테고리별 음식점 검색 기능
    • 상세페이지 URL 복사(for 공유하기)
    • 네이버 포털사이트 이동하여 해당 음식점 검색
    • 카카오 API 사용 ► 해당 음식점의 주소를 받아서 지도 띄우기 + 해당 음식점의 위치를 기반으로 카테고리별 장소 검색
  • [추재영] 회원 커뮤니티

    • 맛집에 관심이 있는 소비자가 이용하는 커뮤니티로, 리뷰 / 사진 / 지유게시판으로 나누어 유저 용도에 따라 세부 메뉴 분류
    • 각 게시판별 게시물 CRUD 기능 및 댓글 insert 기능
    • 리뷰게시판은 영수증 등록 여부를 체크하여 영수증 등록을 한 유저만 리뷰를 남길 수 있도록 제약사항을 추가하여 리뷰의 신뢰도를 강화함.
  • [이후성] 사장 커뮤니티

    • 구독 결제 시 사장회원등록, 결제내역 DB 저장
    • 결제내역 DB를 기반으로 데이터 선별하여 매출차트 및 재방문 차트 구현
    • 리뷰 AI 감정분석 차트 - 사용자들이 작성한 리뷰 데이터를 기반으로 AI 감정분석 API를 사용하여 감정분석 결과를 출력
    • 자유게시판 및 좋아요 기능- 게시글 수정, 검색 기능을 강화, '좋아요' 기능을 추가
  • [함영휘] 포인트 시스템, 랭킹 시스템

    • 영수증 등록 시 포인트 적립
    • 적립된 포인트를 사용해서 상품교환(기프티콘) SENS API 사용해서 문자로 전송
    • 등록된 영수증을 카운트해서 많이 등록된 음식점 카테고리별 분류
  • [전혜진] 캘린더

    • 방문 예정인 맛집 일정을 등록하고, 확인할 수 있는 캘린더 기능을 구현함.

회원가입, 로그인, 마이페이지, AI챗봇 영수증 등록, 검색기능
음식점 상세페이지 회원 커뮤니티
사장 커뮤니티 포인트 시스템, 랭킹 시스템
캘린더

4. ERD 설계


5. 시스템 아키텍쳐 구성도

image



6. 핵심 기능 설명 & 트러블 슈팅

1) [정서현] 이메일 인증, 간편 로그인, 챗봇

📌 핵심 기능 설명
  • 핵심 기능: 이메일 인증, 간편 로그인, 챗봇
1. Gmail SMTP를 활용한 이메일 인증
  • Gmail 설정에 IMAP 액세스 상태를 사용으로 수정 후 앱 비밀번호 생성
  • root-context에 이메일과 비밀번호, SSLSocketFactory 저장하여 빈 등록
  • 서비스에 랜덤으로 6자리 인증번호 생성 메소드 정의하여 선언한 변수에 저장
  • 이메일 폼 작성 메소드에서 폼 작성하여 전송 메소드 호출하여 메일 전송 후 인증번호 리턴
  • 이메일 전송 메소드에 작성 폼을 받고, 메시지를 생성하여 입력된 이메일로 전송
  • !!결과!! 이메일 인증 버튼 클릭 시 인증번호가 담긴 메일 전송!
  • [👉전체 흐름 확인하기] image
  • 활용 UUID를 생성하여 Low time 부분만 변수 선언 후 임시 비밀번호로 update하여 메일 전송
  • [👉전체 흐름 확인하기] image
2. OAuth 2.0 프로토콜 기반 사용자 인증 후 간편 로그인
  • 로그인 API 사용시 필요한 값(클라이언트 아이디, 시크릿 키, 콜백 URI, 세션 상태, 프로필 URL)을 변수 선언
  • BO에 1. 토큰 메소드, 2. 인증 URL 생성 메소드 정의, 3. 세션에 선언한 상태값을 넣는 getter, setter 정의
    • 토큰 생성 시에 코드 정보를 받아 토큰으로 발급
  • 컨트롤러에서 콜백 경로로 맵핑 후 버튼 클릭 시 호출되는 메서드 생성
  • 토큰 발급 메서드 호출 후 저장된 토큰값을 가지고 유저의 정보 획득
  • json으로 넘어온 값을 파싱하여 필요한 값을 dto에 저장
  • !!결과!! 회원 조회 후 없으면 자동 회원가입 진행, 있으면 세션에 아이디 저장 후 콜백 url로 리턴
    • 카카오 로그인은 전화번호를 받을 수 없어 마이페이지로 포워딩하여 정보 수정 받도록 진행
  • [👉전체 흐름 확인하기] image
3. 웹소켓과 CLOVA API를 활용한 웹소켓
  • TextWebSocketHandler를 상속하는 챗봇 핸들러를 작성
  • 핸들러에 1. 웹소켓 연결 후, 2. 클라이언트의 텍스트 받아올때, 3. 연결 해제 후 이렇게 3가지 상황의 메소드 정의
  • 핸들러를 servlet-context.xml에 빈 등록, 웹소켓 핸들러로 설정하고 웹소켓 연결 경로 지정
  • javascript에서 정한 uri로 웹소켓 객체 생성하고 성공하면 웰컴 메시지 전달
  • 유저가 버튼 클릭하여 버튼의 메시지를 발신하면 메시지에 맞는 내용 수신
  • javascript로 수신한 메시지 json을 파싱하여 description의 부분이 유저에게 보일 수 있도록 메소드 정의
  • 유저가 메인이 아닌 다른 페이지로 이동할 경우 연결 해제
  • 결과!! 클로바 챗봇 API에 작성한 시나리오 흐름에 따라 FAQ 진행
  • [👉전체 흐름 확인하기] image
⚽ 트러블 슈팅
  • 메시지 리턴 과정, 간편 로그인 정보 저장, 챗봇 에 관한 트러블 슈팅

1. 유효성 검사를 진행하며 지정한 메시지가 리턴되지 않음

❓ 문제가 뭐지? - 문제 정의

  • 유효성 검사를 진행하여 에러가 발생했는데 에러 메시지가 아닌 null 값 출력
  • 404, 500 등 클라이언트, 서버의 오류는 없었고 이클립스 콘솔에 뜨는 에러도 없었음

❓ 왜 이런 문제가 발생하지? - 가설 세우기

  1. request에 저장해서 view에 불렀는데, request의 저장된 값의 변수명이 다른가?
  2. 내가 리턴하는 방식에 문제가 있나?

이렇게 하면 해결되려나? - 시도

1. request에서 get하는 키의 변수명 문제 ❌ 
   에러가 있을 시에 서비스에서 key=value 형태로 에러를 저장하는데, 저장한 map을 출력하여 테스트
   key에 내가 포맷한 이름 형태와 value에 내가 쓴 에러 메시지가 출력
   모델에 넣어서 전달하는 값도 동일하게 출력
   => key의 값을 넣은 request에서 get하는 변수명은 문제가 아니다!

💡 이렇게 해서 해결! - 해결 방법 & 결과

2. 리턴하는 방식의 문제 ⭕️ -> 리턴 방식 변경
   문제가 발생했을때의 나는 모델, 즉 request영역에 값을 저장하고 
   리턴 값에 정한 경로에 리다이렉트를 사용하여 로그인 페이지로 넘김
   리다이렉트는 request와 response 객체가 새롭게 생성되는데, 그걸 모르는 상태에서 사용
  • 원래 코드 -> 수정 코드
  • return redirect:/mz_member/login -> return /mz_member/login

📖 그래서 이런 지식을 얻었다! - 알게 된 점

리다이렉트 VS 포워딩

리다이렉트

  • URL을 다시 가리킨다라는 뜻으로,
  • 클라이언트가 서버에 요청한 URL을 받고 서버에서 해당 요청이 이동되었음을 확인한 경우
  • 이동된 url로 재접속을 응답하여 클라이언트가 이동된 url에 재접속하여 다시 url 요청
  • url 확인 후 코드와 body에 html을 응답
  • 여기서 리다이렉트 응답은 3xx / 정상 응답은 2xx으로 코드 응답
  • 리다이렉트는 재접속을 요청하기 때문에 request와 response의 값은 더이상 유효하지 않음
    • 세션 값은 유효함

포워딩

  • 건내주기라는 뜻으로,
  • 클리이언트와 통신하여 처리하는 리다이렉트와 달리, 포워딩은 서버 내부에서만 처리
  • 클라이언트가 서버에 url을 요청하면 서버에서 내부 처리를 하고 2xx 코드와 함께 응답
  • 그래서 클라이언트는 실제로 다른 페이지로 이동했는지 알 수 없음
  • 포워딩은 요청정보가 다음 url에서도 유효하기에 request와 response 객체를 공유

2. 네이버 로그인 중 승인 토큰을 얻지 못하고 null 리턴

❓ 문제가 뭐지? - 문제 정의

  • BO의 승인 토큰을 얻는 과정에서 세션 검증용 값과 세션에 저장된 값이 동일하지 않아 null값을 리턴
  • 승인 토큰을 얻지 못해서 로그인이 실행되지 않고 500 상태의 오류 발생

❓ 왜 이런 문제가 발생하지? - 가설 세우기

  1. 세션에 값을 정하는 setter에서 잘못된 값을 저장하나?

💡 이렇게 해서 해결! - 해결 방법 & 결과

1. 세션 setter 부분의 문제 ⭕️ -> setter에 들어가는 값을 수정
   세션 setter의 값을 출력해보니, 세션에 세션 상태에 고유 식별자 ID를 저장했어야 하는데
   코드를 잘못 보고 그냥 받아온 세션 값을 지정함 
   => setter부터 잘못되었으니, 잘못된 값을 get해서 승인 토큰 발급 도중 값이 동일하지 않아 null을 리턴했고, 순차적으로 null값이 넘어간 것
  • 원래 코드 -> 수정 코드
  • session.setAttribute(SESSION_STATE, session) -> session.setAttribute(SESSION_STATE, state)
    • SESSION_STATE는 지정된 값을 저장해놨던 값 변수명

📖 그래서 이런 습관을 얻었다! - 태도

당황하지 않고 실행 순서의 코드를 되집어보는 습관!

  • 처음 의심갔던 컨트롤러의 승인 토큰 받는 부분을 출력해 보고 콘솔을 확인하니 null값이 발생
  • 어디서부터 잘못된 것인지 코드의 실행 순서를 반대로 올라가보니, 경로 비교하는 if문에서 null을 리턴하는 것을 파악
  • 이렇게 코드를 실행 순서의 반대로 올라가니 생각보다 빨리 해결할 수 있었음
  • 이 경험을 통해서 코드의 실행 순서를 명확히 아는 것이 얼마나 중요한지 알게 됨!

📖 To Be Next - 앞으로 같은 문제를 만나면

이클립스의 디버깅을 활용

  • Debug 모드를 활용하여 break point를 먼저 찾아볼 것!
    • 멘토 분께서 알려주신 방법

3. 웹소켓 연결 도중 404 에러가 발생하여 연결 실패

❓ 문제가 뭐지? - 문제 정의

  • 웹소켓 연결에 지정한 경로 값을 찾지 못해서 계속 연결 실패

❓ 왜 이런 문제가 발생하지? - 가설 세우기

  1. handler의 endpoint로 지정한 경로의 문제인가?
  2. 컨트롤러의 매핑 값의 문제인가?
  3. 전송된 데이터 자체를 인식 못해 생기는 문제인가? * 이 부분은 개발자 도구를 이용해 어디서 에러가 나는지 확인해 보니 abstract-xhr.js 파일에서 payload 인식을 못하는 것을 파악

이렇게 하면 해결되려나? - 시도

1. endpoint로 지정한 경로의 문제 ❌ 
   웹소켓과 연결하는 클래스 파일의 endpoint와 웹소켓 객체 생성하는 메소드의 경로를 출력해서 확인해보니
   둘이 동일한 값이 나왔기에 그 부분의 문제는 아니었음.
   jstl로 상대 경로를 인식하지 못하는 건가 싶어서 절대 경로로 바꿔도 실패
   setAllowedOrigin 부분을 *로 지정해서 모든 값이 되도록 핸들링했는데, 이것도 실패
   => endpoint로 지정한 값과 웹소켓 객체 생성하는 경로가 달라 생기는 문제가 아니다!

2. 매핑한 값의 문제 ❌ 
   매핑 이름이 다르면 항상 이클립스 콘솔에 매핑을 찾을 수 없다는 에러가 뜨기에 아니라는 생각은 가지고 있었음
   그래도 값을 변경하여 실행해보았으나 결과는 똑같이 연결 실패
   일부러 매핑 값을 다르게 지정해 봤는데, 
   이때는 콘솔에 매핑한 것을 찾을 수 없다는 에러 발생하여 매핑 문제는 아니란 것을 확신
   => 매핑 값이 달라 생기는 문제가 아니다!

💡 이렇게 해서 해결! - 해결 방법 & 결과

1. 데이터 자체를 인식 못함 ⭕️ -> 프로젝트를 새로 만들어 실행 
개발자 도구를 통해 에러가 나는 부분을 확인하고 이 부분 해결을 위해 정보 검색
1-1. 첫번째 시도는 에러나는 부분을 주석 처리하고 실행
     다른 사람의 경우, 같은 에러를 봤을때 주석 처리하고 실행하면 에러 없이 된다는 글을 발견
     나도 같은 부분을 주석 처리 후 실행 -> 에러는 없었다
     그러나! 연결 자체가 안 되었음. 연결된다면 connect가 콘솔에 찍히도록 코드를 작성했지만,
     콘솔에 찍히지 않고 연결되지도 않아서 이건 정확한 해결 방법이 아니라고 파악
 1-2. 💡 새로운 프로젝트를 만들어서 웹소켓 연결 테스트를 진행하니 해결! 
     => 알아본 결과 sockjs-node에서 에러가 났는데, 이것은 서버 자체의 문제

📖 그래서 이런 지식, 습관을 얻었다! - 알게된 점, 태도

  • 개발 중 네트워크 환경 변경으로 서버가 액세스 소스 확인 못한 것
  • sockjs-node와 sockjs-client에서 넘어오는 값을 확인하면 어디의 오류인지 알 수 있다!
    • sockjs-node는 서버의 오류 / sockjs-client는 클라이언트의 오류
  • 너무 오래 잡고 있어도 득이 되지 않고, 정말 모르겠다면 새로운 프로젝트를 파서 해결해보는 것도 하나의 방법임을 깨달았다

4. 챗봇 연결 후 웰컴 메시지의 버튼 클릭 후 에러 발생하여 연결 해제

❓ 문제가 뭐지? - 문제 정의

  • 웹소켓 연결과 챗봇 API의 시나리오대로 웰컴메시지는 뜨지만, 그 후에 버튼을 누르면 에러가 발생해 웹소켓이 자동으로 연결 해제

❓ 왜 이런 문제가 발생하지? - 가설 세우기

  1. javascript 부분에 내가 close를 잘못 호출했나?
  2. API url을 요청했을 때 응답하는 코드가 200이 아닌가?
  3. 핸들러의 sendMessage 부분에 넘어오는 값이 없나?

이렇게 하면 해결되려나? - 시도

1. javascript에 잘못된 메소드 호출 문제 ❌
   동기 처리 시(페이지가 이동될 때)에 close 메소드가 호출되는 코드말고는 close 메소드를 호출하지 않음
   혹시나 해서 close 메소드 호출 부분 위에 실행 전 콘솔에 찍히도록 했는데, 콘솔에 찍힌 것이 없었음!
   => 자바스크립트 부분에서는 문제가 없었다!

2. API url 호출 시 응답하는 코드 문제 ❌
   API의 시크릿키가 문제인가 싶어 재발급 받고 변수 선언, 이 부분은 문제가 아니었음
   API url을 연결했을때 응답받는 코드를 출력해보니 200 정상 호출되었음
   => API 게이트웨이의 url과 시크릿 키에는 문제가 없었고, 호출 시 응답하는 코드도 문제 없었다!

💡 이렇게 해서 해결! - 해결 방법 & 결과

3. 핸들러의 send 메소드 호출 시 넘어오는 값이 없나? ⭕️ -> 핸들러에서 잘못된 임포트 수정
   내가 만든 클래스를 사용해야 정해진 값이 넘어올 수 있는데, 다른 라이브러리 안에 클래스를 임포트하여
   값이 null로 리턴되고, 그 null값이 그대로 응답한 리퀘스트에도 전달되어 
   보낼 값이 없어 웹소켓이 연결을 끊어버린 것
  • 해결 방법: 전달되는 값을 받는 VO에 잘못된 임포트를 삭제

📖 그래서 이런 습관을 얻었다! - 태도

임포트 부분도 잘 확인하자

  • 잘못된 클래스를 임포트한다면 내가 원한 값과 다른 값이 넘어오니 임포트할때 패키지 확인 잘해야 함 코드의 실행 순서를 명확히 알고 있는 것은 중요하다
  • 이번 트러블 슈팅도 코드의 실행 순서를 알고 있어서 빠르게 파악할 수 있었던 문제
  • 코드를 사용할때 무작정 붙여넣고, 공부하지 않는다면 어디서 에러가 발생하는지 찾느라 오랜 시간을 허비함
  • 그렇기 때문에 코드의 흐름을 명확히 파악하고 사용하는 것이 중요

About

맛집 공유 웹사이트 (멀티캠퍼스 파이널 팀프로젝트)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • Java 68.6%
  • CSS 28.5%
  • SCSS 1.5%
  • JavaScript 1.4%