2020-8-1 스프링 MVC(10) 예외처리핸들러와 전역컨트롤러

예외처리핸들러 @ExceptionHandler

특정 예외가 발생한 요청을 처리하는 핸들러

  • 지원하는 메서드 아규먼트

  • 지원하는 리턴 값

  • REST API의 경우 응답 본문에 에러 정보를 담아주고, 상태코드를 설정하려면 ResponseEntity를 이용하면 된다.

  • @Controller
    @SessionAttributes("event")
    public class EventController {
    
        @ExceptionHandler
        public String eventErrorHandler(EventException exception, Model model) {
            model.addAttribute("message", "event error");
            return "error";
        }
    
        @ExceptionHandler
        public String runTimeErrorHandler(RuntimeException exception, Model model) {
            model.addAttribute("message", "runtime error");
            return "error";
        }
    	...
        @GetMapping("events/form/name")
        public String eventFormName(Model model) {
            throw new EventException();
        }
    }
    
  • 가장 구체적인 에러를 처리한다. runtimeErrorHandler가 아닌 eventErrorHandler로 응답이 온다.

전역컨트롤러 : @(Rest)ControllerAdvice

  • 예외처리, 바인딩 설정, 모델 객체를 모든 컨트롤러 전반에 걸쳐 적용하고 싶은 경우에 사용한다.

    • @ExceptionHandler

    • @InitBinder

    • @ModelAttributes

    • @ControllerAdvice
      public class BaseController {
          @ExceptionHandler
          public String eventErrorHandler(EventException exception, Model model) {
              model.addAttribute("message", "event error");
              return "error";
          }
      
          @ExceptionHandler
          public String runTimeErrorHandler(RuntimeException exception, Model model) {
              model.addAttribute("message", "runtime error");
              return "error";
          }
      
          @InitBinder
          public void initEventBinder(WebDataBinder webDataBinder) {
              webDataBinder.setDisallowedFields("id");
              webDataBinder.addValidators(new EventValidator());
          }
      
          @ModelAttribute("categories")
          public List<String> categories(Model model) {
              return Arrays.asList("study", "seminar");
          }
      }
      
      
    • 위의 코드는 모든 컨트롤러에 다 적용이 된다.
  • 적용할 범위도 지정할 수 있다.(spring 4.0부터 적용됨)

    • 특정 어노테이션을 가지고 있는 컨트롤러에만 적용하기

    • 특정 패키지 이하의 컨트롤러에만 적용

      • @ControllerAdvice(assignableTypes = {EventController.class, EventApi.class})
        public class BaseController {
        }
        
    • 특정 클래스 타입에만 적용하기

참조

매개변수를 이용한 테스트

  • JunitParams를 사용.

    • @RunWith(JUnitParamsRunner.class)
      public class EventTest {
         // case1 파라미터만 전달
          @Test
          @Parameters({
                  "0, 0, true",
                  "100, 0, false",
                  "0, 100, false"
          })
          public void testFree(int basePrice, int maxPrice, boolean isFree) {
              // Given
              Event event = Event.builder()
                      .basePrice(basePrice)
                      .maxPrice(maxPrice)
                      .build();
              // When
              event.update();
              // Then
              assertThat(event.isFree()).isEqualTo(isFree);
          }
      
        // case2 메서드 이름으로 전달
       	@Test
        @Parameters(method = "parametersForOffline")
        public void offlineTest(String location, boolean isOffline) {
          // Given
          Event event = Event.builder()
            .location(location)
            .build();
          // When
          event.update();
          // Then
          System.out.println(event.getLocation());
          assertThat(event.isOffLine()).isEqualTo(isOffline);
        }
      
        private Object[] parametersForOffline() {
          return new Object[] {
            new Object[] {"강남", true},
            new Object[] {null, false},
            new Object[] {"      ", false}
          };
        }
      }
      
    • 테스트 메서드에 파라미터를 전달해서 각 테스트 경우에 대해서 중복을 제거할 수 있다.
Written on August 1, 2020