例外処理パッケージのグローバルspringboot
簡単な紹介
システムの異常が多い例えば、プロジェクトの場合、NullPointerException
その上、及び。デフォルトでは、未処理の場合、springboot
それはデフォルトのエラーメッセージに応答しますので、ユーザーエクスペリエンスが優しいシステムレベルのエラーではない、ユーザーが知覚できない、でもとして500
ミス、同様のユーザー促すことができる服务器开小差
やさしいヒントを。
マイクロサービスでは、各サービスが例外を持つことになり、ほぼすべての反復符号化の多くが得られ、デフォルトのサービス構成一貫した例外処理、の、我々はこれらのデフォルトの例外ハンドラを繰り返すことになります一般的に抽出することができstarter
、パッケージを、あなたは各サービスに頼ることができ、カスタマイズされました開発中の様々なモジュールでの例外処理。
コンフィギュレーション
統一-処分-springbootスターター
このモジュールは、グローバルなエラー処理が含まれており、以下、パッケージング機能を返します。
次のように完全なディレクトリ構造は次のとおりです。
├── 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
例外処理のアノテーション。
さんが作成してみましょう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);
}
/**
* 二次深度检查错误类型
*/
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 参数错误异常
*/
@ExceptionHandler(HttpMessageNotReadableException.class)
public Result handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
outPutError(HttpMessageNotReadableException.class, CommonErrorCode.PARAM_ERROR, e);
String msg = String.format("%s : 错误详情( %s )", CommonErrorCode.PARAM_ERROR.getMessage(),
e.getRootCause().getMessage());
return Result.ofFail(CommonErrorCode.PARAM_ERROR.getCode(), msg);
}
/**
* BindException 参数错误异常
*/
@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());
}
}
いくつかの一般的な例外を扱ったプロジェクトの一般的な内容はException
、BindException
障害をパラメータ。
ここではデフォルトで404
、405
、415
およびその他のデフォルトのhttp
ステータスコードも書き直されます。
このデフォルトのステータスコードを設定する必要がありますオーバーライドthrow-exception-if-no-handler-found
にもadd-mappings
。
# 出现错误时, 直接抛出异常(便于异常统一处理,否则捕获不到404)
spring.mvc.throw-exception-if-no-handler-found=true
# 是否开启默认的资源处理,默认为true
spring.resources.add-mappings=false
PS:両方設定された静的なリソースが無視されることに注意してください。
生産をテストしてください。WebMvcAutoConfiguration#addResourceHandlers
Exception
保護されていないにはいくつかの例外を防ぐために、ユーザーがデフォルトに戻り服务器开小差,请稍后再试
、その他のヒント。
具体的な異常は一致する大に小さなデフォルト。
あなたが投げた場合はBindException
、カスタムがBindException
プロセスのこのプロセッサに行きます。その親クラスを一致させるために行くことはありません、ご参照くださいjava-异常体系
。
他の既知の異常が所有することができます@ExceptionHandler
取得プロセスの注釈を。
一般的な異常列挙
外れ値の悪いメンテナンスを避けるために、我々は、使用CommonErrorCode
して維持するために、一般的な異常のヒントを列挙します。
@Getter
public enum CommonErrorCode {
/**
* 404 Web 服务器找不到您所请求的文件或脚本。请检查URL 以确保路径正确。
*/
NOT_FOUND("CLOUD-404",
String.format("哎呀,无法找到这个资源啦(%s)", HttpStatus.NOT_FOUND.getReasonPhrase())),
/**
* 405 对于请求所标识的资源,不允许使用请求行中所指定的方法。请确保为所请求的资源设置了正确的 MIME 类型。
*/
METHOD_NOT_ALLOWED("CLOUD-405",
String.format("请换个姿势操作试试(%s)", HttpStatus.METHOD_NOT_ALLOWED.getReasonPhrase())),
/**
* 415 Unsupported Media Type
*/
UNSUPPORTED_MEDIA_TYPE("CLOUD-415",
String.format("呀,不支持该媒体类型(%s)", HttpStatus.UNSUPPORTED_MEDIA_TYPE.getReasonPhrase())),
/**
* 系统异常 500 服务器的内部错误
*/
EXCEPTION("CLOUD-500", "服务器开小差,请稍后再试"),
/**
* 系统限流
*/
TRAFFIC_LIMITING("CLOUD-429", "哎呀,网络拥挤请稍后再试试"),
/**
* 服务调用异常
*/
API_GATEWAY_ERROR("API-9999", "网络繁忙,请稍后再试"),
/**
* 参数错误
*/
PARAM_ERROR("CLOUD-100", "参数错误"),
/**
* 业务异常
*/
BUSINESS_ERROR("CLOUD-400", "业务异常"),
/**
* rpc调用异常
*/
RPC_ERROR("RPC-510", "呀,网络出问题啦!");
private String code;
private String message;
CommonErrorCode(String code, String message) {
this.code = code;
this.message = message;
}
}
実際には、starter
パッケージが使用することは推奨されていない@Getter
と、他のlombok
未使用から他人を防ぐために、ノートlombok
プロジェクトの問題に依存。
一般的なビジネスの例外
これらの2つのクラスは、傍受、基本的な、通常の使用の例外を行うことができますが、ビジネスの利便性のために、我々は一般的な、一般的なビジネス例外を作成します。
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());
}
次のメソッドによってスローされるプログラムのイニシアチブ:
throw new BusinessException(BusinessErrorCode.BUSINESS_ERROR);
// 或者
throw new BusinessException("CLOUD800","没有多余的库存");
通常は例外をスロー直接ユニバーサルBusinessExceptionをお勧めしません、例外処理クラスが追加され、対応するモジュール内のエラーの種類に対応する対応列挙エリアべきです。
メンバーモジュール場合:
作成しUserException
た例外クラス、UserErrorCode
列挙、およびUserExceptionHandler
統一傍受クラスを。
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());
}
}
ユーザー・エラーコード:
@Getter
public enum UserErrorCode {
/**
* 权限异常
*/
NOT_PERMISSIONS("CLOUD401","您没有操作权限"),
;
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());
}
}
最後に、以下のサービスを使用します。
// 判断是否有权限抛出异常
throw new UserException(UserErrorCode.NOT_PERMISSIONS);
春のコンテナに参加
最後に、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
しかし、我々は、注釈モードを使用して、この時間はオンになっています。他のプロジェクトの依存関係の後、あなたは追加する必要がある@EnableGlobalDispose
唯一のグローバル傍受機能をオンにすることができます。
作成したばかりのspring.factories
作成、コメントEnableGlobalDispose
のメモを。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(GlobalDefaultConfiguration.class)
public @interface EnableGlobalDispose {
}
使用するインポートが可能。@Import
GlobalDefaultConfiguration
使用
依存追加
<dependency>
<groupId>io.deepblueai</groupId>
<artifactId>unified-dispose-deepblueai-starter</artifactId>
<version>0.1.0.RELEASE</version>
</dependency>
開始オープンクラスの@EnableGlobalDispose
ノートは、することができます。
概要
重複したコードの多くでのプロジェクトは、開発の量を減らすの特定の目的を達成するためにいくつかの簡単な方法を通過することができます。
サンプルコード住所:統一-廃棄-springboot
GitHubの上:
Purgeyaoは注意を歓迎します