当前位置: 移动技术网 > IT编程>开发语言>Java > SpringBoot初始教程之统一异常处理详解

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

2019年07月22日  | 移动技术网IT编程  | 我要评论

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);
 }

分别会有如下两种返回

{
 "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这种方式比较实用,因为可以通过不同的头部返回不同的数据格式,在配置上稍微复杂一些,但是从实用的角度来说比较方便而且可以定义通用组件

本文代码:

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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网