spring boot 捕获404错误 ErrorController

之前在使用springmvc的时候可以通过在web.xml中配置404指向对应的页面,但是在spring boot是没有web.xml的,如果没有任何配置的话我们会得到下面的返回

浏览器访问

使用工具post

那么我想spring boot肯定为我们准备好了对应的解决方案,那就是BasicErrorController,这个继承自AbstractErrorController,而且是在没有其他实现的时候,这个默认的ErrorController才会生效,我们可以看到ErrorMvcAutoConfiguration里面的声明,里面的ConditionalOnMissingBean就是这个意思

    @Bean
    @ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)
    public BasicErrorController basicErrorController(ErrorAttributes errorAttributes) {
        return new BasicErrorController(errorAttributes, this.serverProperties.getError(),
                this.errorViewResolvers);
    }

下面我们关注一下BasicErrorController里面的两个方法,一个方法对面的是我们上面浏览器访问的的那个返回,一个application/json的post请求返回,他们返回了自己预先定义的数据,这里我们注意下一个细节,就是ModelAndView modelAndView = resolveErrorView(request, response, status, model)这一行,我们进去看下他的源码,就会知道,这里去拿返回的时候,它会默认去项目的资源目录根据请求的状态码获取html文件返回,所以如果只支持浏览器访问的get方式的话,我们直接定义好对应的html文件就可以了
源码

,spring boot静态默认的默认目录是static,这里去error下去找view,那么只要在/resources/static/error/目录下定义文件就行
image.png
    @RequestMapping(produces = "text/html")
    public ModelAndView errorHtml(HttpServletRequest request,
            HttpServletResponse response) {
        HttpStatus status = getStatus(request);
        Map 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> error(HttpServletRequest request) {
        Map body = getErrorAttributes(request,
                isIncludeStackTrace(request, MediaType.ALL));
        HttpStatus status = getStatus(request);
        return new ResponseEntity>(body, status);
    }

但是我们更多的是接口请求,而且这样灵活性太差,所以我们还是自己定义一个ErrorController比较合适,然后重写这两个方法,errorHtml这个基本和BasicErrorController一样,只要定义好静态文件就行,对于error方法,我们返回自己系统定义的json格式数据,下面是具体实现,类的其他代码直接参考BasicErrorController的就行,定义完自己的ExceptionController之后,还需要一个配置类的

 @RequestMapping(produces = "text/html")
 public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
  HttpStatus status = getStatus(request);
  log.error("接口请求错误,http status:{}", status);
  Map model = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.TEXT_HTML));
  JsonResult result = new JsonResult<>(ResultCode.NOT_FOUND);
  model.put("restResponse", result);
  response.setStatus(status.value());
  ModelAndView modelAndView = resolveErrorView(request, response, status, model);
  return (modelAndView == null ? new ModelAndView("error", model) : modelAndView);
 }
 @RequestMapping
 @ResponseBody
 public ResponseEntity> error(HttpServletRequest request) {
  HttpStatus status = getStatus(request);
  log.error("接口请求错误,http status:{}", status);
  //这里构建自己的输出格式,详细代码就不贴出,如有需要可以到代码仓库查看
  if (Objects.equals(status.value(), 404)) {
   return new ResponseEntity<>(new JsonResult<>(ResultCode.NOT_FOUND), status);
  } else {
   return new ResponseEntity<>(new JsonResult<>(ResultCode.ERROR_SYSTEM), status);
  }
 }
 
 
@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({Servlet.class, DispatcherServlet.class})
@AutoConfigureBefore(WebMvcAutoConfiguration.class)
@EnableConfigurationProperties(ResourceProperties.class)
public class ExceptionControllerConfig {

  private final ServerProperties serverProperties;

  private final List errorViewResolvers;

  public ExceptionControllerConfig(ServerProperties serverProperties,
      ObjectProvider> errorViewResolversProvider) {
    this.serverProperties = serverProperties;
    this.errorViewResolvers = errorViewResolversProvider.getIfAvailable();
  }

  @Bean
  public ExceptionController exceptionController(ErrorAttributes errorAttributes) {
    return new ExceptionController(errorAttributes, this.serverProperties.getError(), this.errorViewResolvers);
  }
}

这样我们就定义好了自己的错误控制器,可以根据不同的请求状态码返回自己的数据;

还有一种做法

还有一种做法就是通过spring boot的配置直接完成,这样配置的顾名思义,就是在没有handler的时候直接作为异常抛出,这样我们的全局异常捕获器就能够捕获到了,然后根据不同的状态码返回就行,但是这里需要看到的是有个add-mappings:false,就是这种情况下静态资源是要不能访问的,其实是因为静态资源是直接访问,不需要控制器,所以要配置成false;如果你的项目仅仅是作为接口服务的话,那么这种方式来的更加的简单,我本来也是这么做的,但是我的项目里面使用了swagger,这个东西暴露出去的api是动态生成的静态文件,如果这样配置之后,swagger也不能用了,所以我还是使用了第一种方式进行捕获error

  spring:
    mvc:
      throw-exception-if-no-handler-found: true
    resources:
      add-mappings: false

你可能感兴趣的:(spring boot 捕获404错误 ErrorController)