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); }
分别会有如下两种返回
{ "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
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: 30分钟入门Java8之方法引用学习