일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 자료구조와함께배우는알고리즘입문
- 리눅스
- iterator
- ㅒ
- 코드로배우는스프링웹프로젝트
- 코드로배우는스프링부트웹프로젝트
- 처음 만나는 AI수학 with Python
- 스프링 시큐리티
- 처음 만나는 AI 수학 with Python
- 데비안
- 목록처리
- network configuration
- /etc/network/interfaces
- 친절한SQL튜닝
- d
- Kernighan의 C언어 프로그래밍
- 알파회계
- 티스토리 쿠키 삭제
- baeldung
- 페이징
- 이터레이터
- 선형대수
- 구멍가게코딩단
- GIT
- 스프링부트핵심가이드
- 서버설정
- 네트워크 설정
- 자료구조와 함께 배우는 알고리즘 입문
- resttemplate
- 자바편
- Today
- Total
bright jazz music
blog03: 데이터 검증2 (ExceptionController, @ControllerAdvice) 본문
blog03: 데이터 검증2 (ExceptionController, @ControllerAdvice)
bright jazz music 2022. 12. 13. 08:38이전 포스팅처럼 에러를 처리한다면 아래와 같은 문제가 있다.
/*
* 1. 매번 메서드마다 검증해야함. 귀찮음. 실수 가능성+
* 2. 응답값을 HashMap으로 하지 말고 응답 클래스로 만든 것이 좋다.
* 3. 여러 개의 에러처리가 힘들다. 여러 개의 응답을 보내줘야 한다면 에러마다 만들어줘야 한다...
* 4. 반복작업을 피할 것
*
* @ControllerAdvice를 사용하여 이런 문제를 개선해 보자
* : 클래스에 이 어노테이션을 달면 개별 컨트롤러가 아니라 모든 컨트롤러에 대한 에러를 캐치한다.
*/
----------------------------------------------------------------
전역적인 에러를 처리할 임의의 컨트롤러 생성(여기서는 ExceptionController) ==>
생성한 컨트롤러(ExceptionController)에 @ControllerAdvice 어노테이션 부착 ==>
처리할 @ResponseStatus를 사용하여 처리할 status 설정
@ExceptionHandler(Exception.class)를 붙인 exceptionHandler() 메소드 사용
exceptionHandler() 메소드에서 처리
----------------------------------------------------------------
1. @ControllerAdvice를 적용하는 ExceptionController 생성
Exception을 처리하기 위한 클래스 생성. ( ExceptionController.java)
그리고 클래스에 @ControllerAdvice 적용
//ExceptionController.java
package com.endofma.blog.controller;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
@ControllerAdvice
public class ExceptionController {
@ResponseStatus(HttpStatus.OK) //여기선 일부러 200으로 설정하였다.
@ExceptionHandler(Exception.class)
public void exceptionHandler(){
System.out.println("하하하 ExceptionController.java");
}
}
//PostControllerTest.java
@WebMvcTest
class PostControllerTest {
@Autowired
private MockMvc mockMvc; ////Could not autowire. No beans of 'MockMvc' type found.
//...
//PostControllerTest.java
@Test
@DisplayName("/posts 요청시 title 값은 필수다")
void test2() throws Exception {
//expected
mockMvc.perform(post("/posts")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"title\": null, \"content\": \"내용입니다.\"}") //title 값을 빈 스트링으로 설정하였다.
)
.andExpect(status().isOk())
// .andExpect(content().string(""))
.andExpect(MockMvcResultMatchers.jsonPath("$.title").value("타이틀을 입력하세요!")) //json 검증. json 응답값의 필드 값이 value로 내려 오는지 여부 확인
.andDo(print());
}
}
그러나 걸리지 않는다. post메서드의 파라미터에 BindingResult가 존재하기 때문이다.
이를 제거하고, 그 밑의 코드들도 다 지워준다.
//PostController.java
@Slf4j
@RestController
public class PostController {
@PostMapping("/posts")
public Map<String, String> post(@RequestBody @Valid PostCreate params) {/
//파라미터에서 BindingResult 제거.
//이미 바인딩에서 에러 발생. 여기까지 오지 못함.
log.info("params={}", params.toString());
return Map.of();
}
}
다시 테스트 해본다.
그러면 아래와 같이 ExceptionController 클래스가 대신 에러를 처리하는 모습을 볼 수 있다. (하하하 ExceptionController.java)
또한 @ResponseStatus(HttpStatus.OK) 덕분에 status = 200으로 응답 받은 것을 확인할 수 있다.
2022-12-19 18:47:28.145 INFO 12392 --- [ Test worker] c.e.blog.controller.PostControllerTest : Started PostControllerTest in 2.665 seconds (JVM running for 5.297)
하하하 ExceptionController.java
MockHttpServletRequest:
HTTP Method = POST
Request URI = /posts
Parameters = {}
Headers = [Content-Type:"application/json;charset=UTF-8", Content-Length:"46"]
Body = {"title": null, "content": "내용입니다."}
Session Attrs = {}
Handler:
Type = com.endofma.blog.controller.PostController
Method = com.endofma.blog.controller.PostController#post(PostCreate)
Async:
Async started = false
Async result = null
Resolved Exception:
Type = org.springframework.web.bind.MethodArgumentNotValidException
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 200
Error message = null
Headers = []
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
No value at JSON path "$.title"
java.lang.AssertionError: No value at JSON path "$.title"
at org.springframework.test.util.JsonPathExpectationsHelper.evaluateJsonPath(JsonPathExpectationsHelper.java:304)
... 89 more
Disconnected from the target VM, address: 'localhost:58898', transport: 'socket'
PostControllerTest > /posts 요청시 title 값은 필수다 FAILED
java.lang.AssertionError at PostControllerTest.java:58
Caused by: java.lang.IllegalArgumentException at PostControllerTest.java:58
1 test completed, 1 failed
> Task :test FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':test'.
> There were failing tests. See the report at: file:///D:/personal/work/blog/build/reports/tests/test/index.html
* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 23s
4 actionable tasks: 2 executed, 2 up-to-date
2. 에러에 대한 응답을 json으로 반환하기
json으로 응답하기
//ExceptionController.java
@Slf4j
@ControllerAdvice
public class ExceptionController {
@ResponseStatus(HttpStatus.BAD_REQUEST) //400
@ResponseBody //응답을 json으로 보내기 위해 추가
@ExceptionHandler(MethodArgumentNotValidException.class)
public Map<String, String> invalidRequestHandler(MethodArgumentNotValidException e){
//MethodArgumentNotValidation
//e.getField()를 사용하기 위해서는 Exception이 아니라 MethodArgumentNotValidation을 사용해야 한다. 파라미터 변경 필요
FieldError fieldError = e.getFieldError();
String field = fieldError.getField();
String message = fieldError.getDefaultMessage();
Map<String, String > response = new HashMap<>();
response.put(field, message);
return response;
}
}
'Projects > blog' 카테고리의 다른 글
blog04: 작성글 저장1 - 게시글 저장 구현 (0) | 2022.12.28 |
---|---|
blog03: 데이터 검증3 (ExceptionController) (0) | 2022.12.27 |
blog03: 데이터 검증1 (@NotBlank, @Valid, BindingResult) (0) | 2022.12.12 |
blog02: POST로 데이터 전송(x-www-form-urlencoded, Json) (0) | 2022.12.12 |
blog01 : 프로젝트 생성/기본 RestController 생성/테스트 수행 (0) | 2022.12.10 |