Springbootがカスタムエラーページを実装する方法(エラー処理メカニズムの詳細な説明)

一般的に、プロジェクトで作業する場合、エラーメカニズムは必要な常識です。基本的にすべてのプロジェクトがエラー処理を行います。プロジェクトがエラーを報告したときに元のエラーページに直接ジャンプすることはできません。このブログは主に焦点を当てています。 springbootとselfのデフォルトの処理メカニズム説明するエラーページ処理を定義し、それを必要とする友人は、エディターに従って一緒に学びましょう!

ここでは、コード例を使用して彼の理由と原則を分析します。原則を理解することによってのみ、実際の戦闘でそれらをより適切に使用できます。

ブログの下部には、私自身の小さなデモがあります。これは、誰もがすばやく学ぶのに便利です。

原則に飽きたら、直接スキップしてコードを見ることができます。読んだ後、興味があれば戻ってもう一度見ることができます。

デフォルト効果の例

Springbootには独自のデフォルト処理メカニズムがあります。存在しないパスにアクセスするためにspringbootプロジェクトを作成するだけで、そのようなメッセージがポップアップ表示されることがわかります。

郵便配達員の直接インターフェースを使用してアクセスすると、彼が返すものはもはやページではないことがわかります。デフォルトでjsonデータへの応答

現時点では、誰かが考えるべきです、springbootは私たちがページ訪問者であるかどうかをどのように認識しますか?

効果例理由

springbootのデフォルトのエラー処理メカニズムは、ヘッダーのAcceptに基づいて判断されます。このパラメータは、Postmanアクセスかページアクセスかに関係なく渡されます。

ページにアクセスすると、彼はtest / htmlに合格します。

そして郵便配達員はこれです

エラーメカニズムの原理

私たちはおそらくその理由を理解しているでしょう、そしてそれから私たちはソースコードを見ることによって彼の原理を簡単に理解します。

スプリングブーツの原理の簡単なレビュー

springbootがそのまま使用される理由は、多くのフレームワークがすでに構成されているためです。多くのAutoConfigurationが含まれており、ErrorMvcAutoConfigurationクラスがエラーメカニズムの構成です。

このjarパッケージに保存されています
ここに画像の説明を挿入します

springboo 2.4バージョンでは、ErrorMvcAutoConfigurationはこのパスに保存されます

Springboot1.5バージョンErrorMvcAutoConfigurationはこのパスに保存されます

もちろん、彼はバージョン間でクラスの保存場所を変更しただけですが、ソースコードの違いはそれほど大きくありません。

springbootで使用されるすべての構成はコンテナーから取得されます。コンテナーの役割は、構成のインスタンス化プロセスを起動時に配置することです。これを使用する場合は、作成せずにコンテナーから直接取得します。これは、コンテナーを中心に開発することです。 。この理由は、springbootを使用するときに発見する必要があります。springbootのデフォルト設定の一部を変更する場合は、有効になる前にコンテナに入れるように最善を尽くします。

ソースコードには、多数の@ConditionalOnMissingBeanがあります。これは、この構成がプロジェクトで構成されている場合、springbootはデフォルトの構成を使用せず、構成を使用するだけです。

ErrorMvcAutoConfigurationplication

ErrorMvcAutoConfigurationは、次のコンポーネントをコンテナに追加します。

1、DefaultErrorAttributes

ページ内のエラー情報やアクセス時間などは、DefaultErrorAttributesのこれら2つのメソッドで取得されます。

	@Override
	public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
		Map<String, Object> errorAttributes = getErrorAttributes(webRequest, options.isIncluded(Include.STACK_TRACE));
		if (Boolean.TRUE.equals(this.includeException)) {
			options = options.including(Include.EXCEPTION);
		}
		if (!options.isIncluded(Include.EXCEPTION)) {
			errorAttributes.remove("exception");
		}
		if (!options.isIncluded(Include.STACK_TRACE)) {
			errorAttributes.remove("trace");
		}
		if (!options.isIncluded(Include.MESSAGE) && errorAttributes.get("message") != null) {
			errorAttributes.put("message", "");
		}
		if (!options.isIncluded(Include.BINDING_ERRORS)) {
			errorAttributes.remove("errors");
		}
		return errorAttributes;
	}

	@Override
	@Deprecated
	public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
		Map<String, Object> errorAttributes = new LinkedHashMap<>();
		errorAttributes.put("timestamp", new Date());
		addStatus(errorAttributes, webRequest);
		addErrorDetails(errorAttributes, webRequest, includeStackTrace);
		addPath(errorAttributes, webRequest);
		return errorAttributes;
	}

2、BasicErrorController

デフォルト/エラー要求の処理

エラーページを返すか、jsonデータを返すかを決定するのはBasicErrorControllerの2つのメソッドでもあります

@RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
	public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
		HttpStatus status = getStatus(request);
		Map<String, Object> model = Collections
				.unmodifiableMap(getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.TEXT_HTML)));
		response.setStatus(status.value());
		ModelAndView modelAndView = resolveErrorView(request, response, status, model);
		return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
	}

	@RequestMapping
	public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
		HttpStatus status = getStatus(request);
		if (status == HttpStatus.NO_CONTENT) {
			return new ResponseEntity<>(status);
		}
		Map<String, Object> body = getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.ALL));
		return new ResponseEntity<>(body, status);
	}

3、ErrorPageCustomizer

システムでエラーが発生すると、処理のためのエラー要求が発生します;(web.xmlによって登録されたエラーページルールと同等)

4、DefaultErrorViewResolver

DefaultErrorViewResolverConfiguration内部クラス

ここで、彼がDefaultErrorViewResolverをコンテナーに挿入したことがわかります。

DefaultErrorViewResolverオブジェクトには、状態に応じてページジャンプを完了するための2つのメソッドがあります。

	@Override
	public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status,
			Map<String, Object> model) {
			
		//获取错误状态码,这里可以看出他将状态码传入了resolve方法
		ModelAndView modelAndView = resolve(String.valueOf(status), model);
		if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {
			modelAndView = resolve(SERIES_VIEWS.get(status.series()), model);
		}
		return modelAndView;
	}

	private ModelAndView resolve(String viewName, Map<String, Object> model) {
		//从这里可以得知,当我们报404错误的时候,他会去error文件夹找404的页面,如果500就找500的页面。
		String errorViewName = "error/" + viewName;
		//模板引擎可以解析这个页面地址就用模板引擎解析
		TemplateAvailabilityProvider provider = this.templateAvailabilityProviders
				.getProvider(errorViewName, this.applicationContext);
		//模板引擎可用的情况下返回到errorViewName指定的视图地址
		if (provider != null) {
			return new ModelAndView(errorViewName, model);
		}
		//模板引擎不可用,就在静态资源文件夹下找errorViewName对应的页面 error/404.html
		return resolveResource(errorViewName, model);
	}

コンポーネントの実行手順

システムに4xxや5xxなどのエラーが発生すると、ErrorPageCustomizerが有効になります(カスタマイズされたエラー応答ルール)。/errorリクエストに送信されます。BasicErrorControllerによって処理されます。移動先のページはDefaultErrorViewResolverによって解析されます。

コード例

ここでは、コードを直接アップロードすることを選択しました。これにより、誰もがより早く開始できるようになります。

1.依存関係をインポートします

ここで、thymeleafテンプレートを引用しました。ページジャンプ機能は、springboot内で構成されています。

これは私が書いたthymeleafに関するブログです。使ったことがない、またはよく知らない場合は、学ぶことができます。

thymeleafの学習:https://blog.csdn.net/weixin_43888891/article/details/111350061

<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-thymeleaf</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>

	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-tomcat</artifactId>
		<scope>provided</scope>
	</dependency>
</dependencies>

2.カスタム例外

機能:データが見つからないためにnullポインターを報告するいくつかのエラーが発生した場合、手動で例外をスローできます。

package com.gzl.cn;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@ResponseStatus(HttpStatus.NOT_FOUND)
public class NotFoundException extends RuntimeException {

    public NotFoundException() {
    }

    public NotFoundException(String message) {
        super(message);
    }

    public NotFoundException(String message, Throwable cause) {
        super(message, cause);
    }
}

3.例外インターセプトを定義します

package com.gzl.cn.handler;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;

@ControllerAdvice
public class ControllerExceptionHandler {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());


    @ExceptionHandler(Exception.class)
    public ModelAndView exceptionHander(HttpServletRequest request, Exception e) throws Exception {
        logger.error("Requst URL : {},Exception : {}", request.getRequestURL(),e);
		
		//假如是自定义的异常,就让他进入404,其他的一概都进入error页面
        if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null) {
            throw e;
        }

        ModelAndView mv = new ModelAndView();
        mv.addObject("url",request.getRequestURL());
        mv.addObject("exception", e);
        mv.setViewName("error/error");
        return mv;
    }
}

4.テストインターフェイスを作成します

package com.gzl.cn.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import com.gzl.cn.NotFoundException;

@Controller
public class HelloController {

    //这个请求我们抛出我们定义的错误,然后被拦截到直接跳到404,这个一般当有一些数据查不到的时候手动抛出
    @GetMapping("/test")
    public String test(Model model){
        String a = null;
        if(a == null) {
        	throw new NotFoundException();
        }
        System.out.println(a.toString());
        return "success";
    }
    
    //这个请求由于a为null直接进500页面
    @GetMapping("/test2")
    public String test2(Model model){
        String a = null;
        System.out.println(a.toString());
        return "success";
    }
}

5.404ページを作成します

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h2>404</h2>
    <p>对不起,你访问的资源不存在</p>
</body>
</html>

6.エラーページを作成します

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h2>错误</h2>
    <p>对不起,服务异常,请联系管理员</p>
    
	<!--这段代码在页面不会展现,只会出现在控制台,假如线上报错可以看控制台快速锁定错误原因-->    
	<div>
	    <div th:utext="'&lt;!--'" th:remove="tag"></div>
	    <div th:utext="'Failed Request URL : ' + ${url}" th:remove="tag"></div>
	    <div th:utext="'Exception message : ' + ${exception.message}" th:remove="tag"></div>
	    <ul th:remove="tag">
	      <li th:each="st : ${exception.stackTrace}" th:remove="tag"><span th:utext="${st}" th:remove="tag"></span></li>
	    </ul>
	    <div th:utext="'--&gt;'" th:remove="tag"></div>
	</div>
</body>
</html>

7.プロジェクトの構造

8.ランニング効果

http:// localhost:8080 / test2

このとき、ここでそのコードが有効になっていることがわかります。お客様には見えないというメリットがありますが、見た目は美しくないので、この方法を採用しています。

存在しないページにアクセスする


今回はhttp:// localhost:8080 / testにアクセスすると、彼が404ページにジャンプしたことがわかります。

エディターが好きであることを忘れないでください!

おすすめ

転載: blog.csdn.net/weixin_43888891/article/details/112254711