当前位置: 移动技术网 > IT编程>开发语言>Java > 详解Springboot自定义异常处理

详解Springboot自定义异常处理

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

背景

springboot 默认把异常的处理集中到一个modelandview中了,但项目的实际过程中,这样做,并不能满足我们的要求。具体的自定义异常的处理,参看以下

具体实现

如果仔细看完spring boot的异常处理详解,并且研究过源码后,我觉得具体的实现可以不用看了。。。

重写定义错误页面的url,默认只有一个/error

@bean
  public embeddedservletcontainercustomizer containercustomizer(){
    return new embeddedservletcontainercustomizer(){
      @override
      public void customize(configurableembeddedservletcontainer container) {
        container.adderrorpages(new errorpage(httpstatus.not_found, "/error/404"));
        container.adderrorpages(new errorpage(httpstatus.internal_server_error, "/error/500"));
        container.adderrorpages(new errorpage(java.lang.throwable.class,"/error/500"));
      }
    };
  }

重写通过实现errorcontroller,重写basicerrorcontroller的功能实现

/**
 * 重写basicerrorcontroller,主要负责系统的异常页面的处理以及错误信息的显示
 * @see org.springframework.boot.autoconfigure.web.basicerrorcontroller
 * @see org.springframework.boot.autoconfigure.web.errormvcautoconfiguration
 *
 * @author jonathan
 * @version 2016/5/31 11:22
 * @since jdk 7.0+
 */
@controller
@requestmapping(value = "error")
@enableconfigurationproperties({serverproperties.class})
public class exceptioncontroller implements errorcontroller {

  private errorattributes errorattributes;

  @autowired
  private serverproperties serverproperties;


  /**
   * 初始化exceptioncontroller
   * @param errorattributes
   */
  @autowired
  public exceptioncontroller(errorattributes errorattributes) {
    assert.notnull(errorattributes, "errorattributes must not be null");
    this.errorattributes = errorattributes;
  }


  /**
   * 定义404的modelandview
   * @param request
   * @param response
   * @return
   */
  @requestmapping(produces = "text/html",value = "404")
  public modelandview errorhtml404(httpservletrequest request,
                 httpservletresponse response) {
    response.setstatus(getstatus(request).value());
    map<string, object> model = geterrorattributes(request,
        isincludestacktrace(request, mediatype.text_html));
    return new modelandview("error/404", model);
  }

  /**
   * 定义404的json数据
   * @param request
   * @return
   */
  @requestmapping(value = "404")
  @responsebody
  public responseentity<map<string, object>> error404(httpservletrequest request) {
    map<string, object> body = geterrorattributes(request,
        isincludestacktrace(request, mediatype.text_html));
    httpstatus status = getstatus(request);
    return new responseentity<map<string, object>>(body, status);
  }

  /**
   * 定义500的modelandview
   * @param request
   * @param response
   * @return
   */
  @requestmapping(produces = "text/html",value = "500")
  public modelandview errorhtml500(httpservletrequest request,
                 httpservletresponse response) {
    response.setstatus(getstatus(request).value());
    map<string, object> model = geterrorattributes(request,
        isincludestacktrace(request, mediatype.text_html));
    return new modelandview("error/500", model);
  }


  /**
   * 定义500的错误json信息
   * @param request
   * @return
   */
  @requestmapping(value = "500")
  @responsebody
  public responseentity<map<string, object>> error500(httpservletrequest request) {
    map<string, object> body = geterrorattributes(request,
        isincludestacktrace(request, mediatype.text_html));
    httpstatus status = getstatus(request);
    return new responseentity<map<string, object>>(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 = this.serverproperties.geterror().getincludestacktrace();
    if (include == errorproperties.includestacktrace.always) {
      return true;
    }
    if (include == errorproperties.includestacktrace.on_trace_param) {
      return gettraceparameter(request);
    }
    return false;
  }


  /**
   * 获取错误的信息
   * @param request
   * @param includestacktrace
   * @return
   */
  private map<string, object> geterrorattributes(httpservletrequest request,
                          boolean includestacktrace) {
    requestattributes requestattributes = new servletrequestattributes(request);
    return this.errorattributes.geterrorattributes(requestattributes,
        includestacktrace);
  }

  /**
   * 是否包含trace
   * @param request
   * @return
   */
  private boolean gettraceparameter(httpservletrequest request) {
    string parameter = request.getparameter("trace");
    if (parameter == null) {
      return false;
    }
    return !"false".equals(parameter.tolowercase());
  }

  /**
   * 获取错误编码
   * @param request
   * @return
   */
  private httpstatus getstatus(httpservletrequest request) {
    integer statuscode = (integer) request
        .getattribute("javax.servlet.error.status_code");
    if (statuscode == null) {
      return httpstatus.internal_server_error;
    }
    try {
      return httpstatus.valueof(statuscode);
    }
    catch (exception ex) {
      return httpstatus.internal_server_error;
    }
  }

  /**
   * 实现错误路径,暂时无用
   * @see exceptionmvcautoconfiguration#containercustomizer()
   * @return
   */
  @override
  public string geterrorpath() {
    return "";
  }

}

总结

第一步,通过定义containercustomizer,重写定义了异常处理对应的视图。目前定义了404和500,可以继续扩展。

第二步,重写basicerrorcontroller,当然可以直接定义一个普通的controller类,直接实现第一步定义的视图的方法。重写的目的是重用errorattributes。这样在页面,直接可以获取到status,message,exception,trace等内容。

如果仅仅是把异常处理的视图作为静态页面,不需要看到异常信息内容的话,直接第一步后,再定义error/404,error/500等静态视图即可。

errorcontroller根据accept头的内容,输出不同格式的错误响应。比如针对浏览器的请求生成html页面,针对其它请求生成json格式的返回

以上两步的操作,比网上流传的更能实现自定义化。希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

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

相关文章:

验证码:
移动技术网