SpringBootグローバル例外処理とカスタム404ページ

1.エラー処理原理の分析

Spring Bootを使用して作成されたWebプロジェクトで、要求したページが存在しない場合(httpステータスコードは404)、または例外が発生すると(httpステータスコードは通常500)、Spring Bootはエラーメッセージを返します。

つまり、SpringBoot Webプロジェクトでは、/ errorのエラーインターフェイスが自動的に作成され、エラー情報が返されます。ただし、アクセス方法が異なる場合は、次の2つの異なる戻り情報があります。これは主にAcceptアクセスできるタイプを指定するためにアクセスしたときのhttpヘッダー情報のに依存します

  • ブラウザでアクセスした場合のヘッダ情報とその返却結果
Accept: text/html

  • モバイルクライアントなどの他のデバイスを使用して、ヘッダー情報とその返された結果にアクセスします(通常、別のフロントエンドアーキテクチャ)。
Accept: */*

第二に、エラー処理

例外を処理するには、主に2つの方法があります。

1. SpringBootの自動構成原理を使用して例外処理を行う

SpringBootは自動的にクラスErrorMvcAutoConfiguration構成して例外を処理します。興味がある場合は、調べてから、このクラスでエラーBasicErrorControllerクラスを定義できます。メインコードは次のとおりです。

@Controller
@RequestMapping({"${server.error.path:${error.path:/error}}"})
public class BasicErrorController extends AbstractErrorController {

  	/**
  	 * 错误的页面响应 
  	 */
    @RequestMapping(produces = {"text/html"})
    public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
        HttpStatus status = this.getStatus(request);
        Map<String, Object> model = Collections.unmodifiableMap(this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.TEXT_HTML)));
        response.setStatus(status.value());
      	// 得到一个modelAndView对象
        ModelAndView modelAndView = this.resolveErrorView(request, response, status, model);
        return modelAndView != null ? modelAndView : new ModelAndView("error", model);
    }
		
  /**
   * 错误的json响应
   */
    @RequestMapping
    public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
        HttpStatus status = this.getStatus(request);
        if (status == HttpStatus.NO_CONTENT) {
            return new ResponseEntity(status);
        } else {
            Map<String, Object> body = this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.ALL));
            return new ResponseEntity(body, status);
        }
    }
}

これ以上詳しく調べないコードがあるので、興味があれば調べてみてください。上記のコードは、異なるリクエストメソッドに対して異なる結果が返されることを意味します。キーは @RequestMappingアノテーションのproduces = {"text/html"}属性あります

1)。404、500などのエラーページを返します。

  • テンプレートエンジンがある場合(ページのレンダリングに使用できます)

プロジェクトで使用されるテンプレートエンジン(thymeleaf、freemarkerなど)は、ページのレンダリングに使用されます。テンプレートに/エラーフォルダを作成し、以下に示すように、エラーステータスコードに対応する.htmlファイルを追加します。

ここで、404と500は決定されたエラーステータスコードであり、4xxは400、401など、4で始まる他のエラーを示します。もちろん、ステータスコードごとに対応するエラーページを設定できますが、設定してもメリットがないため、代わりに4xx.htmlのような一般的な用語を使用します。

次の情報(つまり、ModelAndViewオブジェクトのコンテンツ)は、エラーページで取得できます。

フィールド名 解説
ティムスタンプ タイムスタンプ
状態 エラー状態コード
エラー エラーメッセージ
例外 例外オブジェクト
メッセージ 例外メッセージ
ページパス

注意深い友人は、これが実際に携帯電話を使用して要求すると返されるjsonコンテンツであることに気付くでしょう

たとえば、上記の情報をコードに追加してから、バックエンドにエラーコードを記述します。

@RequestMapping("haserror")
@ResponseBody
public Object myError(){
  int i =10/0;
  return "something is error";
}
这是一个错误页面:
<ul>
    <li>错误状态码:[[${status}]]</li>
    <li>错误消息:[[${error}]]</li>
    <li>异常对象:[[${exception}]]</li>
    <li>异常消息:[[${message}]]</li>
    <li>当前时间:[[${timestamp}]]</li>
</ul>

  • テンプレートエンジンなし

テンプレートエンジンがプロジェクトで使用されていない場合は、エラーフォルダー全体を静的フォルダーに移動します。

ただし、これは静的リソースであり、レンダリング用のテンプレートエンジンがないため、現時点では上記の情報を取得できません。

2)、対応するjson文字列を返します

これについては何も言うことはありません。json文字列を返します。形式は次のとおりです。

{
"timestamp": "2020-04-22T16:13:37.506+0000",
"status": 500,
"error": "Internal Server Error",
"message": "/ by zero",
"path": "/hello/haserror",
"reason": "完了,你写的代码又产生了一次线上事故"
}

3)、カスタムページは情報を返します

これは最も重要なコンテンツです。この情報はjsonとして返されるだけでなく、上記のエラーページで取得することも、jsonを直接返すこともできるためです。実際、これも非常に単純で、SpringコンテナにErrorAttributesオブジェクトを追加するだけです。ここでは、そのサブクラスを継承することを選択します。

@Component
public class MyErrorAttributes extends DefaultErrorAttributes {
    @Override
    public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
        //调用父类的方法,会自动获取内置的那些属性,如果你不想要,可以不调用这个
        Map<String, Object> errorAttributes = super.getErrorAttributes(webRequest, includeStackTrace);

        //添加自定义的属性
        errorAttributes.put("reason","完了,你写的代码又产生了一次线上事故");
        // 你可以看一下这个方法的参数webRequest这个对象,我相信你肯定能发现好东西

        return errorAttributes;
    }
}

これですべてです。2つのリクエストメソッドを使用して、カスタムプロパティの1つの可用性をテストします。

2.処理にAOP例外通知を使用する(推奨)

その原則は、グローバルな例外通知を取得して処理することです。プロジェクトでサイドコードを記述するだけで済みます(実際、上記はカスタム例外情報を持つクラスです)

@ControllerAdvice
public class ErrroAcvice {

    /**
     * 全局捕获异常的切面类
     * @param request 请求对象,可不传
     * @param response 响应对象,可不传
     * @param e 异常类(这个要和你当前捕获的异常类是同一个)
     */
    @ExceptionHandler(Exception.class) //也可以只对一个类进行捕获
    public void errorHandler(HttpServletRequest request, HttpServletResponse response,Exception e){
      	/*
      	 * You can do everything you want to do
         * 这里你拿到了request和response对象,你可以做任何你想做的事
         * 比如:
         *	1.用request从头信息中拿到Accept来判断是请求方可接收的类型从而进行第一个方法的判断
         *	2.如果你也想返回一个页面,使用response对象进行重定向到自己的错误页面就可以了
         *  3.你甚至还拿到了异常对象
      	 */
      
        String accept = request.getHeader("Accept");
				// 根据这个字符串来判断做出什么响应	
      
        try {
            response.setStatus(500);
            response.getWriter().write("hello");
        } catch (IOException ex) {
            ex.printStackTrace();
        }
      
    }
}

3. 2つの方法の比較:

  • 最初の方法は、現在のプロジェクトにいくつかのエラーステータスコードページを配置し、Spring Bootにそれらを検出させることです。返されたカスタムエラーメッセージもサポート
  • 2番目の方法は、例外通知処理にAOPのアイデアを直接使用する方法です。これは非常に自由度が高くなります。
  • 2つ目の方法は、自由度が高く、独自のビジネスロジックに合わせていつでも変更できるため、個人的にはおすすめです。次の記事に良い例があります
  • 2番目の方法を使用した後、最初の方法で配置されたすべてのエラーページとカスタムエラーメッセージが無効になる

3.コードアドレス:

WeChatパブリックアカウントに注意してください:XiaoyuとJava、バックグラウンドで「2000」と返信して取得します。

おすすめ

転載: www.cnblogs.com/Lyn4ever/p/12757947.html