Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#5 [WEEK3] 기본/심화/생각 과제 제출 #12

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open

Conversation

yeseul106
Copy link
Collaborator

@yeseul106 yeseul106 commented Jun 1, 2023

SERVER PR

🙏 깃이 한번 꼬였어서 다시 제출하는 점 양해 부탁드립니다

💫 Related Issue

🐕 과제 구현 명세

✅ 기본 과제

  • 세미나 시간에 배운 코드 작성 완료 했습니다 !

  • 패키지 구조

    image
  • domain : Entity 등 도메인과 관련된 파일
  • infrastructure : repository 파일

✅ 심화 과제

  • User 테이블과 Post 테이블 ERD는 다음과 같습니다! 연관 관계를 조금 더 공부해보고자, 댓글 Post_Comment 테이블을 추가했습니다 !
    • 유저는 하나의 게시물에 여러 개의 댓글을 달 수 있다.
    • User - Post : 일대다 (One-to-Many) 관계
    • Post - Comment : 일대다 (One-to-Many) 관계
    • Comment - User : 다대일 (Many-to-One) 관계

      image
  • 📌 API 명세서

      domain method route info
      User POST /user/signup 유저 생성
      Post POST /post 게시물 생성
      Post GET /post/:postId 게시물 조회
      Comment GET /comment/:postId 특정 게시물의 댓글 목록 조회
      Comment POST /comment 특정 게시물의 댓글 생성

✅ 생각 과제

🐥 이런 점이 새로웠어요 / 어려웠어요

  • ☑️ 기본 과제: 기본 과제를 다시 한번 해보면서 저번 기수 node.js 쓸 때와는 또 컨트롤러 단에서 처리해주는 것이나, 계층 구조가 조금씩 달라져서 헷갈리는 부분도 있었던 것 같아요 ! 차분히 정리해나가겠습니다 !!
    • @NotNull , @NotEmpty , @NotBlank 의 차이가 헷갈렸는데 아래에 정리해두었습니다!
    • @Valid은 정확히 무엇을 검증하는 것일까 ?
      • 이 어노테이션이 붙은 객체 검증에 오류가 있다면 MethodArgumentNotValidException 예외가 발생하게 되고, 디스패처 서블릿에 기본으로 등록된 예외 리졸버(Exception Resolver)인 DefaultHandlerExceptionResolver에 의해 400 BadRequest 에러가 발생한다.
      • 이러한 이유로 @Valid기본적으로 컨트롤러에서만 동작하며 기본적으로 다른 계층에서는 검증이 되지 않는다. 다른 계층에서 파라미터를 검증하기 위해서는 @validated와 결합해야 한다.
      • JSR 표준 스펙은 다양한 제약 조건 어노테이션을 제공하고 있는데, 대표적인 어노테이션으로는 다음과 같은 것들이 있다
        • @NotNull: 해당 값이 null이 아닌지 검증함 ("", " "은 둘다 허용)
        • @notempty: 해당 값이 null이 아니고, 빈 스트링("") 아닌지 검증함(" "은 허용됨)
        • @notblank: 해당 값이 null이 아니고, 공백(""과 " " 모두 포함)이 아닌지 검증함
        • @AssertTrue: 해당 값이 true인지 검증함
        • @SiZe: 해당 값이 주어진 값 사이에 해당하는지 검증함(String, Collection, Map, Array에도 적용 가능)
        • @min: 해당 값이 주어진 값보다 작지 않은지 검증함
        • @max: 해당 값이 주어진 값보다 크지 않은지 검증함
        • @pattern: 해당 값이 주어진 패턴과 일치하는지 검증함
    • Controller 단에서 @ResponseStatus 어노테이션으로 각각 상태 코드에 맞춰 해당하는 response를 보내주는 것은 모두 성공에 대한 케이스만 작성해준다.
      • 실패 케이스에 대한 에러 처리는 @RestControllerAdvice 어노테이션을 사용해서 Advice 파일에서 처리를 해주도록 작성한다.
      • 이 부분에 대해서 각 api의 @ResponseStatus 의 상태 코드마다 분기 처리를 해주어야 하면 api 들 사이에서도 중복되는 코드가 많아서 동적으로 바인딩 해주어야 간편한게 아닌가라고 생각했지만, 에러 처리를 모두 Advice에서 해주므로 이 문제가 해결 된다는 것을 처음에 생각을 못했다. 기억하자!
    • ControllerExceptionAdvice 클래스 → handleMethodArgumentNotValidException에서 다음과 같은 코드를 작성하여 api 요청 시, Request body 필드에서 나는 각각의 오류를 처리해주었다.
      • FieldError fieldError = Objects.requireNonNull(e.getFieldError());
        • Objects.requireNonNull()은 Java 8에서 추가된 메서드로서, 지정된 객체가 null이 아닌지 확인하는 데 사용됩니다. 만약 객체가 null이라면 NullPointerException을 발생시킵니다.
        • e.getFieldError()는 스프링의 예외 처리에서 발생한 예외 객체(e)에서 필드 에러 정보(FieldError)를 가져오는 메서드입니다.
        • FieldError는 사용자가 제출한 폼 데이터나 요청 매개변수와 관련하여 발생한 검증 오류 정보를 나타냅니다. 폼 데이터의 유효성 검사를 수행하는 동안 에러가 발생하면, 이 객체를 통해 에러에 대한 자세한 정보를 얻을 수 있습니다.
      • Objects.requireNonNull()을 사용하여 e.getFieldError()의 결과가 null인지 확인한 뒤, fieldError 변수에 할당합니다. 만약 e.getFieldError()가 null이라면 NullPointerException이 발생합니다.
      • 이렇게 한번 fieldError 변수에 할당된 후에는 fieldError 객체를 통해 필드 에러와 관련된 정보를 활용할 수 있습니다. 예를 들어, 에러 메시지를 가져오거나 에러가 발생한 필드의 이름을 확인하는 등의 작업을 수행할 수 있습니다.
        • fieldError.getCode()
        • fieldError.getField()
        • fieldError.getDefaultMessage()
        • fieldError.getRejectedValue()

  • ☑️ 심화 과제: 연관 관계 매핑도 그렇고, 예외처리 로직도 그렇고 뭔가 둥둥 떠다니는 개념을 잡아가며 하느라 오래 걸린 것 같습니다 ! 이해하고 짜는 습관 아자아자🔥

    • 엔티티에 공통으로 들어가는 createdAt, updatedAt 필드를 가지는 BaseEntity 클래스를 생성해서 이 클래스를 다른 엔티티 클래스에서 상속 받도록 구현 했습니다.
      • @MappedSuperclass : 테이블과 관계 없고, 단순히 엔티티가 공통으로 사용하는 매핑 정보를 모으는 역할
        • 위의 어노테이션을 붙인다고 해서 상속 관계를 매핑하는 것이 아님 ! 헷갈릴 수 있으니 주의하자.
        • 이 어노테이션이 붙은 클래스는 엔티티가 아니고, 테이블과 매핑하는 클래스도 아니다. 단지 부모 클래스를 상속 받는 자식 클래스에 매핑 정보만 제공하는 것이다.
        • 직접 생성해서 사용할 일이 없으므로 추상 클래스를 권장한다.
        • @entity 클래스는 다른 엔티티나 @MappedSuperclass로 지정한 클래스만 상속 가능하다.
      • @EntityListeners(AuditingEntityListener.class) : Auditing을 적용할 엔티티에 해당 어노테이션을 붙여주면 된다.
        • 해당 어노테이션은 엔티티의 변화를 감지해서 엔티티와 매핑된 테이블의 데이터를 조작하는 것이다.
        • 이 어노테이션의 파라미터에 지금 AuditingEntityListener.class 라는 이벤트 리스너를 넣어줌으로서, Spring Data JPA에서 제공하는 이벤트 리스너로 엔티티의 영속, 수정 이벤트를 감지하는 역할을 한다.
    • 에러 처리는 봐도 봐도 너무 헷갈리네요… 다시 제대로 정리를 한번 해야겠습니다… 이번 과제를 하면서 에러를 처리하는 로직에 사용되는 클래스들은 아래와 같습니다 !
      • ErrorStatus

        • 에러 형식을 Enum으로 정의해서 각 케이스를 한 곳에 정리한다.
        • 응답에 내보낼 HttpStatus와 에러 메세지 message를 가진다.
      • CustomException

        • 전역으로 사용할 사용자 지정 에러이다. 기본적으로 제공되는 Exception 외에 사용한다.
        • RuntimeException 클래스를 상속 받아서 활용한다.
      • ResponseEntity

        • Spring Framework에서 제공하는 클래스 중 HttpEntity라는 클래스가 존재한다. 이것은 HTTP 요청 또는 응답에 해당하는 HttpHeaderHttpBody를 포함하는 클래스이다.
        public class HttpEntity<T> {
        
        	private final HttpHeaders headers;
        
        	@Nullable
        	private final T body;
        }
        • 이 HttpEntity 클래스를 상속받아 구현한 클래스가 RequestEntity, ResponseEntity 클래스이다. ResponseEntity는 사용자의 HttpRequest에 대한 응답 데이터를 포함하는 클래스이다. 따라서 HttpStatus, HttpHeaders, HttpBody를 포함한다.
        • 우리가 내려주는 ApiResponse는 위에 HttpBody에 들어가는 것이고, HttpStatus도 클라이언트와 정한 규칙에 맞게 커스텀해서 내려주어야한다. 따라서 CustomException이 발생 했을때 ResponseEntity 객체를 생성해서 내려주도록 구현한다.
          • 근데 이건 @ResponseStatus 로도 해결 가능 ! 이 어노테이션을 통해 HttpStatus 코드 값을 바꿀 수 있다.
          • 즉, ResponseEntity 클래스를 사용해서 controller에서 response 객체를 내려줄 수도 있고, 우리가 하는 것처럼 ApiResponse 클래스를 따로 구현해서 커스텀할 수도 있는 것이다 !
      • ControllerExceptionAdvice

        • 프로젝트 전역에서 발생하는 에러를 한번에 처리할 수 있도록 하는 Controller 클래스이다.
        • 프로젝트 전역에서 발생하는 에러를 모두 잡아서 한 곳에서 처리하고 싶다면 @ControllerAdvice 를 사용하는데, 현재 우리는 View를 사용하지 않고 단순히 Rest API 만을 사용하므로 @RestControllerAdvice 를 에러를 처리해주는 ControllerExceptionAdvice 클래스에 붙여준다.
        • 이 클래스 내부에서 또 각각 특정 Exception을 지정해서 별도로 처리해주기 위해서 각 에러를 처리하는 메서드에 @ExceptionHandler 를 붙여준다.
    • 🚨 ApiResponse 클래스에 @Getter를 붙이지 않으면 HttpMediaTypeNotAcceptableException: 에외가 터진다… 왜 그런지를 고민해보고 공부해봤다.
      • 현재 우리는 ApiResponse 라는 클래스를 만들어 일정한 response body를 내려주고 있다. 이 때 Jackson 라이브러리를 통해서 객체 형태를 json 타입으로 바꿔준다.
      • Jackson은 내부적으로 ObjectMapping API를 사용하여 객체를 json으로 변환하고, Jackson 라이브러리는 Getter/Setter 프로퍼티를 기준으로 작동한다.
      • 그래서 결국 Getter를 붙여주지 않으면 내부적으로 Getter의 역할을 할 프로퍼티를 찾지 못해서 에러가 나는것이다 !
        • 만일 Getter/Setter 쓰지 않고 @JsonProperty , @JsonAutoDetect 를 사용해 멤버 변수를 프로퍼티로 지정할 수 있다고 한다.

@yeseul106 yeseul106 requested review from dev-Crayon and a team June 1, 2023 20:37
@yeseul106 yeseul106 self-assigned this Jun 1, 2023
@yeseul106 yeseul106 changed the title [3주차] 기본/심화/생각 과제 제출 # 5 [WEEK3] 기본/심화/생각 과제 제출 Jun 1, 2023
@yeseul106 yeseul106 changed the title # 5 [WEEK3] 기본/심화/생각 과제 제출 #5 [WEEK3] 기본/심화/생각 과제 제출 Jun 1, 2023
@sung-silver
Copy link
Member

심심해서 서버 사람들 깃허브 놀러다니다가 예슬언니꺼를 딱 들어왔는데.. 진짜 차기 파트장 생각은 없으신지 .. 정리도 잘해 글도 잘써 코드도 잘짜 못하는게 뭘까?

@yeseul106
Copy link
Collaborator Author

심심해서 서버 사람들 깃허브 놀러다니다가 예슬언니꺼를 딱 들어왔는데.. 진짜 차기 파트장 생각은 없으신지 .. 정리도 잘해 글도 잘써 코드도 잘짜 못하는게 뭘까?

네 ??!?!!? 무슨 소리세요오 ~~~~ 한없이 부족합니다 ㅠㅠ 잘 봐주셔서 감사해여 성은씨 알랍😘❤️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[3주차] 기본/심화/생각 과제 제출
2 participants