2.spring系列之404异常的捕获
2021-12-29 22:09
246 查看
回顾
我在之前发布了一篇spring统一返回的文章,最后提到是无法捕获404异常的,这里我们先来测试一下
@RestController public class TestController { @GetMapping("/test") public String insert22() { return "hello"; } }
浏览器请求试一下 http://localhost:8080/xxx 报错
# Whitelabel Error Page This application has no explicit mapping for /error, so you are seeing this as a fallback. Wed Dec 29 10:14:36 CST 2021 There was an unexpected error (type=Not Found, status=404).
springboot的处理方式
springboot处理这个404的异常是在
BasicErrorController中处理的
@Controller @RequestMapping("${server.error.path:${error.path:/error}}") public class BasicErrorController extends AbstractErrorController { ........... @Override public String getErrorPath() { return null; } @RequestMapping(produces = MediaType.TEXT_HTML_VALUE) public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) { HttpStatus status = getStatus(request); Map<String, Object> model = Collections .unmodifiableMap(getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.TEXT_HTML))); response.setStatus(status.value()); ModelAndView modelAndView = resolveErrorView(request, response, status, model); return (modelAndView != null) ? modelAndView : new ModelAndView("error", model); } // 包含请求头 "Accept": "application/json" 会往这里走 @RequestMapping public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) { HttpStatus status = getStatus(request); if (status == HttpStatus.NO_CONTENT) { return new ResponseEntity<>(status); } Map<String, Object> body = getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.ALL)); return new ResponseEntity<>(body, status); } ............. }
只要请求路径/error就可以进去到
errorHtml这个方法,在浏览器请求http://localhost:8080/error就可以进入这个方法
解决方案
我这使用的springboot的版本为2.3.7.RELEASE
方案1:重写/error的请求
这种方案会直接舍弃掉HTML响应方式,但是前后端分离模式下,后端已经很少使用ModelAndView了
@Controller public class NoFoundController extends AbstractErrorController { public NoFoundController(ErrorAttributes errorAttributes) { super(errorAttributes); } /** * 默认路径/error,可以通过server.error.path配置 */ @RequestMapping(("${server.error.path:/error}")) public ResponseEntity<Map<String, Object>> notFoundError(HttpServletRequest request, HttpServletResponse response) { Map<String, Object> map = new HashMap<>(3); HttpStatus status = getStatus(request); map.put("code", status.value()); map.put("data", null); map.put("message", status.toString()); return new ResponseEntity<>(map, status); } /** * 在springboot2.3.0新增了server.error.path进行配置,这个废弃使用了,之前版本可以直接通过设置这个返回值修改默认/error的路径 */ @Override public String getErrorPath() { return null; } }
方案2:重写BasicErrorController中的错误处理
这种方式无法将HTML响应的也改成了json返回,请求中要有
"Accept": "application/json"才能走json响应
@Controller @RequestMapping("${server.error.path:${error.path:/error}}") public class MyBasicErrorController extends BasicErrorController { public MyBasicErrorController(ServerProperties serverProperties) { // import org.springframework.boot.web.servlet.error.DefaultErrorAttributes; super(new DefaultErrorAttributes(), serverProperties.getError()); } /** * JSON响应 */ @Override public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) { Map<String, Object> map = new HashMap<>(); HttpStatus status = getStatus(request); map.put("code", status.value()); map.put("data", null); map.put("message", status.toString()); return new ResponseEntity<>(map, status); } /** * HTML响应,根据需求处理自己处理 */ @Override public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) { return super.errorHtml(request, response); } }
其中
MyBasicErrorController的构造函数可以参考spring自动装配
ErrorMvcAutoConfiguration中的传值
//源码: public class ErrorMvcAutoConfiguration { private final ServerProperties serverProperties; public ErrorMvcAutoConfiguration(ServerProperties serverProperties) { this.serverProperties = serverProperties; } @Bean @ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT) public DefaultErrorAttributes errorAttributes() { // ErrorAttributes return new DefaultErrorAttributes(); } @Bean @ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT) public BasicErrorController basicErrorController(ErrorAttributes errorAttributes, ObjectProvider<ErrorViewResolver> errorViewResolvers) { // serverProperties.getError return new BasicErrorController(errorAttributes, this.serverProperties.getError(), errorViewResolvers.orderedStream().collect(Collectors.toList())); } ........ }
最后附上完整代码:
@Getter public class BusinessException extends RuntimeException { private Integer code; public BusinessException(Integer code, String message) { super(message); this.code = code; } public BusinessException(String message) { super(message); } } -------------------------------------------------------------------------------------------- @ControllerAdvice @ResponseBody @Slf4j public class GlobalException { @ExceptionHandler(value = BusinessException.class) public ResponseModel<Void> businessExceptionError(BusinessException e) { log.error("业务异常", e); if (e.getCode() != null) { return ResponseModel.error(e.getCode(), e.getMessage()); } return ResponseModel.error(e.getMessage()); } @ExceptionHandler(value = Exception.class) public ResponseModel<Void> exceptionError(Exception e) { log.error("系统异常", e); return ResponseModel.error(); } } -------------------------------------------------------------------------------------------- @Getter public enum ResponseEnum { SUCCESS(0, "OK"), PARAMETER_ERROR(1,"参数异常"), NO_FOUND(404,"not found"), SYSTEM_ERROR(500, "服务器异常,请联系管理员"); ResponseEnum(Integer code, String message) { this.code = code; this.message = message; } private final Integer code; private final String message; } -------------------------------------------------------------------------------------------- public class ResponseModel<T> { private Integer code; private String message; private T data; public ResponseModel(Integer code, String message, T data) { this.code = code; this.message = message; this.data = data; } public static ResponseModel<Void> ok() { return ok(null); } public static <T> ResponseModel<T> ok(T data) { return new ResponseModel<>(ResponseEnum.SYSTEM_ERROR.getCode(), ResponseEnum.SYSTEM_ERROR.getMessage(), data); } public static <T> ResponseModel<T> ok(T data, String message) { return new ResponseModel<>(ResponseEnum.SYSTEM_ERROR.getCode(), message, data); } public static ResponseModel<Void> error(Integer statusCode, String message) { return new ResponseModel<>(statusCode, message, null); } public static ResponseModel<Void> error(String message) { return error(ResponseEnum.SYSTEM_ERROR.getCode(), message); } public static ResponseModel<Void> error() { return error(ResponseEnum.SYSTEM_ERROR.getCode(), ResponseEnum.SYSTEM_ERROR.getMessage()); } } -------------------------------------------------------------------------------------------- @Controller public class NoFoundController extends AbstractErrorController { public NoFoundController(ErrorAttributes errorAttributes) { super(errorAttributes); } /** * 默认路径/error,可以通过server.error.path配置 */ @RequestMapping(("${server.error.path:/error}")) public ResponseEntity<Map<String, Object>> notFoundError(HttpServletRequest request, HttpServletResponse response) { Map<String, Object> map = new HashMap<>(3); HttpStatus status = getStatus(request); map.put("code", status.value()); map.put("data", null); map.put("message", status.toString()); return new ResponseEntity<>(map, status); } /** * 在springboot2.3.0新增了server.error.path进行配置,这个废弃使用了,之前版本可以直接通过设置这个返回值修改默认/error的路径 */ @Override public String getErrorPath() { return null; } }
感谢各位小伙伴阅读到最后,如有错误,敬请指正。
相关文章推荐
- SpringBoot入门系列篇(三):进行全局异常捕获
- SpringBoot系列教程web篇之404、500异常页面配置
- SpringBoot系列教程web篇之404、500异常页面配置
- SpringBoot系列之三全局异常的捕获处理
- SpringBoot处理全局捕获异常
- Spring事务异常回滚,try catch 捕获异常不回滚
- springboot全局异常捕获
- springcloud+feign 集成LCN5.0.2分布式事务,以及全局异常捕获问题的解决方案
- Spring事务异常回滚,捕获异常不抛出就不会回滚
- 总结SSH阶段常见异常系列之五spring
- Spring-MVC开发之全局异常捕获全面解读
- spring mvc 使用 @ControllerAdvice 捕获404异常
- [系列] go-gin-api 路由中间件 - 捕获异常(四)
- Spring-MVC开发之全局异常捕获全面解读
- 实战Spring Boot 2.0系列(二) - 全局异常处理和测试
- 170621、springboot编程之全局异常捕获
- Spring与AOP-异常通知-捕获自定义异常
- Spring-MVC开发值全局异常捕获全面解读
- 异常捕获不抛出,Spring事务无法回滚
- spring中配置了事务,数据业务层捕获异常,事务配置不成功?