관리 메뉴

bright jazz music

blog12: 예외처리2 본문

Projects/blog

blog12: 예외처리2

bright jazz music 2023. 1. 13. 07:43

예외처리 1에서는 정상적이지 않은 입력값이 들어갔을 경우의 예외처리를 구성하였다.

 

이번에는 PostController에서 발생할 수 있는 오류에 대한 예외처리를 만들고 테스트한다.

 

우선 단건 조회부터.

//PostService.java

//...

//단건 조회
    public PostResponse get(Long id) {

        Post post = postRepository.findById(id)
//                .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 글입니다.")); //있으면 post반환 없으면 에러 반환
//                .orElseThrow(() -> new PostNotFound());
                .orElseThrow(PostNotFound::new); //위와 같은 표현
        //또한 IllegalArgumentException과 같은 자바 기본제공 에러들은 우리의 에러를 명확히 표현해 주지는 못함.
        // 이렇게 처리해주면 굳이 test에서 전부 메시지를 확인할 필요가 없다. 이 에러가 발생했다면 글을 찾지 못했다는 뜻이기 때문이다.

        //응답 클래스를 분리
        return PostResponse.builder()
                .id(post.getId())
                .title(post.getTitle())
                .content(post.getContent())
                .build();

    }

 

위에서 보듯이 현재 단건조회에 대한 입력 오류는 PostNotFound 클래스를 통해 메시지를 반환해야 한다.

현재 예외는 내가 만든 ExceptionController(@ControllerAdvice부착)가 해결하고 있다.

따라서 ExceptionController에서 PostNotFound를 활용해 에러를 반환할 수 있도록 해줘야 한다.

 

이러한 처리를 하지 않은 상태에서 블라우저를 사용하여 글을 단건 조회하면(e.g. localhost:8080/posts/1), 500에러가 떨어진다.

 

ExceptionController에 PostNotFound 처리 추가하기

//ExceptionController.java

package com.endofma.blog.controller;

import com.endofma.blog.exception.PostNotFound;
import com.endofma.blog.response.ErrorResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;

@Slf4j
@ControllerAdvice
public class ExceptionController {

//...

    @ResponseBody
    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ExceptionHandler(PostNotFound.class)
    public ErrorResponse postNotFound(PostNotFound e) {
        ErrorResponse response = ErrorResponse.builder()
                .code("404")
                .message(e.getMessage()) //익셉션으로 받은 에러 메시지 "PostNotFound=>존재하지 않는 글입니다."
                .build();

        return response; //@Response바디가 붙었으므로 json으로 반환
    }


}

 

vaidation이라는 오타가 있었다. ErrorResponse.java에서 vaidation 필드명을  validation 필드로 변경해 주었다.

 

위에서는 validation 필드가 비어 있는데, 만약 빈 필드가 반환되는 것이 싫다면 해당 필드를 가진 클래스의 선언부 위에 아래의 코드를 추가해 주면 된다.

@JsonInclude(value = JsonInclude.Include.NON_EMPTY) //비어있지 않은 데이터만 보낸다.
public class ExampleClass{ //... }

그러나 비어 있는 상태 또한 하나의 의미이므로 빼지 않는 것을 선호하는 사람들도 있다. 이 예제에서는 뺴지 않고 진행한다.

 

 

edit()에 관한 컨트롤러 테스트 에러추

@Test
    @DisplayName("존재하지 않는 게시글 수정")
    void test10() throws Exception{
        //given
        ObjectMapper objectMapper = new ObjectMapper();
        PostEdit postEdit = PostEdit.builder()
                .title("블로그 수정")
                .content("부림동 ").build();

        //excepted
        mockMvc.perform(patch("/posts/{postId}", 1L)
                .contentType(APPLICATION_JSON)
                .content(objectMapper.writeValueAsString(postEdit)))
//                .andExpect(status().isOk())
                .andExpect(status().isNotFound())
                .andDo(print());
                
/*
MockHttpServletResponse:
           Status = 404
    Error message = null
          Headers = [Content-Type:"application/json"]
     Content type = application/json
             Body = {"code":"404","message":"PostNotFound=>존재하지 않는 글입니다.","validation":{}}
    Forwarded URL = null
   Redirected URL = null
          Cookies = []
*/

---

 

잘못된 요청에 대한 예외에 대응하기 위해 exception패키지에 InvalidRequest.java 클래스를 만들어 주었다.

//InvalidRequest.java
package com.endofma.blog.exception;

public class InvalidRequest extends RuntimeException {
    private static final String MESSAGE ="잘못된 요청입니다.";

    public InvalidRequest() {
        super(MESSAGE);
    }
    //글 작성 등에서 글 작성에서 @NotBlank와 같은 어노테이션으로
    //해결할 수 없을 경우 추가적인 방법이 필요할 때.
    //PostController의 post()에 보내는 요청의 제목에 "바보"라는 글자를 넣을 수 없다면.
}

 

 

 

컨트롤러에는 아래와 같이 적어주었다.

//PostController.java
@PostMapping("/posts")
    public void post(@RequestBody @Valid PostCreate request) {

        //PostController의 post()에 보내는 요청의 제목에 "바보"라는 글자를 넣을 수 없다면.
        if(request.getTitle().contains("바보")){
            throw new InvalidRequest();
        }

        postService.write(request);
//        return Map.of();
    }

테스트를 아래와 같이 작성하였다.

 

//PostControllerTest.java
@Test
@DisplayName("게시글 작성 시 제목에 '바보'는 포함될 수 없다.")
void test11() throws Exception{
    //given
    PostCreate request = PostCreate.builder()
            .title("나는 바보입니다.")
            .content("제이드빌.")
            .build();
    String json = objectMapper.writeValueAsString(request);
    
    //when
    mockMvc.perform(post("/posts")
            .contentType(APPLICATION_JSON)
            .content(json))
            .andExpect(status().isOk())
            .andDo(print());
   
}
/*
Request processing failed; nested exception is com.endofma.blog.exception.InvalidRequest: 잘못된 요청입니다.
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is com.endofma.blog.exception.InvalidRequest: 잘못된 요청입니다.
	at app//org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)
	at app//org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
*/

 

'Projects > blog' 카테고리의 다른 글

blog12: 예외처리 4  (0) 2023.01.14
blog12: 예외처리 3  (0) 2023.01.14
blog12: 예외처리1  (0) 2023.01.10
blog11: 게시글 삭제  (0) 2023.01.10
blog10: 게시글 수정 2 (오류수정, 보충)  (0) 2023.01.09
Comments