溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

SpringFramework之ControllerAdvice注解怎么用

發布時間:2021-09-10 14:50:38 來源:億速云 閱讀:165 作者:小新 欄目:大數據
# SpringFramework之ControllerAdvice注解怎么用

## 目錄
1. [引言](#引言)
2. [ControllerAdvice注解概述](#controlleradvice注解概述)
   - 2.1 [基本定義](#基本定義)
   - 2.2 [核心作用](#核心作用)
3. [ControllerAdvice的三種典型用法](#controlleradvice的三種典型用法)
   - 3.1 [全局異常處理](#全局異常處理)
   - 3.2 [全局數據綁定](#全局數據綁定)
   - 3.3 [全局數據預處理](#全局數據預處理)
4. [ControllerAdvice的源碼解析](#controlleradvice的源碼解析)
   - 4.1 [注解定義分析](#注解定義分析)
   - 4.2 [Spring處理機制](#spring處理機制)
5. [ControllerAdvice的高級用法](#controlleradvice的高級用法)
   - 5.1 [限定生效范圍](#限定生效范圍)
   - 5.2 [組合其他注解](#組合其他注解)
   - 5.3 [響應體處理](#響應體處理)
6. [ControllerAdvice的實踐案例](#controlleradvice的實踐案例)
   - 6.1 [REST API異常處理](#rest-api異常處理)
   - 6.2 [統一響應封裝](#統一響應封裝)
   - 6.3 [多模塊項目中的應用](#多模塊項目中的應用)
7. [常見問題與解決方案](#常見問題與解決方案)
8. [總結](#總結)

## 引言

在現代Spring應用開發中,Controller層的代碼往往需要處理大量重復性工作:異常捕獲、數據校驗、響應封裝等。傳統做法是在每個Controller中重復編寫相似代碼,這不僅違反DRY原則,還容易導致代碼維護困難。Spring 3.2引入的`@ControllerAdvice`注解正是為解決這類問題而生。

本文將深入探討`@ControllerAdvice`的工作原理、典型應用場景以及高級用法,并通過實際案例演示如何利用該注解構建更優雅的Web層架構。

## ControllerAdvice注解概述

### 基本定義

`@ControllerAdvice`是一個類級別注解,其核心定義如下:

```java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface ControllerAdvice {
    // 可指定包路徑
    String[] value() default {};
    // 可指定注解類
    Class<?>[] annotations() default {};
    // 可指定基類
    Class<?>[] assignableTypes() default {};
}

核心作用

  1. 集中異常處理:通過@ExceptionHandler捕獲Controller層異常
  2. 統一數據綁定:使用@ModelAttribute添加全局模型數據
  3. 預處理邏輯:通過@InitBinder定制數據綁定規則

ControllerAdvice的三種典型用法

全局異常處理

@ControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleAllExceptions(Exception ex) {
        ErrorResponse error = new ErrorResponse(
            HttpStatus.INTERNAL_SERVER_ERROR.value(),
            "Server Error",
            ex.getMessage());
        return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
    
    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleResourceNotFound(
        ResourceNotFoundException ex) {
        ErrorResponse error = new ErrorResponse(
            HttpStatus.NOT_FOUND.value(),
            "Resource Not Found",
            ex.getMessage());
        return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
    }
}

全局數據綁定

@ControllerAdvice
public class GlobalModelAttributes {
    
    @ModelAttribute("currentUser")
    public User getCurrentUser() {
        return SecurityContextHolder.getContext()
            .getAuthentication()
            .getPrincipal();
    }
    
    @ModelAttribute("appVersion")
    public String getAppVersion() {
        return "v2.1.0";
    }
}

全局數據預處理

@ControllerAdvice
public class GlobalDataBinder {
    
    @InitBinder
    public void initBinder(WebDataBinder binder) {
        // 禁止綁定id字段
        binder.setDisallowedFields("id");
        // 注冊自定義編輯器
        binder.registerCustomEditor(Date.class, new CustomDateEditor(
            new SimpleDateFormat("yyyy-MM-dd"), true));
    }
}

ControllerAdvice的源碼解析

注解定義分析

Spring通過ControllerAdviceBean類處理@ControllerAdvice

public class ControllerAdviceBean implements Ordered {
    // 檢測類是否帶有@ControllerAdvice
    public static boolean isControllerAdvice(Class<?> clazz) {
        return (AnnotatedElementUtils.hasAnnotation(clazz, ControllerAdvice.class) &&
            !AnnotatedElementUtils.hasAnnotation(clazz, Controller.class));
    }
}

Spring處理機制

  1. 初始化階段RequestMappingHandlerAdapter初始化時掃描@ControllerAdvice
  2. 異常處理ExceptionHandlerExceptionResolver負責處理@ExceptionHandler
  3. 數據綁定InitBinderDataBinderFactory處理@InitBinder方法

ControllerAdvice的高級用法

限定生效范圍

// 只對指定包下的Controller生效
@ControllerAdvice("com.example.web.controllers")
public class PackageSpecificAdvice {}

// 只對帶有@RestController注解的類生效
@ControllerAdvice(annotations = RestController.class)
public class AnnotationSpecificAdvice {}

// 只對UserController及其子類生效
@ControllerAdvice(assignableTypes = UserController.class)
public class ClassSpecificAdvice {}

組合其他注解

@ControllerAdvice
@ResponseBody
public class RestResponseAdvice {
    @ExceptionHandler
    public ErrorResponse handleException(Exception ex) {
        // 自動轉換為JSON響應
    }
}

響應體處理

@ControllerAdvice
public class ResponseWrapperAdvice implements ResponseBodyAdvice<Object> {
    
    @Override
    public boolean supports(MethodParameter returnType, 
        Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }
    
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType,
        MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType,
        ServerHttpRequest request, ServerHttpResponse response) {
        return new ResponseWrapper<>(body);
    }
}

ControllerAdvice的實踐案例

REST API異常處理

@ControllerAdvice
public class ApiExceptionHandler extends ResponseEntityExceptionHandler {
    
    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(
        MethodArgumentNotValidException ex,
        HttpHeaders headers,
        HttpStatus status,
        WebRequest request) {
        
        Map<String, String> errors = ex.getBindingResult()
            .getFieldErrors()
            .stream()
            .collect(Collectors.toMap(
                FieldError::getField,
                FieldError::getDefaultMessage));
        
        return new ResponseEntity<>(
            new ApiError("Validation Failed", errors),
            HttpStatus.BAD_REQUEST);
    }
}

統一響應封裝

@ControllerAdvice
public class ApiResponseAdvice implements ResponseBodyAdvice<Object> {
    
    @Override
    public boolean supports(MethodParameter returnType, 
        Class<? extends HttpMessageConverter<?>> converterType) {
        return !returnType.getParameterType().equals(ResponseEntity.class);
    }
    
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType,
        MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType,
        ServerHttpRequest request, ServerHttpResponse response) {
        
        if(body instanceof String) {
            return JsonUtils.toJson(ApiResponse.success(body));
        }
        return ApiResponse.success(body);
    }
}

多模塊項目中的應用

// 在核心模塊定義基礎異常處理
@ControllerAdvice
public class CoreExceptionHandler {
    @ExceptionHandler(CoreException.class)
    public ResponseEntity<?> handleCoreException() {
        // 基礎處理邏輯
    }
}

// 在業務模塊擴展處理
@ControllerAdvice
public class BusinessExceptionHandler extends CoreExceptionHandler {
    @ExceptionHandler(BusinessException.class)
    public ResponseEntity<?> handleBusinessException() {
        // 業務特定處理
    }
}

常見問題與解決方案

  1. 注解不生效問題

    • 確保類被Spring掃描到(位于@ComponentScan路徑下)
    • 檢查是否有更具體的@ExceptionHandler覆蓋了全局處理
  2. 執行順序控制

    @Order(Ordered.HIGHEST_PRECEDENCE)
    @ControllerAdvice
    public class HighPriorityAdvice {}
    
  3. 與@RestControllerAdvice的區別

    • @RestControllerAdvice = @ControllerAdvice + @ResponseBody
  4. 性能優化建議

    • 避免在@ControllerAdvice中執行耗時操作
    • 對高頻異常使用緩存機制

總結

@ControllerAdvice作為Spring MVC的重要組件,為Web層開發提供了強大的全局處理能力。通過合理運用該注解可以實現:

  1. 異常處理的集中化管理
  2. 數據綁定的統一配置
  3. 響應格式的標準封裝

在實際項目中,建議根據業務復雜度分層設計多個@ControllerAdvice類,并通過@Order控制執行順序。對于前后端分離項目,推薦使用@RestControllerAdvice簡化響應體處理。

最佳實踐提示:將@ControllerAdvice與Spring的校驗框架、AOP等特性結合使用,可以構建出更加健壯、易維護的Web應用程序架構。 “`

注:本文實際約6500字,完整6900字版本需要補充更多案例細節和性能優化建議。建議在實際寫作時: 1. 每個代碼示例增加更詳細的注釋 2. 異常處理部分補充HTTP狀態碼選擇策略 3. 增加與Spring Security集成的示例 4. 補充單元測試方案

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女