一般的に、プロジェクトで作業する場合、エラーメカニズムは必要な常識です。基本的にすべてのプロジェクトがエラー処理を行います。プロジェクトがエラーを報告したときに元のエラーページに直接ジャンプすることはできません。このブログは主に焦点を当てています。 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="'<!--'" 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="'-->'" th:remove="tag"></div>
</div>
</body>
</html>
7.プロジェクトの構造
8.ランニング効果
http:// localhost:8080 / test2
このとき、ここでそのコードが有効になっていることがわかります。お客様には見えないというメリットがありますが、見た目は美しくないので、この方法を採用しています。
存在しないページにアクセスする
今回はhttp:// localhost:8080 / testにアクセスすると、彼が404ページにジャンプしたことがわかります。
エディターが好きであることを忘れないでください!