解决springboot配置@ControllerAdvice不能捕获NoHandlerFoundException问题
作者:互联网
使用springboot开发一个RESTful API服务,配置了@ControllerAdvice,其它类型异常都能正常捕获,就是不能捕获NoHandlerFoundException,安装以往使用springmvc的经验,需要设置DispatcherServlet.throwExceptionIfNoHandlerFound,NoHandlerFoundException就会被DispatcherSevlet抛出,并被@ControllerAdvice捕获处理。想来springboot中自然也是可以的。
网上一搜发现,只需设置spring.mvc.throw-exception-if-no-handler-found=true即可。设置后依然无效!
再次搜索,还需要设置spring.resources.add-mappings=false,问题解决!
很奇怪,为什么禁用了资源映射后,问题就解决了呢?
研究DispatcherServlet源码发现,NoHandlerFoundException异常能否被抛出,关键在如下代码:
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
只有第一句代码找不到对应该请求的处理器时,才会进入下面的noHandler方法去抛出NoHandlerFoundException异常。
通过测试发现,springboot的WebMvcAutoConfiguration会默认配置如下资源映射:
/映射到/static(或/public、/resources、/META-INF/resources) /webjars/ 映射到classpath:/META-INF/resources/webjars/ /**/favicon.ico映射favicon.ico文件.
这下就明白了,即使你的地址错误,仍然会匹配到/**这个静态资源映射地址,就不会进入noHandlerFound方法,自然不会抛出NoHandlerFoundException了。
所以,我们需要的就是改掉默认的静态资源映射访问路径就可以了。
配置如下属性,NoHandlerFoundException异常就能被@ControllerAdvice捕获了
spring.mvc.throw-exception-if-no-handler-found=true
spring.mvc.static-path-pattern=/statics/**
附上@ControllerAdvice代码:
/**
* ResponseEntityExceptionHandler预提供了一个处理Spring常见异常的Exceptionhandler
* @author wangyongjun
* @date 2018/4/19.
*/
@RestControllerAdvice
public class GlobalControllerExceptionHandler extends ResponseEntityExceptionHandler {
/**
* 覆盖handleExceptionInternal这个汇总处理方法,将响应数据替换为我们的{@link ApiErrorResponse}即可
* @param ex
* @param body
* @param headers
* @param status
* @param request
* @return
*/
@Override
protected ResponseEntity<Object> handleExceptionInternal(Exception ex, Object body, HttpHeaders headers, HttpStatus status, WebRequest request) {
return new ResponseEntity<>(new ApiErrorResponse().setCode(String.valueOf(status.value())).setMsg(ex.getMessage()), status);
}
/**
* 400错误,bad request
* @param ex
* @return
*/
@ExceptionHandler(value = { IllegalArgumentException.class,Exception400.class})
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ApiErrorResponse badRequestException(Exception ex) {
return ApiErrorResponse.error400().setMsg(ex.getMessage());
}
/**
* 401错误,未授权
* @param ex
* @return
*/
@ExceptionHandler(value = { Exception401.class})
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ApiErrorResponse unauthorizedException(Exception ex) {
return ApiErrorResponse.error401().setMsg(ex.getMessage());
}
/**
* 403错误,权限不足
* @param ex
* @return
*/
@ExceptionHandler(value = { Exception403.class})
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ApiErrorResponse forbiddenException(Exception ex) {
return ApiErrorResponse.error403().setMsg(ex.getMessage());
}
/**
* 404错误,处理器不存在异常,资源不存在异常
* @param ex
* @return
*/
@ExceptionHandler(value = { Exception404.class })
@ResponseStatus(HttpStatus.NOT_FOUND)
public ApiErrorResponse noHandlerFoundException(Exception ex) {
return ApiErrorResponse.error404().setMsg(ex.getMessage());
}
/**
* 500异常
* @param ex
* @return
*/
@ExceptionHandler(value = {Exception500.class,Exception.class })
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ApiErrorResponse exception(Exception ex) {
return ApiErrorResponse.error500().setMsg(ex.getMessage());
}
}
我使用的是@RestControllerAdvice,异常处理的返回都会被解析为json,不做RESTful API的使用@ControllerAdvice即可。
spring预提供了一个ResponseEntityExceptionHandler,能处理大部分spring自己定义的异常,我们只需要覆盖handleExceptionInternal这个汇总处理方法,将返回的ResponseEntity的body部分替换为我们自己定义的ApiErrorResponse即可。
当然,你也可以自由地配置对其它异常的处理。
转自:https://my.oschina.net/u/3049656/blog/1798583
标签:NoHandlerFoundException,return,springboot,param,public,ApiErrorResponse,ex,Contr 来源: https://blog.csdn.net/yht520100/article/details/121615791