其他分享
首页 > 其他分享> > 解决springboot配置@ControllerAdvice不能捕获NoHandlerFoundException问题

解决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