WEB으로 구성한 서버에서 Exception을 활용해서 에러코드를 핸들링하는 경우가 있는데, 이럴때 ControllerAdvice를 쓴다.
예를들어 Exception을 날리면 ControllerAdvice에서 캐치하고, 데이터를 가공해 리턴하는 것이다.
다음과 같이 설정을 해보자
@RestController
public class TestController {
@GetMapping("/test/get")
public String testGet(@RequestParam(value = "text") String text) {
System.out.println("/test/get text = " + text);
return "testGet";
}
}
GET방식으로 /test/get 을 호출하게 했고, text라는 파라미터를 필수로 받게 했다.(@RequestParam 은 required의 기본값이 true이기 때문에 값을 보내지 않으면 400 에러(Bad Request)를 반환한다. 실제로 테스트를 작성해서 테스트해보았다.
테스트를 위해 RestTemplate 를 사용할 것이고 Bean을 다음과 같이 설정해준다.
@Configuration
public class OtherConfig {
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
아래는 테스트 작성
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class TestControllerTest {
@Autowired
TestRestTemplate testRestTemplate;
@Test
@DisplayName("get parameter에 필수값 체크")
void testGetTest() {
// given
String url = "/test/get";
// when
ResponseEntity<String> responseEntity = testRestTemplate.getForEntity(url, String.class);
// then
System.out.println("responseEntity.getStatusCodeValue() = " + responseEntity.getStatusCodeValue());
System.out.println("responseEntity.getBody() = " + responseEntity.getBody());
}
}
테스트결과 다음과같은 에러가 발생했다
status는 400, 그리고 body부분에 보면
timestamp => 시도한 시간
error => Bad Request
message => Required String parameter 'textt' is not present'
등 담겨서 리턴된다
에러를 핸들링하기 위해서 ControllerAdvice를 다음과 같이 설정해보자
@ControllerAdvice(basePackages = "kr.sample.demo")
public class ControllerAdviceHandler {
@ExceptionHandler(MissingServletRequestParameterException.class)
@ResponseBody
public Map missingServletRequestParameterException(MissingServletRequestParameterException ex) {
HashMap result = new HashMap<>();
result.put("code", "PARAMETER_ERROR");
result.put("message", ex.getMessage());
return result;
}
}
code에는 서버에서 설정한 커스텀한 코드를, 그리고 message에서는 Exception이 발생하고 생성된 message를 가져오게 했다. 참고로 메세지는 핸들러에 등록된 MissingServletRequestParameterException 안에 구성되어 있으며 그 안을 보면 다음과 같다.
public class MissingServletRequestParameterException extends ServletRequestBindingException {
...
@Override
public String getMessage() {
return "Required " + this.parameterType + " parameter '" + this.parameterName + "' is not present";
}
...
}
message 도 보기 편하게 담고싶다면 다음의 파라미터로 조합하면 된다
ex.getParameterName() => 문제가 된 파라미터 명을 호출
ex.getParameterType() => 문제가 된 파라미터의 자료형
그런데 문제는 이렇게 등록해두면 HttpStatus 가 200으로 리턴된다는 것이다. ControllerAdvice가 캐치를 했지만 이후 정상으로 리턴했기 때문에 발생한 문제다.
만약 클라이언트에서 에러를 캐치하는 부분이 있을텐데 200으로 줄 경우 활용할 수 없을것이다. 혹은 이미 만들어진 서비스라면 클라이언트를 대폭 수정해야하는 일이 생길 수 있다. 그래서 HttpStatus 가 400으로 갈 수 있도록 설정해야 한다. 어노테이션 @ResponseStatus 를 추가하면 된다.
@ControllerAdvice(basePackages = "kr.sample.demo")
public class ControllerAdviceHandler {
@ExceptionHandler(MissingServletRequestParameterException.class)
@ResponseBody
@ResponseStatus(HttpStatus.BAD_REQUEST) // 이부분 추가
public Map missingServletRequestParameterException(MissingServletRequestParameterException ex) {
HashMap result = new HashMap<>();
result.put("code", "PARAMETER_ERROR");
result.put("message", ex.getMessage());
result.put("error", HttpStatus.BAD_REQUEST.getReasonPhrase()); // 여기도 추가
return result;
}
}
설정하면 Status가 400으로 리턴된다. 그리고 error에다가 HttpStatus의 상태값을 넣어주었다.
테스트를 실행하면 다음과 같이 원하는대로 리턴한다.
로그 확인
responseEntity.getStatusCodeValue() = 400
responseEntity.getBody() = {"code":"PARAMETER_ERROR","message":"Required String parameter 'text' is not present","error":"Bad Request"}
끝.
github 주소:
https://github.com/lemontia/controllerAdviceCustom
'공부 > 프로그래밍' 카테고리의 다른 글
[springboot] request 시 reject당하는 error log 확인 방법 (0) | 2020.04.28 |
---|---|
[aws,ec2,wordpress] 한달에 10달러로 워드프레스 설치하고 나만의 블로그 만들기 (0) | 2020.04.14 |
[mysql] REPEATABLE-READ에서 dead lock이 걸린 이유 (0) | 2020.04.09 |
[spring oauth2 ResourceServer] oauth2 에서 CORS 설정 테스트 (0) | 2020.04.04 |
[DBMS] 트랜잭션 격리수준 (isolation level) (0) | 2020.04.03 |
댓글