首页 > 编程 > Java > 正文

SpringBoot初始教程之统一异常处理详解

2019-11-26 12:39:59
字体:
来源:转载
供稿:网友

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持武林网。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表