Spring Boot系列(7)——自定义异常反馈

〇、原始的异常反馈

  当出现4xx或5xx错误时,spring boot项目返回的原始异常反馈是如下风格。

  

 

一、指定异常页面

  1.ErrorMvcAutoConfiguration

  按照Spring Boot的惯例,默认的配置都在xxxAutoConfiguration类中。而异常处理则在ErrorMvcAutoConfiguration中。

  错误请求会交由BasicErrorController处理,从类名可以看出这是一个错误处理控制器

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

  /**
  * 该方法响应错误请求
  * 其中resolvErrorView形成错误反馈页面的路径
  */ @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 = this.resolveErrorView(request, response, status, model); return modelAndView != null ? modelAndView : new ModelAndView("error", model); }
}

 

  2.错误反馈页面路径

  

 

 

   

  3.总结

  把错误反馈页面放在根目录 error文件下(使用templeaf模板时,在/templates/error下),并且页面文件名为状态码,则发送该类错误,就会返回此页面。

  例如:发生 404 Http请求错误时,会返回  /error/404.html的页面 或 /error/4xx.html的页面。

  

 

 

 

二、定制反馈信息

  1.编写异常处理方法

  注意:客户端或服务器异常会首先被处理再返回,而处理过后再返回则Http状态码会变为200,所以要通过"javax.servlet.error.status_code"指定Http的错误状态码

       通过以下代码,当发生UserNotExistException异常时,就来到此方法,我们就可以在其中添加自定义的反馈信息。

 1 /*
 2  * 增强的Controller,作用如下:
 3  * 1.全局异常处理
 4  * 2.全局数据绑定
 5  * 3.全局数据预处理
 6  */
 7 @ControllerAdvice
 8 public class ExceptionController {
 9 
10     /*
11      * @ExceptionHandler( )处理特定的异常
12      * UserNotExistException为自定义异常
13      * 即当发生该异常时,就转到该方法处理
14      */
15     @ExceptionHandler(UserNotExistException.class)
16     public String hanldException(Exception e, HttpServletRequest request){
17         Map<String,Object> map = new HashMap<>();
18         request.setAttribute("javax.servlet.error.status_code",404);
19         
20         //转到“/error”请求处理控制器处理方法
21         return "forward:/error";
22     }
23 }

 

  2.错误反馈信息要写在哪?

   回答该问题,我们可以参考本文开头图片中的Spring Boot默认返回的 错误反馈数据出处,如下:

  BasicErrorController控制器中errorHtml( )方法是响应/error请求的方法,其中调用了getErrorAttributes( )方法,而默认的错误反馈数据正是来自getErrorAttributes( )方法。

 1 //BasicErrorController类
 2   @RequestMapping(
 3         produces = {"text/html"}
 4     )
 5     public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
 6         HttpStatus status = this.getStatus(request);
 7         Map<String, Object> model = Collections.unmodifiableMap(this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.TEXT_HTML)));
 8         response.setStatus(status.value());
 9         ModelAndView modelAndView = this.resolveErrorView(request, response, status, model);
10         return modelAndView != null ? modelAndView : new ModelAndView("error", model);
11     }
 1 //DefaultErrorAttributes类
 2 public Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
 3         Map<String, Object> errorAttributes = new LinkedHashMap();
 4         errorAttributes.put("timestamp", new Date());
 5         errorAttributes.put("path", request.path());
 6         Throwable error = this.getError(request);
 7         MergedAnnotation<ResponseStatus> responseStatusAnnotation = MergedAnnotations.from(error.getClass(), SearchStrategy.TYPE_HIERARCHY).get(ResponseStatus.class);
 8         HttpStatus errorStatus = this.determineHttpStatus(error, responseStatusAnnotation);
 9         errorAttributes.put("status", errorStatus.value());
10         errorAttributes.put("error", errorStatus.getReasonPhrase());
11         errorAttributes.put("message", this.determineMessage(error, responseStatusAnnotation));
12         errorAttributes.put("requestId", request.exchange().getRequest().getId());
13         this.handleException(errorAttributes, this.determineException(error), includeStackTrace);
14         return errorAttributes;
15     }

 

  3.自定义反馈信息

  按照上面所述,我们可以通过继承DefaultErrorAttributes类,重写getErrorAttributes( )方法以加入自定义的错误反馈信息:

  再在页面中通过templeaf的标签将值取出

 1 import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
 2 
 3 
 4 //继承DefaultErrorAttributes类
 5 @Component
 6 public class MyErrorAttributes extends DefaultErrorAttributes {
 7 
 8     //重写getErrorAttributes方法
 9     @Override
10     public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
11         Map<String, Object> errorAttributes = super.getErrorAttributes(webRequest, includeStackTrace);
12         
13         //加入自定义信息
14         errorAttributes.put("message","页面找不到");
15         return errorAttributes;
16     }
17 }
//页面
<h1>错误码:404</h1>
<P>message:[[${message}]]</P>

 

 

   3.各方法执行顺序

      (1)异常处理器@ExceptionHandler(异常类)  ;  

   (2)BasicErrorController的errorHtml( )方法(调用getErrorAttributes( )方法);

   (3)重写的getErrorAttributes( )方法 ;

   (4)返回BasicErrorController的errorHtml( )方法;

  根据此执行顺序,我们可以把自定义反馈信息在异常处理器中编写,并放入request中。再在重写的getErrorAttributes( )方法 中通过request取出,如下:

 1 /*
 2  * 增强的Controller,作用如下:
 3  * 1.全局异常处理
 4  * 2.全局数据绑定
 5  * 3.全局数据预处理
 6  */
 7 @ControllerAdvice
 8 public class ExceptionController {
 9 
10     /*
11      * @ExceptionHandler( )处理特定的异常
12      * UserNotExistException为自定义异常
13      * 即当发生该异常时,就转到该方法处理
14      */
15     @ExceptionHandler(UserNotExistException.class)
16     public String hanldException(Exception e, HttpServletRequest request){
17         System.out.println("ExceptionController的hanldException方法");
18         Map<String,Object> map = new HashMap<>();
19         request.setAttribute("javax.servlet.error.status_code",404);
20        //将自定义的反馈信息放入request
21         map.put("message","页面找不到!");
22         request.setAttribute("ext",map);
23         //转到“/error”请求处理控制器处理方法
24         return "forward:/error";
25     }
26 }
 1 //继承DefaultErrorAttributes类
 2 @Component
 3 public class MyErrorAttributes extends DefaultErrorAttributes {
 4 
 5     //重写getErrorAttributes方法
 6     @Override
 7     public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
 8         Map<String, Object> errorAttributes = super.getErrorAttributes(webRequest, includeStackTrace);
 9         System.out.println("MyErrorAttributes的getErrorAttributes方法");
10         //从request取出自定义信息
11         errorAttributes.put("ext",webRequest.getAttribute("ext",0));
12         return errorAttributes;
13     }
14 }

 

posted @ 2020-02-05 23:39  Drajun  阅读(510)  评论(0编辑  收藏  举报