TIL (ToDay I LearNEd)/K P T (keeP, pRoBlem, Try) & 트러블슈팅

뉴스피드 프로젝트_트러블 슈팅.TIL

sooyeoneo 2024. 11. 21. 21:49

Java와 Spring을 배우고 본격적으로 Spring을 활용하여 협업 프로젝트를 시작했다. (2024.11.19~2024.11.25.)

이번 과제는 친구들의 가장 최근에 업데이트 된 게시물을 볼 수 있는 페이지가 담긴 뉴스피드를 만드는 것이다.

쉽게 이해하자면 facebook이나 Instagram 같은 SNS 라고 볼 수 있다.

 

참고 코드

  1. build.gradle 에 아래의 의존성을 추가해주세요.
  2. implementation 'at.favre.lib:bcrypt:0.10.2'
  3. config 패키지가 없다면 추가하고, 아래의 클래스를 추가해주세요.
  4. import at.favre.lib.crypto.bcrypt.BCrypt; import org.springframework.stereotype.Component; @Component public class PasswordEncoder { public String encode(String rawPassword) { return BCrypt.withDefaults().hashToString(BCrypt.MIN_COST, rawPassword.toCharArray()); } public boolean matches(String rawPassword, String encodedPassword) { BCrypt.Result result = BCrypt.verifyer().verify(rawPassword.toCharArray(), encodedPassword); return result.verified; } }

1. 프로필 관리

  • 프로필 조회 기능
    • 다른 사용자의 프로필 조회 시, 민감한 정보는 표시되지 않는다.
      • 민감한 정보가 무엇일지는 팀 내에서 결정한다.
  • 프로필 수정 기능
    • 로그인한 사용자는 본인의 사용자 정보를 수정할 수 있다.
    • 비밀번호 수정 조건
      • 비밀번호 수정 시, 본인 확인을 위해 현재 비밀번호를 입력하여 올바른 경우에만 수정할 수 있다.
      • 현재 비밀번호와 동일한 비밀번호로는 변경할 수 없다.
    • ⚠️ 예외처리
      • 비밀번호 수정 시, 본인 확인을 위해 입력한 현재 비밀번호가 일치하지 않은 경우
      • 비밀번호 형식이 올바르지 않은 경우
      • 현재 비밀번호와 동일한 비밀번호로 수정하는 경우

2. 뉴스피드 게시물 관리

  • 게시물 작성, 조회, 수정, 삭제 기능
    • 조건
      • 게시물 수정, 삭제는 작성자 본인만 처리할 수 있다.
    • ⚠️ 예외처리
      • 작성자가 아닌 다른 사용자가 게시물 수정, 삭제를 시도하는 경우
  • 뉴스피드 조회 기능
    • 기본 정렬은 생성일자 ****기준으로 내림차순 정렬한다.
    • 10개씩 페이지네이션하여, 각 페이지 당 뉴스피드 데이터가 10개씩 나오게 한다.

3. 사용자 인증

  • 회원가입 기능
    • 사용자 아이디
      • 사용자 아이디는 이메일 형식이어야 한다.
    • 비밀번호
      • Bcrypt로 인코딩합니다.
        • 암호화를 위한 PasswordEncoder를 직접 만들어 사용한다. 
      • 대소문자 포함 영문 + 숫자 + 특수문자를 최소 1글자씩 포함합니다.
      • 비밀번호는 최소 8글자 이상이어야 합니다.
    • ⚠️ 예외처리
      • 중복된 사용자 아이디로 가입하는 경우
      • 사용자 아이디 이메일과 비밀번호 형식이 올바르지 않은 경우

참고 코드

// build.gradle 에 아래의 의존성을 추가해주세요.
implementation 'at.favre.lib:bcrypt:0.10.2'


//config 패키지가 없다면 추가하고, 아래의 클래스를 추가해주세요.
import at.favre.lib.crypto.bcrypt.BCrypt;
import org.springframework.stereotype.Component;

@Component
public class PasswordEncoder {

    public String encode(String rawPassword) {
        return BCrypt.withDefaults().hashToString(BCrypt.MIN_COST, rawPassword.toCharArray());
    }

    public boolean matches(String rawPassword, String encodedPassword) {
        BCrypt.Result result = BCrypt.verifyer().verify(rawPassword.toCharArray(), encodedPassword);
        return result.verified;
    }
}
  • 회원탈퇴 기능
    • 조건
      • 탈퇴 처리 시 비밀번호를 확인한 후 일치할 때 탈퇴 처리합니다.
      • 탈퇴한 사용자의 아이디는 재사용할 수 없고, 복구할 수 없습니다.
    • ⚠️ 예외처리
      • 사용자 아이디와 비밀번호가 일치하지 않는 경우
      • 이미 탈퇴한 사용자 아이디인 경우
  • 회원 탈퇴 방식을 어떻게 처리할지 고민해보세요.

4. 친구 관리

  • 특정 사용자를 친구로 추가/삭제 할 수 있습니다.
  • 친구 기능이 구현되었다면, 뉴스피드에 친구의 최신 게시물들을 최신순으로 볼 수 있습니다.
    • ⚠️ 주의사항
      • 친구는 상대방의 수락 기능이 필요합니다. 만약 어렵다면, 관심 유저를 팔로우하는 기능으로 개발하셔도 좋습니다.

1. 업그레이드 뉴스피드

  • 정렬 기능
    • 수정일자 기준 최신순
    • 좋아요 많은 순
  • 기간별 검색 기능
    • 예) 2024.05.01 ~ 2024.05.27 동안 작성된 뉴스피드 게시물 검색

2. 댓글

  • 댓글 작성, 조회, 수정, 삭제
    • 사용자는 게시물에 댓글을 작성할 수 있고, 본인의 댓글은 수정 및 삭제를 할 수 있습니다.
    • 내용만 수정이 가능합니다.
    • 댓글 수정, 삭제는 댓글의 작성자 혹은 게시글의 작성자만 가능합니다.
  • 댓글 수정, 삭제는 댓글의 작성자 혹은 게시글의 작성자만 가능합니다.

3. 좋아요

  • 게시물 및 댓글 좋아요 / 좋아요 취소 기능
    • 사용자가 게시물이나 댓글에 좋아요를 남기거나 취소할 수 있습니다.
    • 본인이 작성한 게시물과 댓글에 좋아요를 남길 수 없습니다.
    • 같은 게시물에는 사용자당 한 번만 좋아요가 가능합니다.

 

🎯 트러블 슈팅

오류 1

로그인 서버 요청 오류 500 Internal Server Error (2024.11.21.)

수정된 코드를 Pull Request 한 뒤 원격저장소의 develop 브랜치를 로컬에 있는 develop 브랜치에 Pull 받고, 

다시 feature/login 브랜치로 이동한 뒤, develop 브랜치를 로컬의 login 브랜치에 Pull 받았다.

 

pull이 안 된 줄 알고 여러 번 pull을 했더니, 이미 받아졌다고 오류가 뜬다.

 

 

실행을 한 뒤에 포스트맨을 열어서 프로필 생성으로 회원가입을 해준 뒤에 로그인을 눌러줬더니, 500 Internal Server 에러가 뜬다.

500 에러

오류 메시지 : "'void jakarta.servlet.http.Cookie.setAttribute(java.lang.String, java.lang.String)'"

 

 

실행이 된 콘솔 화면을 열어보니 Error 가 뜨는 것을 확인할 수 있었다.

Servlet.service( ) for servlet [dispatcherServlet] in context with path....

 

 

원인을 파악하기 위해 local history에서 마지막으로 오류가 없었던 시점의 코드로 돌아가보았다.

 

확실하게 발견되지 않아서 추가로 디버깅을 진행하였다.

 

Postman에서 오류가 발생한 것일 수도 있어서, Intellij에서 test.http를 만들어 서버 요청을 테스트해보았다.

 

test.http에 추가한 코드

POST http://api/login
Content-Type: application/json

{
    "email" : "abcd@gmail.com",
    "password" : "Aaaa1111!",
}

 

 

서버 요청도 여전히 되지 않아서 다시 추가로 디버깅을 하였다. 

디버깅 한 결과 : 

build.gradle에 implementation 'jakarta.servlet:jakarta.servlet-api:5.0.0' 을 추가해서 오류가 발생한 것을 확인하였다.
(이전 코드 변경점에서는 이 코드가 없었다.)

 

현재 톰캣 10 version을 쓰는데,

위와 같이 jakarta.servlet:jakarta.servlet-api:5.x

 

즉, 5버전대를 사용하면 버전이 맞지 않아서 오류가 발생할 수 있다는 것을 알게 되었다.

현재 사용하는 SpringBoot는 3.x.x 버전이라 Jakrata 6을 지원하고 있다.
한마디로 6이 아닌 5로 implement 해서 발생한 문제였던 것이다.

 

참고 링크 : https://github.com/spring-projects/spring-boot/issues/33661

 

Spring Boot Test 3 NoClassDefFoundError: jakarta/servlet/ServletConnection · Issue #33661 · spring-projects/spring-boot

Spring Boot Web + Jetty (exclude Tomcat) + MockMvc 3.0.1 and jakarta-servlet.version 5.0.0 Error test on startup: java.lang.NoClassDefFoundError: jakarta/servlet/ServletConnection at org.springfram...

github.com

 

 

 

자, 이제 문제가 되는 implementation을 드레그하고...

 

 

깔끔하게 지워준다.

 

 

실행을 다시 해보면...

앗차... build.gradle을 수정한 후 rebuild를 하지 않았다...

 

반드시 build 변경 사항을 꼭! 반영해야한다. clean -> build

 

 

기존에 빌드를 안해서 발생한 문제에 대해서는...

빌드를 하게 되면 프로젝트 내부에 build 파일이 생성되어 사용되어진다.

clean -> build 를 안하면 기존의 것을 바라보는 경향이 있다고 한다.

 

 

다시 실행한 상태로 문제가 되었던 Postman 로그인 요청 화면으로 돌아간다.

 

 

 

다시 Send 로 요청을 보내주면, 200 OK 가 정상적으로 응답되는 것을 확인할 수 있다.

 

 

로그아웃도 정상적으로 작동하는 것을 확인하였다.

 

 

 

로그인 오류 해결 부분을 바로 commit한 후 push하였다.

오류 수정 후 pull request한 후 merge한 상태의 코드를 pull 받았다.

 

 

.

 

 

오류 2

서버 실행 기록이 캐시에 남아서 발생하는 실행 오류 (2024.11.22.)

 

몇 번의 pull request와 merge를 이어가서 pull 받아 여느 때처럼 코드를 실행했는데, 

에러가 뜨면서 실행이 되지 않았다.

 

에러 내용은 

Application Failed To Start

 

Description: 

Web server failed to start. Port 8080 was already in use.

 

Action :

Identify and stop the process that's listening on port 8080 or configure this application to listen on another port.

 

이미 8080 포트가 실행중이라서 어플리케이션 시작에 실패했다는 오류 메시지가 떴다.

 

그래서 바로 인텔리제이와 다른 앱의 서버들을 모두 종료 후에 재시작했는데,

역시나 같은 오류가 발생해서 원인을 제거하지 못하고 있었다.

 

오류 메시지 부분을 클릭하면 더 자세한 내용을 찾아볼 수 있다.

 

 

모든 서버를 종료해도 동일한 문제가 발생하면, 서버에 실행 기록이 캐시에 남아있어 오류가 난 것으로 추측되어진다.

 

팀원에게 도움을 요청했더니 터미널에 입력할 명령어를 받게 되었다!

lsof -i:8080 // 8080이 사용되고 있는 위치를 알려준다. 여기에 번호를 복사한다.
kill -9 <PID> // <> 안에 복사한 번호를 입력하고 엔터.

 

 

다시 한 번 lsof -i:8080를 입력해서 완전히 내역이 지워졌는지 확인한다.

비어있으면 잘 지워진 것!

 

덕분에 바로 실행이 잘 되어서 문제를 해결할 수 있었다.

 

 

 

 

 

 

TIL 11월 21일