본문 바로가기
공부/프로그래밍

[springboot] ControllerAdvice 응용해 return 꾸미기(HttpStatus 지정 포함)

by demonic_ 2020. 4. 11.
반응형

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

 

lemontia/controllerAdviceCustom

Contribute to lemontia/controllerAdviceCustom development by creating an account on GitHub.

github.com

 

반응형

댓글