SpringBootにおける共通機能の統一的処理手法

インターセプター

ログイン状態の確認を各APIで個別に実装する代わりに、リクエストを一元的に処理する方法としてインターセプターを利用します。インターセプターはSpringフレームワークが提供する機能で、リクエスト処理の前後で共通ロジックを実行できます。

インターセプターの基本概念

インターセプターはユーザーリクエストを横断的に処理するための仕組みです。リクエスト処理前後に任意の処理を追加でき、認証チェックやログ記録などの共通タスクに適しています。

カスタムインターセプターの実装

@Component
public class AuthInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) {
        HttpSession session = req.getSession(false);
        if (session != null && session.getAttribute("USER_AUTH") != null) {
            return true;
        }
        res.setStatus(HttpStatus.UNAUTHORIZED.value());
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest req, HttpServletResponse res, Object handler, ModelAndView mav) {
        // リクエスト処理後の追加操作
    }

    @Override
    public void afterCompletion(HttpServletRequest req, HttpServletResponse res, Object handler, Exception ex) {
        // レンダリング完了後の処理
    }
}

インターセプターの登録

@Configuration
public class WebConfiguration implements WebMvcConfigurer {

    @Autowired
    private AuthInterceptor authInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/auth/login", "/static/**");
    }
}

インターセプターの動作フロー

  1. preHandleメソッドでリクエスト前処理を実行
  2. trueを返すとController処理を継続
  3. Controller処理後にpostHandleを実行
  4. ビュー描画後にafterCompletionを実行

レスポンスデータの統一フォーマット

APIレスポンスを標準化するために@ControllerAdviceとResponseBodyAdviceを組み合わせます。

@ControllerAdvice
public class ResponseFormatter implements ResponseBodyAdvice<Object> {

    private final ObjectMapper jsonMapper = new ObjectMapper();

    @Override
    public boolean supports(MethodParameter rt, Class<?> ct) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter rt, 
            MediaType mt, Class<?> ct, ServerHttpRequest req, ServerHttpResponse res) {
            
        if (body instanceof ApiResult) {
            return body;
        }
        return new ApiResult(HttpStatus.OK.value(), "success", body);
    }
}

特殊な戻り値型への対応

文字列型の戻り値は明示的にJSON変換が必要です:

if (body instanceof String) {
    return jsonMapper.writeValueAsString(new ApiResult(body));
}

例外処理の統合

@ControllerAdviceと@ExceptionHandlerでアプリケーション全体の例外処理を一元化します。

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(NullPointerException.class)
    public ApiResult handleNullPointer(NullPointerException ex) {
        return new ApiResult(500, "null reference error");
    }

    @ExceptionHandler(Exception.class)
    public ApiResult handleGeneric(Exception ex) {
        return new ApiResult(500, "internal server error");
    }
}

主要な実装ポイント

  • インターセプターの登録時に適用パスを柔軟に設定可能
  • ResponseBodyAdviceで各種戻り値型を統一フォーマットに変換
  • 例外ハンドラで特定例外と汎用例外を階層的に処理

タグ: SpringBoot Interceptor ControllerAdvice ExceptionHandler DataFormat

8月10日 10:55 投稿