Spring異常の処理


作業中に発生した異常処理方法を整理した.
  • BindingResult
    クライアントから入力した値と、その値を検証したときに検証した結果を含むクラス.
    @Valid宣言を使用してクライアントの入力値を検証し、結果をBindingResultに書き込みます.
     @PostMapping("/sign-in")
      public ResponseEntity<Object> login(@Valid @RequestBody LoginRequest loginRequest, BindingResult bindingResult) {
          if (bindingResult.hasErrors()) {
          	throw new CustomException("message");
          }
      }

  • @ControllerAdvice, @RestControllerAdvice
    ビジネス・ロジック・エンドの例外を統合処理する方法
    @RestControllerAdvice
    public class CustomExceptionAdvice {
    
        @ExceptionHandler
        public ResponseEntity<CustomErrorResponse> customExceptionHandler(CustomException e) {
            return ResponseEntity.status(HttpStatus.SOMETHING).body(customResponseBody);
        }
    }
    2つの方法の欠点はFilter側で処理できないことです
    そのためには、認証された例外処理またはAccessDeniedHandler(承認された例外処理)を使用します.

  • AuthenticationEntryPoint(認証の例外処理)
    @Component
    public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
    
      @Override
      public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
          response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // status code 지정
    
          response.setContentType("application/json;charset=utf-8"); // 반환 타입 지정 
    
          JSONObject jsonObject = new JSONObject();
          String msg = "로그인이 필요합니다";
          jsonObject.put("message", msg);
    
          PrintWriter out = response.getWriter();
          out.print(jsonObject);
      }
    }
    さらにSpringSecurityではAuthenticationEntryPointを指定する必要があります
    次にSpring Security構成例コードを示します
    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
      @Override
      protected void configure(HttpSecurity http) throws Exception {
          http.anyRequest().authenticated()
              .and().exceptionHandling()
              .authenticationEntryPoint(new CustomAuthenticationEntryPoint());
      }

  • AccessDeniedHandler(承認された処理)
    ほとんどAuthenticationEntryPointメソッドと似ています
    @Component
    public class CustomAccessDeniedHandler implements AccessDeniedHandler {
      @Override
      public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {
          ExceptionCode exceptionCode;
          exceptionCode = ExceptionCode.PERMISSION_DENIED;
          setResponse(response, exceptionCode);
    
      }
    
      private void setResponse(HttpServletResponse response, ExceptionCode exceptionCode) throws IOException {
          response.setContentType("application/json;charset=UTF-8");
          response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
    
          JSONObject responseJson = new JSONObject();
          responseJson.put("message", exceptionCode.getMessage());
          responseJson.put("code", exceptionCode.getCode());
    
          response.getWriter().print(responseJson);
      }
    }
    次の行をHTTPビルダーに追加します.
    .accessDeniedHandler(new CustomAccessDeniedHandler())