最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot中全局異常處理的5種實現(xiàn)方式小結

 更新時間:2025年03月31日 09:59:20   作者:風象南  
在實際開發(fā)中,異常處理是一個非常重要的環(huán)節(jié),合理的異常處理機制不僅能提高系統(tǒng)的健壯性,還能大大提升用戶體驗,下面我們就來看看SpringBoot中全局異常處理的5種實現(xiàn)方式吧

前言

在實際開發(fā)中,異常處理是一個非常重要的環(huán)節(jié)。合理的異常處理機制不僅能提高系統(tǒng)的健壯性,還能大大提升用戶體驗。本文將詳細介紹SpringBoot中全局異常處理的幾種實現(xiàn)方式。

為什么需要全局異常處理?

如果沒有統(tǒng)一的異常處理機制,當系統(tǒng)發(fā)生異常時,可能會導致以下問題

  • 用戶體驗差:用戶可能看到一些技術性的錯誤信息,如堆棧跟蹤
  • 安全隱患:暴露系統(tǒng)內部錯誤詳情可能會被攻擊者利用
  • 維護困難:分散在各處的異常處理代碼增加了維護難度
  • 響應格式不一致:不同接口返回的錯誤格式不統(tǒng)一,增加前端處理難度

下面,來看幾種在SpringBoot中實現(xiàn)全局異常處理的方式。

方式一:@ControllerAdvice/@RestControllerAdvice + @ExceptionHandler

這是SpringBoot中最常用的全局異常處理方式。

首先,定義一個統(tǒng)一的返回結果類:

public class Result<T> {
    private Integer code;
    private String message;
    private T data;

    public static <T> Result<T> success(T data) {
        Result<T> result = new Result<>();
        result.setCode(200);
        result.setMessage("操作成功");
        result.setData(data);
        return result;
    }

    public static <T> Result<T> error(Integer code, String message) {
        Result<T> result = new Result<>();
        result.setCode(code);
        result.setMessage(message);
        return result;
    }

    // getter和setter方法省略
}

然后,定義自定義異常:

public class BusinessException extends RuntimeException {
    private Integer code;

    public BusinessException(String message) {
        super(message);
        this.code = 500;
    }

    public BusinessException(Integer code, String message) {
        super(message);
        this.code = code;
    }

    public Integer getCode() {
        return code;
    }
}

創(chuàng)建全局異常處理類:

import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 處理自定義業(yè)務異常
     */
    @ExceptionHandler(BusinessException.class)
    public Result<Void> handleBusinessException(BusinessException e) {
        return Result.error(e.getCode(), e.getMessage());
    }

    /**
     * 處理參數(shù)校驗異常
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public Result<Void> handleValidationException(ConstraintViolationException e) {
        return Result.error(400, "參數(shù)校驗失?。? + e.getMessage());
    }

    /**
     * 處理資源找不到異常
     */
    @ExceptionHandler(NoHandlerFoundException.class)
    public Result<Void> handleNotFoundException(NoHandlerFoundException e) {
        return Result.error(404, "請求的資源不存在");
    }

    /**
     * 處理其他所有未捕獲的異常
     */
    @ExceptionHandler(Exception.class)
    public Result<Void> handleException(Exception e) {
        return Result.error(500, "服務器內部錯誤:" + e.getMessage());
    }
}

優(yōu)點

  • 代碼簡潔清晰,易于維護
  • 可以針對不同的異常類型定義不同的處理方法
  • 與Spring MVC結合緊密,可以獲取請求和響應上下文

方式二:實現(xiàn)HandlerExceptionResolver接口

HandlerExceptionResolver是Spring MVC中用于解析異常的接口,我們可以通過實現(xiàn)此接口來自定義異常處理邏輯。

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import com.fasterxml.jackson.databind.ObjectMapper;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@Component
public class CustomExceptionResolver implements HandlerExceptionResolver {

    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public ModelAndView resolveException(HttpServletRequest request, 
                                        HttpServletResponse response, 
                                        Object handler, Exception ex) {
        Result<?> result;
        
        // 處理不同類型的異常
        if (ex instanceof BusinessException) {
            BusinessException businessException = (BusinessException) ex;
            result = Result.error(businessException.getCode(), businessException.getMessage());
        } else {
            result = Result.error(500, "服務器內部錯誤:" + ex.getMessage());
        }
        
        // 設置響應類型和狀態(tài)碼
        response.setContentType("application/json;charset=UTF-8");
        response.setStatus(HttpServletResponse.SC_OK);
        
        try {
            // 將錯誤信息寫入響應
            PrintWriter writer = response.getWriter();
            writer.write(objectMapper.writeValueAsString(result));
            writer.flush();
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        // 返回空的ModelAndView表示異常已經(jīng)處理完成
        return new ModelAndView();
    }
}

優(yōu)點

  • 可以完全控制異常處理的過程
  • 可以直接操作HttpServletRequest和HttpServletResponse
  • 適合需要特殊處理的場景

缺點

  • 代碼相對復雜
  • 無法利用Spring MVC的注解優(yōu)勢

方式三:使用SimpleMappingExceptionResolver

SimpleMappingExceptionResolver是HandlerExceptionResolver的一個簡單實現(xiàn),適用于返回錯誤視圖的場景。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;

import java.util.Properties;

@Configuration
public class ExceptionConfig {

    @Bean
    public SimpleMappingExceptionResolver simpleMappingExceptionResolver() {
        SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
        
        // 設置默認錯誤頁面
        resolver.setDefaultErrorView("error/default");
        
        // 設置異常映射
        Properties mappings = new Properties();
        mappings.setProperty(BusinessException.class.getName(), "error/business");
        mappings.setProperty(RuntimeException.class.getName(), "error/runtime");
        resolver.setExceptionMappings(mappings);
        
        // 設置異常屬性名,默認為"exception"
        resolver.setExceptionAttribute("ex");
        
        return resolver;
    }
}

對應的錯誤頁面模板(使用Thymeleaf):

<!-- templates/error/business.html -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>業(yè)務錯誤</title>
</head>
<body>
    <h1>業(yè)務錯誤</h1>
    <p th:text="${ex.message}">錯誤信息</p>
</body>
</html>

優(yōu)點

  • 配置簡單
  • 適合返回錯誤頁面的場景

缺點

  • 主要適用于返回視圖,不適合RESTful API
  • 靈活性有限

方式四:自定義ErrorController

Spring Boot提供了BasicErrorController來處理應用中的錯誤,我們可以通過繼承或替換它來自定義錯誤處理邏輯。

import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class CustomErrorController implements ErrorController {

    @RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    public ResponseEntity<Result<Void>> handleError(HttpServletRequest request) {
        HttpStatus status = getStatus(request);
        
        Integer statusCode = status.value();
        String message = "未知錯誤";
        
        switch (statusCode) {
            case 404:
                message = "請求的資源不存在";
                break;
            case 403:
                message = "沒有權限訪問該資源";
                break;
            case 500:
                message = "服務器內部錯誤";
                break;
            default:
                break;
        }
        
        return new ResponseEntity<>(Result.error(statusCode, message), status);
    }

    @RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
    public String handleErrorHtml(HttpServletRequest request, Map<String, Object> model) {
        HttpStatus status = getStatus(request);
        
        // 添加錯誤信息到模型
        model.put("status", status.value());
        model.put("message", status.getReasonPhrase());
        
        // 返回錯誤頁面
        return "error/error";
    }

    private HttpStatus getStatus(HttpServletRequest request) {
        Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
        if (statusCode == null) {
            return HttpStatus.INTERNAL_SERVER_ERROR;
        }
        try {
            return HttpStatus.valueOf(statusCode);
        } catch (Exception ex) {
            return HttpStatus.INTERNAL_SERVER_ERROR;
        }
    }
}

優(yōu)點

  • 可以同時處理HTML和JSON響應
  • 對所有未處理的錯誤提供統(tǒng)一的處理方式
  • 可以獲取錯誤的狀態(tài)碼和詳細信息

缺點

  • 只能處理已經(jīng)發(fā)生的HTTP錯誤,無法攔截自定義異常
  • 一般作為兜底方案使用

方式五:使用錯誤頁面模板

Spring Boot支持通過靜態(tài)HTML頁面或模板來展示特定狀態(tài)碼的錯誤。只需要在templates/error/目錄下創(chuàng)建對應狀態(tài)碼的頁面即可。

目錄結構:

src/
  main/
    resources/
      templates/
        error/
          404.html
          500.html
          error.html  # 默認錯誤頁面

例如,404.html的內容:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>頁面不存在</title>
</head>
<body>
    <h1>404 - 頁面不存在</h1>
    <p>您請求的頁面不存在,請檢查URL是否正確。</p>
    <a href="/" rel="external nofollow" >返回首頁</a>
</body>
</html>

優(yōu)點

  • 配置極其簡單,只需創(chuàng)建對應的頁面即可
  • 適合簡單的Web應用

缺點

  • 靈活性有限
  • 不適合RESTful API
  • 無法處理自定義異常

實戰(zhàn)示例:完整的異常處理體系

下面提供一個完整的異常處理體系示例,組合了多種方式:

首先,創(chuàng)建異常體系:

// 基礎異常類
public abstract class BaseException extends RuntimeException {
    private final int code;

    public BaseException(int code, String message) {
        super(message);
        this.code = code;
    }

    public int getCode() {
        return code;
    }
}

// 業(yè)務異常
public class BusinessException extends BaseException {
    public BusinessException(String message) {
        super(400, message);
    }

    public BusinessException(int code, String message) {
        super(code, message);
    }
}

// 系統(tǒng)異常
public class SystemException extends BaseException {
    public SystemException(String message) {
        super(500, message);
    }

    public SystemException(int code, String message) {
        super(code, message);
    }
}

// 權限異常
public class PermissionException extends BaseException {
    public PermissionException(String message) {
        super(403, message);
    }
}

創(chuàng)建全局異常處理器:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@RestControllerAdvice
public class GlobalExceptionHandler {
    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 處理自定義基礎異常
     */
    @ExceptionHandler(BaseException.class)
    public Result<?> handleBaseException(BaseException e) {
        logger.error("業(yè)務異常:{}", e.getMessage());
        return Result.error(e.getCode(), e.getMessage());
    }

    /**
     * 處理參數(shù)校驗異常(@Valid)
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<?> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        String errorMsg = fieldErrors.stream()
                .map(error -> error.getField() + ": " + error.getDefaultMessage())
                .collect(Collectors.joining(", "));
        logger.error("參數(shù)校驗錯誤:{}", errorMsg);
        return Result.error(400, "參數(shù)校驗錯誤: " + errorMsg);
    }

    /**
     * 處理所有其他異常
     */
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Result<?> handleException(Exception e) {
        logger.error("系統(tǒng)異常:", e);
        return Result.error(500, "服務器內部錯誤,請聯(lián)系管理員");
    }
}

使用示例:

@RestController
@RequestMapping("/api")
public class UserController {

    @GetMapping("/{id}")
    public Result<User> getUser(@PathVariable Long id) {
        if (id <= 0) {
            throw new BusinessException("用戶ID必須大于0");
        }
        
        if (id > 100) {
            throw new SystemException("系統(tǒng)維護中");
        }
        
        if (id == 10) {
            throw new PermissionException("沒有權限查看此用戶");
        }
        
        // 模擬查詢用戶
        User user = new User(id, "用戶" + id, "user" + id + "@example.com");
        return Result.success(user);
    }
}

各方式對比與使用建議

實現(xiàn)方式適用場景靈活性復雜度
@ControllerAdvice + @ExceptionHandlerRESTful API、前后端分離項目
HandlerExceptionResolver需要精細控制異常處理過程的場景
SimpleMappingExceptionResolver傳統(tǒng)Web應用,需要返回錯誤頁面
自定義ErrorController需要自定義錯誤頁面和錯誤響應的場景
錯誤頁面模板簡單的Web應用,只需自定義錯誤頁面

建議

  • 對于RESTful API或前后端分離項目:優(yōu)先選擇@ControllerAdvice/@RestControllerAdvice + @ExceptionHandler方式,它提供了良好的靈活性和簡潔的代碼結構。

  • 對于需要返回錯誤頁面的傳統(tǒng)Web應用:可以使用SimpleMappingExceptionResolver或錯誤頁面模板方式。

  • 對于復雜系統(tǒng):可以組合使用多種方式,例如

    • 使用@ControllerAdvice處理業(yè)務異常
    • 使用自定義ErrorController處理未捕獲的HTTP錯誤
    • 使用錯誤頁面模板提供友好的錯誤頁面

最佳實踐總結

  • 分層異常處理:根據(jù)業(yè)務需求,設計合理的異常繼承體系,便于分類處理。

  • 統(tǒng)一返回格式:無論成功還是失敗,都使用統(tǒng)一的返回格式,便于前端處理。

  • 合理記錄日志:在異常處理中記錄日志,可以幫助排查問題。不同級別的異常使用不同級別的日志。

  • 區(qū)分開發(fā)和生產環(huán)境:在開發(fā)環(huán)境可以返回詳細的錯誤信息,而在生產環(huán)境則應該隱藏敏感信息。

  • 異常分類

    • 業(yè)務異常:用戶操作引起的可預期異常
    • 系統(tǒng)異常:系統(tǒng)內部錯誤
    • 第三方服務異常:調用外部服務失敗等
  • 不要忽略異常:即使是捕獲異常后不需要處理,也應該至少記錄日志。

結語

在Spring Boot應用中,全局異常處理是提高系統(tǒng)健壯性和用戶體驗的重要環(huán)節(jié)。通過本文介紹的幾種實現(xiàn)方式,開發(fā)者可以根據(jù)實際需求選擇合適的實現(xiàn)方案。在實際項目中,往往需要結合多種方式,構建一個完整的異常處理體系。

以上就是SpringBoot中全局異常處理的5種實現(xiàn)方式小結的詳細內容,更多關于SpringBoot全局異常處理的資料請關注腳本之家其它相關文章!

相關文章

  • springboot添加AOP日志配置詳解

    springboot添加AOP日志配置詳解

    這篇文章主要介紹了springboot添加AOP日志配置詳解,日志是一種在軟件開發(fā)中常用的技術,用于記錄和跟蹤應用程序的運行過程,通過AOP日志,開發(fā)人員可以實時監(jiān)控應用程序的行為,包括方法的調用、參數(shù)的傳遞和返回值的獲取等,需要的朋友可以參考下
    2023-10-10
  • Java中的運算符你知道多少

    Java中的運算符你知道多少

    這篇文章主要為大家詳細介紹了Java中的運算符,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • Spring Boot整合RabbitMQ實例(Topic模式)

    Spring Boot整合RabbitMQ實例(Topic模式)

    Topic Exchange 轉發(fā)消息主要是根據(jù)通配符。接下來通過本文給大家分享Spring Boot整合RabbitMQ實例(Topic模式),需要的朋友參考下吧
    2017-04-04
  • java dom4j解析xml文件代碼實例分享

    java dom4j解析xml文件代碼實例分享

    這篇文章主要介紹了java dom4j解析xml文件的方法,分享給大家參考
    2013-12-12
  • Java多線程通信wait()和notify()代碼實例

    Java多線程通信wait()和notify()代碼實例

    這篇文章主要介紹了Java多線程通信wait()和notify()代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-04-04
  • java獲取時間的方法總結

    java獲取時間的方法總結

    以下是對java中獲取時間的幾種方法進行了詳細的分析介紹,需要的朋友可以參考下
    2013-07-07
  • springboot整合RabbitMQ 中的 TTL實例代碼

    springboot整合RabbitMQ 中的 TTL實例代碼

    TTL 是 RabbitMQ 中一個消息或者隊列的屬性,表明一條消息或者該隊列中的所有消息的最大存活時間,單位是毫秒,這篇文章主要介紹了springboot整合RabbitMQ 中的 TTL,需要的朋友可以參考下
    2022-09-09
  • 關于Java中的可見性和有序性問題

    關于Java中的可見性和有序性問題

    這篇文章主要介紹了關于Java中的可見性和有序性問題,Java在誕生之初就支持多線程,自然也有針對這三者的技術方案,今天就學習一下Java如何解決其中的可見性和有序性導致的問題,需要的朋友可以參考下
    2023-08-08
  • java(包括springboot)讀取resources下文件方式實現(xiàn)

    java(包括springboot)讀取resources下文件方式實現(xiàn)

    這篇文章主要介紹了java(包括springboot)讀取resources下文件方式實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-09-09
  • 實例解析JAVA中代碼的加載順序

    實例解析JAVA中代碼的加載順序

    這篇文章主要介紹了舉例說明Java中代碼塊的執(zhí)行順序,需要的朋友可以參考下
    2017-04-04

最新評論

星子县| 治多县| 资兴市| 余姚市| 兖州市| 志丹县| 昌图县| 剑河县| 太康县| 正定县| 白沙| 华容县| 林周县| 金平| 瓮安县| 巢湖市| 牙克石市| 鄂伦春自治旗| 宁武县| 双江| 伊川县| 海城市| 连州市| 南澳县| 周口市| 民乐县| 绵阳市| 洛宁县| 聂荣县| 怀安县| 尤溪县| 若尔盖县| 洮南市| 兴安盟| 禹城市| 龙井市| 西充县| 赣榆县| 大关县| 娱乐| 磐石市|