亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

spring boot教程之全局處理異常封裝

 更新時(shí)間:2019年09月22日 11:45:44   作者:Purgeyao  
這篇文章主要給大家介紹了關(guān)于spring boot教程之全局處理異常封裝的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用spring boot具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧

1|1簡(jiǎn)介

在項(xiàng)目中經(jīng)常出現(xiàn)系統(tǒng)異常的情況,比如NullPointerException等等。如果默認(rèn)未處理的情況下,springboot會(huì)響應(yīng)默認(rèn)的錯(cuò)誤提示,這樣對(duì)用戶體驗(yàn)不是友好,系統(tǒng)層面的錯(cuò)誤,用戶不能感知到,即使為500的錯(cuò)誤,可以給用戶提示一個(gè)類似服務(wù)器開小差的友好提示等。

在微服務(wù)里,每個(gè)服務(wù)中都會(huì)有異常情況,幾乎所有服務(wù)的默認(rèn)異常處理配置一致,導(dǎo)致很多重復(fù)編碼,我們將這些重復(fù)默認(rèn)異常處理可以抽出一個(gè)公共starter包,各個(gè)服務(wù)依賴即可,定制化異常處理在各個(gè)模塊里開發(fā)。

1|2配置

unified-dispose-springboot-starter

這個(gè)模塊里包含異常處理以及全局返回封裝等功能,下面。

完整目錄結(jié)構(gòu)如下:

├── pom.xml
├── src
│   ├── main
│   │   ├── java
│   │   │   └── com
│   │   │       └── purgetiem
│   │   │           └── starter
│   │   │               └── dispose
│   │   │                   ├── GlobalDefaultConfiguration.java
│   │   │                   ├── GlobalDefaultProperties.java
│   │   │                   ├── Interceptors.java
│   │   │                   ├── Result.java
│   │   │                   ├── advice
│   │   │                   │   └── CommonResponseDataAdvice.java
│   │   │                   ├── annotation
│   │   │                   │   ├── EnableGlobalDispose.java
│   │   │                   │   └── IgnorReponseAdvice.java
│   │   │                   └── exception
│   │   │                       ├── GlobalDefaultExceptionHandler.java
│   │   │                       ├── category
│   │   │                       │   └── BusinessException.java
│   │   │                       └── error
│   │   │                           ├── CommonErrorCode.java
│   │   │                           └── details
│   │   │                               └── BusinessErrorCode.java
│   │   └── resources
│   │       ├── META-INF
│   │       │   └── spring.factories
│   │       └── dispose.properties
│   └── test
│       └── java

異常處理

@RestControllerAdvice 或者 @ControllerAdvice為spring的異常處理注解。

我們先創(chuàng)建GlobalDefaultExceptionHandler 全局異常處理類:

@RestControllerAdvice
public class GlobalDefaultExceptionHandler {

 private static final Logger log = LoggerFactory.getLogger(GlobalDefaultExceptionHandler.class);

 /**
 * NoHandlerFoundException 404 異常處理
 */
 @ExceptionHandler(value = NoHandlerFoundException.class)
 @ResponseStatus(HttpStatus.NOT_FOUND)
 public Result handlerNoHandlerFoundException(NoHandlerFoundException exception) {
 outPutErrorWarn(NoHandlerFoundException.class, CommonErrorCode.NOT_FOUND, exception);
 return Result.ofFail(CommonErrorCode.NOT_FOUND);
 }

 /**
 * HttpRequestMethodNotSupportedException 405 異常處理
 */
 @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
 public Result handlerHttpRequestMethodNotSupportedException(
  HttpRequestMethodNotSupportedException exception) {
 outPutErrorWarn(HttpRequestMethodNotSupportedException.class,
  CommonErrorCode.METHOD_NOT_ALLOWED, exception);
 return Result.ofFail(CommonErrorCode.METHOD_NOT_ALLOWED);
 }

 /**
 * HttpMediaTypeNotSupportedException 415 異常處理
 */
 @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
 public Result handlerHttpMediaTypeNotSupportedException(
  HttpMediaTypeNotSupportedException exception) {
 outPutErrorWarn(HttpMediaTypeNotSupportedException.class,
  CommonErrorCode.UNSUPPORTED_MEDIA_TYPE, exception);
 return Result.ofFail(CommonErrorCode.UNSUPPORTED_MEDIA_TYPE);
 }

 /**
 * Exception 類捕獲 500 異常處理
 */
 @ExceptionHandler(value = Exception.class)
 public Result handlerException(Exception e) {
 return ifDepthExceptionType(e);
 }

 /**
 * 二次深度檢查錯(cuò)誤類型
 */
 private Result ifDepthExceptionType(Throwable throwable) {
 Throwable cause = throwable.getCause();
 if (cause instanceof ClientException) {
  return handlerClientException((ClientException) cause);
 }
 if (cause instanceof FeignException) {
  return handlerFeignException((FeignException) cause);
 }
 outPutError(Exception.class, CommonErrorCode.EXCEPTION, throwable);
 return Result.ofFail(CommonErrorCode.EXCEPTION);
 }

 /**
 * FeignException 類捕獲
 */
 @ExceptionHandler(value = FeignException.class)
 public Result handlerFeignException(FeignException e) {
 outPutError(FeignException.class, CommonErrorCode.RPC_ERROR, e);
 return Result.ofFail(CommonErrorCode.RPC_ERROR);
 }

 /**
 * ClientException 類捕獲
 */
 @ExceptionHandler(value = ClientException.class)
 public Result handlerClientException(ClientException e) {
 outPutError(ClientException.class, CommonErrorCode.RPC_ERROR, e);
 return Result.ofFail(CommonErrorCode.RPC_ERROR);
 }

 /**
 * BusinessException 類捕獲
 */
 @ExceptionHandler(value = BusinessException.class)
 public Result handlerBusinessException(BusinessException e) {
 outPutError(BusinessException.class, CommonErrorCode.BUSINESS_ERROR, e);
 return Result.ofFail(e.getCode(), e.getMessage());
 }

 /**
 * HttpMessageNotReadableException 參數(shù)錯(cuò)誤異常
 */
 @ExceptionHandler(HttpMessageNotReadableException.class)
 public Result handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
 outPutError(HttpMessageNotReadableException.class, CommonErrorCode.PARAM_ERROR, e);
 String msg = String.format("%s : 錯(cuò)誤詳情( %s )", CommonErrorCode.PARAM_ERROR.getMessage(),
  e.getRootCause().getMessage());
 return Result.ofFail(CommonErrorCode.PARAM_ERROR.getCode(), msg);
 }

 /**
 * BindException 參數(shù)錯(cuò)誤異常
 */
 @ExceptionHandler(BindException.class)
 public Result handleMethodArgumentNotValidException(BindException e) {
 outPutError(BindException.class, CommonErrorCode.PARAM_ERROR, e);
 BindingResult bindingResult = e.getBindingResult();
 return getBindResultDTO(bindingResult);
 }

 private Result getBindResultDTO(BindingResult bindingResult) {
 List<FieldError> fieldErrors = bindingResult.getFieldErrors();
 if (log.isDebugEnabled()) {
  for (FieldError error : fieldErrors) {
  log.error("{} -> {}", error.getDefaultMessage(), error.getDefaultMessage());
  }
 }

 if (fieldErrors.isEmpty()) {
  log.error("validExceptionHandler error fieldErrors is empty");
  Result.ofFail(CommonErrorCode.BUSINESS_ERROR.getCode(), "");
 }

 return Result
  .ofFail(CommonErrorCode.PARAM_ERROR.getCode(), fieldErrors.get(0).getDefaultMessage());
 }

 public void outPutError(Class errorType, Enum secondaryErrorType, Throwable throwable) {
 log.error("[{}] {}: {}", errorType.getSimpleName(), secondaryErrorType, throwable.getMessage(),
  throwable);
 }

 public void outPutErrorWarn(Class errorType, Enum secondaryErrorType, Throwable throwable) {
 log.warn("[{}] {}: {}", errorType.getSimpleName(), secondaryErrorType, throwable.getMessage());
 }

}

大致內(nèi)容處理了一些項(xiàng)目常見的異常Exception,BindException參數(shù)異常等。

這里將默認(rèn)的404、405、415等默認(rèn)http狀態(tài)碼也重寫了。

重寫這個(gè)默認(rèn)的狀態(tài)碼需要配置throw-exception-if-no-handler-found以及add-mappings。

# 出現(xiàn)錯(cuò)誤時(shí), 直接拋出異常(便于異常統(tǒng)一處理,否則捕獲不到404)
spring.mvc.throw-exception-if-no-handler-found=true
# 是否開啟默認(rèn)的資源處理,默認(rèn)為true
spring.resources.add-mappings=false

ps: 請(qǐng)注意這兩個(gè)配置會(huì)將靜態(tài)資源忽略。

請(qǐng)產(chǎn)考WebMvcAutoConfiguration#addResourceHandlers

Exception為了防止未知的異常沒有防護(hù)到,默認(rèn)給用戶返回服務(wù)器開小差,請(qǐng)稍后再試等提示。

具體異常默認(rèn)會(huì)以小到大去匹配。

如果拋出BindException,自定義有BindException就會(huì)去這個(gè)處理器里處理。沒有就會(huì)走到它的父類去匹配,請(qǐng)參考java-異常體系。

其他已知異常可以自己用@ExceptionHandler注解進(jìn)行捕獲處理。

通用異常枚舉

為了避免異常值不好維護(hù),我們使用CommonErrorCode枚舉把常見的異常提示維護(hù)起來。

@Getter
public enum CommonErrorCode {

 /**
 * 404 Web 服務(wù)器找不到您所請(qǐng)求的文件或腳本。請(qǐng)檢查URL 以確保路徑正確。
 */
 NOT_FOUND("CLOUD-404",
  String.format("哎呀,無法找到這個(gè)資源啦(%s)", HttpStatus.NOT_FOUND.getReasonPhrase())),

 /**
 * 405 對(duì)于請(qǐng)求所標(biāo)識(shí)的資源,不允許使用請(qǐng)求行中所指定的方法。請(qǐng)確保為所請(qǐng)求的資源設(shè)置了正確的 MIME 類型。
 */
 METHOD_NOT_ALLOWED("CLOUD-405",
  String.format("請(qǐng)換個(gè)姿勢(shì)操作試試(%s)", HttpStatus.METHOD_NOT_ALLOWED.getReasonPhrase())),

 /**
 * 415 Unsupported Media Type
 */
 UNSUPPORTED_MEDIA_TYPE("CLOUD-415",
  String.format("呀,不支持該媒體類型(%s)", HttpStatus.UNSUPPORTED_MEDIA_TYPE.getReasonPhrase())),

 /**
 * 系統(tǒng)異常 500 服務(wù)器的內(nèi)部錯(cuò)誤
 */
 EXCEPTION("CLOUD-500", "服務(wù)器開小差,請(qǐng)稍后再試"),

 /**
 * 系統(tǒng)限流
 */
 TRAFFIC_LIMITING("CLOUD-429", "哎呀,網(wǎng)絡(luò)擁擠請(qǐng)稍后再試試"),

 /**
 * 服務(wù)調(diào)用異常
 */
 API_GATEWAY_ERROR("API-9999", "網(wǎng)絡(luò)繁忙,請(qǐng)稍后再試"),

 /**
 * 參數(shù)錯(cuò)誤
 */
 PARAM_ERROR("CLOUD-100", "參數(shù)錯(cuò)誤"),

 /**
 * 業(yè)務(wù)異常
 */
 BUSINESS_ERROR("CLOUD-400", "業(yè)務(wù)異常"),

 /**
 * rpc調(diào)用異常
 */
 RPC_ERROR("RPC-510", "呀,網(wǎng)絡(luò)出問題啦!");

 private String code;

 private String message;

 CommonErrorCode(String code, String message) {
 this.code = code;
 this.message = message;
 }
}

其實(shí)starter包中不建議使用@Getter等lombok注解,防止他人未使用lombok依賴該項(xiàng)目出現(xiàn)問題。

通用業(yè)務(wù)異常

這兩個(gè)類完成基本可以正常使用異常攔截了,不過為了業(yè)務(wù)方便,我們創(chuàng)建一個(gè)一般通用的業(yè)務(wù)異常。

BusinessException繼承RuntimeException即可。

@Getter
public class BusinessException extends RuntimeException {

 private String code;
 private boolean isShowMsg = true;

 /**
 * 使用枚舉傳參
 *
 * @param errorCode 異常枚舉
 */
 public BusinessException(BusinessErrorCode errorCode) {
 super(errorCode.getMessage());
 this.code = errorCode.getCode();
 }

 /**
 * 使用自定義消息
 *
 * @param code 值
 * @param msg 詳情
 */
 public BusinessException(String code, String msg) {
 super(msg);
 this.code = code;
 }

}

將BusinessException加入GlobalDefaultExceptionHandler全局異常攔截。

/**
 * BusinessException 類捕獲
 */
@ExceptionHandler(value = BusinessException.class)
public Result handlerBusinessException(BusinessException e) {
 outPutError(BusinessException.class, CommonErrorCode.BUSINESS_ERROR, e);
 return Result.ofFail(e.getCode(), e.getMessage());
}

程序主動(dòng)拋出異??梢酝ㄟ^下面方式:

throw new BusinessException(BusinessErrorCode.BUSINESS_ERROR);
// 或者
throw new BusinessException("CLOUD800","沒有多余的庫(kù)存");

通常不建議直接拋出通用的BusinessException異常,應(yīng)當(dāng)在對(duì)應(yīng)的模塊里添加對(duì)應(yīng)的領(lǐng)域的異常處理類以及對(duì)應(yīng)的枚舉錯(cuò)誤類型。

如會(huì)員模塊:

創(chuàng)建UserException異常類、UserErrorCode枚舉、以及UserExceptionHandler統(tǒng)一攔截類。

UserException:

@Data
public class UserException extends RuntimeException {

 private String code;
 private boolean isShowMsg = true;

 /**
 * 使用枚舉傳參
 *
 * @param errorCode 異常枚舉
 */
 public UserException(UserErrorCode errorCode) {
 super(errorCode.getMessage());
 this.setCode(errorCode.getCode());
 }

}

UserErrorCode:

@Getter
public enum UserErrorCode {
 /**
  * 權(quán)限異常
  */
 NOT_PERMISSIONS("CLOUD401","您沒有操作權(quán)限"),
 ;

 private String code;

 private String message;

 CommonErrorCode(String code, String message) {
  this.code = code;
  this.message = message;
 }
}

UserExceptionHandler:

@Slf4j
@RestControllerAdvice
public class UserExceptionHandler {

 /**
 * UserException 類捕獲
 */
 @ExceptionHandler(value = UserException.class)
 public Result handler(UserException e) {
 log.error(e.getMessage(), e);
 return Result.ofFail(e.getCode(), e.getMessage());
 }

}

最后業(yè)務(wù)使用如下:

// 判斷是否有權(quán)限拋出異常
throw new UserException(UserErrorCode.NOT_PERMISSIONS);

加入spring容器

最后將GlobalDefaultExceptionHandler以bean的方式注入spring容器。

@Configuration
@EnableConfigurationProperties(GlobalDefaultProperties.class)
@PropertySource(value = "classpath:dispose.properties", encoding = "UTF-8")
public class GlobalDefaultConfiguration {

 @Bean
 public GlobalDefaultExceptionHandler globalDefaultExceptionHandler() {
 return new GlobalDefaultExceptionHandler();
 }

 @Bean
 public CommonResponseDataAdvice commonResponseDataAdvice(GlobalDefaultProperties globalDefaultProperties){
 return new CommonResponseDataAdvice(globalDefaultProperties);
 }

}

將GlobalDefaultConfiguration在resources/META-INF/spring.factories文件下加載。

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
 com.purgetime.starter.dispose.GlobalDefaultConfiguration

不過我們這次使用注解方式開啟。其他項(xiàng)目依賴包后,需要添加@EnableGlobalDispose才可以將全局?jǐn)r截的特性開啟。

將剛剛創(chuàng)建的spring.factories注釋掉,創(chuàng)建EnableGlobalDispose注解。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(GlobalDefaultConfiguration.class)
public @interface EnableGlobalDispose {

}

使用@Import將GlobalDefaultConfiguration導(dǎo)入即可。

使用

添加依賴

<dependency>
 <groupId>io.deepblueai</groupId>
 <artifactId>unified-dispose-deepblueai-starter</artifactId>
 <version>0.1.0.RELEASE</version>
</dependency>

啟動(dòng)類開啟@EnableGlobalDispose注解即可。

1|3總結(jié)

項(xiàng)目里很多重復(fù)的code,我們可以通過一定的方式去簡(jiǎn)化,以達(dá)到一定目的減少開發(fā)量。

示例代碼地址:unified-dispose-springboot

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • Java語言實(shí)現(xiàn)掃雷游戲(2)

    Java語言實(shí)現(xiàn)掃雷游戲(2)

    這篇文章主要為大家詳細(xì)介紹了Java語言實(shí)現(xiàn)掃雷游戲第二部分代碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-04-04
  • Windows中Tomcat整合到Eclipse的圖文教程

    Windows中Tomcat整合到Eclipse的圖文教程

    下面小編就為大家?guī)硪黄猈indows中Tomcat整合到Eclipse的圖文教程。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-10-10
  • Spring boot自定義http反饋狀態(tài)碼詳解

    Spring boot自定義http反饋狀態(tài)碼詳解

    這篇文章主要給大家介紹了Spring boot自定義http反饋狀態(tài)碼的相關(guān)資料,文中介紹的非常詳細(xì),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面跟著小編一起來學(xué)習(xí)學(xué)習(xí)吧。
    2017-06-06
  • Java設(shè)計(jì)模式中的單一責(zé)任原則詳解

    Java設(shè)計(jì)模式中的單一責(zé)任原則詳解

    這篇文章主要介紹了Java設(shè)計(jì)模式中的單一責(zé)任原則詳解,應(yīng)該有且僅有一個(gè)原因引起類的變更,即單一指責(zé)原則要求一個(gè)借口或類只有一個(gè)原因引起變化,也就是一個(gè)接口或類只有一個(gè)職責(zé),它就負(fù)責(zé)一件事情,需要的朋友可以參考下
    2023-11-11
  • springboot集成mybatis?plus和dynamic-datasource注意事項(xiàng)說明

    springboot集成mybatis?plus和dynamic-datasource注意事項(xiàng)說明

    這篇文章主要介紹了springboot集成mybatis?plus和dynamic-datasource注意事項(xiàng)說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • java使用EditText控件時(shí)不自動(dòng)彈出輸入法的方法

    java使用EditText控件時(shí)不自動(dòng)彈出輸入法的方法

    這篇文章主要介紹了java使用EditText控件時(shí)不自動(dòng)彈出輸入法的方法,需要的朋友可以參考下
    2015-03-03
  • SpringData如何通過@Query注解支持JPA語句和原生SQL語句

    SpringData如何通過@Query注解支持JPA語句和原生SQL語句

    這篇文章主要介紹了SpringData如何通過@Query注解支持JPA語句和原生SQL語句,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • 聊聊@RequestParam,@PathParam,@PathVariable等注解的區(qū)別

    聊聊@RequestParam,@PathParam,@PathVariable等注解的區(qū)別

    這篇文章主要介紹了聊聊@RequestParam,@PathParam,@PathVariable等注解的區(qū)別,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • MyBatis中的接口代理機(jī)制及其使用方式

    MyBatis中的接口代理機(jī)制及其使用方式

    這篇文章主要介紹了MyBatis中的接口代理機(jī)制及其使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-06-06
  • Java定時(shí)任務(wù)的三種實(shí)現(xiàn)方式

    Java定時(shí)任務(wù)的三種實(shí)現(xiàn)方式

    這篇文章主要給大家介紹了關(guān)于Java定時(shí)任務(wù)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-01-01

最新評(píng)論