欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

SpringBoot初始教程之统一异常处理详解

程序员文章站 2024-03-01 15:47:52
1.介绍 在日常开发中发生了异常,往往是需要通过一个统一的异常处理处理所有异常,来保证客户端能够收到友好的提示。springboot在页面发生异常的时候会自动把请求转到/...

1.介绍

在日常开发中发生了异常,往往是需要通过一个统一的异常处理处理所有异常,来保证客户端能够收到友好的提示。springboot在页面发生异常的时候会自动把请求转到/error,springboot内置了一个basicerrorcontroller对异常进行统一的处理,当然也可以自定义这个路径

application.yaml

server:
 port: 8080
 error:
 path: /custom/error

basicerrorcontroller提供两种返回错误一种是页面返回、当你是页面请求的时候就会返回页面,另外一种是json请求的时候就会返回json错误

 @requestmapping(produces = "text/html")
 public modelandview errorhtml(httpservletrequest request,
   httpservletresponse response) {
  httpstatus status = getstatus(request);
  map<string, object> model = collections.unmodifiablemap(geterrorattributes(
    request, isincludestacktrace(request, mediatype.text_html)));
  response.setstatus(status.value());
  modelandview modelandview = resolveerrorview(request, response, status, model);
  return (modelandview == null ? new modelandview("error", model) : modelandview);
 }

 @requestmapping
 @responsebody
 public responseentity<map<string, object>> error(httpservletrequest request) {
  map<string, object> body = geterrorattributes(request,
    isincludestacktrace(request, mediatype.all));
  httpstatus status = getstatus(request);
  return new responseentity<map<string, object>>(body, status);
 }

分别会有如下两种返回

SpringBoot初始教程之统一异常处理详解

{
 "timestamp": 1478571808052,
 "status": 404,
 "error": "not found",
 "message": "no message available",
 "path": "/rpc"
}

2.通用exception处理

通过使用@controlleradvice来进行统一异常处理,@exceptionhandler(value = exception.class)来指定捕获的异常

下面针对两种异常进行了特殊处理分别返回页面和json数据,使用这种方式有个局限,无法根据不同的头部返回不同的数据格式,而且无法针对404、403等多种状态进行处理

 @controlleradvice
 public class globalexceptionhandler {
  public static final string default_error_view = "error";
  @exceptionhandler(value = customexception.class)
  @responsebody
  public responseentity defaulterrorhandler(httpservletrequest req, customexception e) throws exception {
   return responseentity.ok("ok");
  }
  @exceptionhandler(value = exception.class)
  public modelandview defaulterrorhandler(httpservletrequest req, exception e) throws exception {
   modelandview mav = new modelandview();
   mav.addobject("exception", e);
   mav.addobject("url", req.getrequesturl());
   mav.setviewname(default_error_view);
   return mav;
  }
 }

3.自定义basicerrorcontroller 错误处理

在初始介绍哪里提到了basicerrorcontroller,这个是springboot的默认错误处理,也是一种全局处理方式。咱们可以模仿这种处理方式自定义自己的全局错误处理

下面定义了一个自己的basicerrorcontroller,可以根据自己的需求自定义errorhtml()和error()的返回值。

 @controller
 @requestmapping("${server.error.path:${error.path:/error}}")
 public class basicerrorcontroller extends abstracterrorcontroller {
  private final errorproperties errorproperties;
  private static final logger logger = loggerfactory.getlogger(basicerrorcontroller.class);
  @autowired
  private applicationcontext applicationcontext;

  /**
   * create a new {@link org.springframework.boot.autoconfigure.web.basicerrorcontroller} instance.
   *
   * @param errorattributes the error attributes
   * @param errorproperties configuration properties
   */
  public basicerrorcontroller(errorattributes errorattributes,
         errorproperties errorproperties) {
   this(errorattributes, errorproperties,
     collections.<errorviewresolver>emptylist());
  }

  /**
   * create a new {@link org.springframework.boot.autoconfigure.web.basicerrorcontroller} instance.
   *
   * @param errorattributes the error attributes
   * @param errorproperties configuration properties
   * @param errorviewresolvers error view resolvers
   */
  public basicerrorcontroller(errorattributes errorattributes,
         errorproperties errorproperties, list<errorviewresolver> errorviewresolvers) {
   super(errorattributes, errorviewresolvers);
   assert.notnull(errorproperties, "errorproperties must not be null");
   this.errorproperties = errorproperties;
  }

  @override
  public string geterrorpath() {
   return this.errorproperties.getpath();
  }

  @requestmapping(produces = "text/html")
  public modelandview errorhtml(httpservletrequest request,
          httpservletresponse response) {
   httpstatus status = getstatus(request);
   map<string, object> model = collections.unmodifiablemap(geterrorattributes(
     request, isincludestacktrace(request, mediatype.text_html)));
   response.setstatus(status.value());
   modelandview modelandview = resolveerrorview(request, response, status, model);
   inserterror(request);
   return modelandview == null ? new modelandview("error", model) : modelandview;
  }



  @requestmapping
  @responsebody
  public responseentity<map<string, object>> error(httpservletrequest request) {
   map<string, object> body = geterrorattributes(request,
     isincludestacktrace(request, mediatype.all));
   httpstatus status = getstatus(request);
   inserterror(request);
   return new responseentity(body, status);
  }

  /**
   * determine if the stacktrace attribute should be included.
   *
   * @param request the source request
   * @param produces the media type produced (or {@code mediatype.all})
   * @return if the stacktrace attribute should be included
   */
  protected boolean isincludestacktrace(httpservletrequest request,
            mediatype produces) {
   errorproperties.includestacktrace include = geterrorproperties().getincludestacktrace();
   if (include == errorproperties.includestacktrace.always) {
    return true;
   }
   if (include == errorproperties.includestacktrace.on_trace_param) {
    return gettraceparameter(request);
   }
   return false;
  }

  /**
   * provide access to the error properties.
   *
   * @return the error properties
   */
  protected errorproperties geterrorproperties() {
   return this.errorproperties;
  }
 }

springboot提供了一种特殊的bean定义方式,可以让我们容易的覆盖已经定义好的controller,原生的basicerrorcontroller是定义在errormvcautoconfiguration中的

具体代码如下:

 @bean
 @conditionalonmissingbean(value = errorcontroller.class, search = searchstrategy.current)
 public basicerrorcontroller basicerrorcontroller(errorattributes errorattributes) {
  return new basicerrorcontroller(errorattributes, this.serverproperties.geterror(),
    this.errorviewresolvers);
 }

可以看到这个注解@conditionalonmissingbean 意思就是定义这个bean 当 errorcontroller.class 这个没有定义的时候, 意思就是说只要我们在代码里面定义了自己的errorcontroller.class时,这段代码就不生效了,具体自定义如下:

 @configuration
 @conditionalonwebapplication
 @conditionalonclass({servlet.class, dispatcherservlet.class})
 @autoconfigurebefore(webmvcautoconfiguration.class)
 @enableconfigurationproperties(resourceproperties.class)
 public class configspringboot {
  @autowired(required = false)
  private list<errorviewresolver> errorviewresolvers;
  private final serverproperties serverproperties;

  public configspringboot(
    serverproperties serverproperties) {
   this.serverproperties = serverproperties;
  }

  @bean
  public mybasicerrorcontroller basicerrorcontroller(errorattributes errorattributes) {
   return new mybasicerrorcontroller(errorattributes, this.serverproperties.geterror(),
     this.errorviewresolvers);
  }
 }

在使用的时候需要注意mybasicerrorcontroller不能被自定义扫描controller扫描到,否则无法启动。

3.总结

一般来说自定义basicerrorcontroller这种方式比较实用,因为可以通过不同的头部返回不同的数据格式,在配置上稍微复杂一些,但是从实用的角度来说比较方便而且可以定义通用组件

本文代码:springboot-learn_jb51.rar

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。