默认效果:
1)、浏览器,返回一个默认的错误页面

  1.1 请求头

  1.2返回结果

2)、如果是其他客户端,默认响应一个json数据

2.1请求头

2.2返回结果

{"timestamp": "2018-11-25T08:22:36.343+0000","status": 404,"error": "Not Found","message": "No message available","path": "/golden"
}

步骤:
  1)系统出现4xx或者5xx之类的错误;ErrorPageCustomizer就会生效(定制错误的响应规则);

  2) 根据相应规则来到/error请求;被BasicErrorController处理;

  3)响应页面;被Controller处理后去哪个页面是由DefaultErrorViewResolver解析得到的;

源码解析

public class ErrorMvcAutoConfiguration {   // 系统出现错误以后来到error请求进行处理;(相当于web.xml注册错误页面规则) @Beanpublic ErrorPageCustomizer errorPageCustomizer() {return new ErrorPageCustomizer(this.serverProperties, this.dispatcherServletPath);}/*** {@link WebServerFactoryCustomizer} that configures the server's error pages.*/private static class ErrorPageCustomizer implements ErrorPageRegistrar, Ordered {private final ServerProperties properties;private final DispatcherServletPath dispatcherServletPath;protected ErrorPageCustomizer(ServerProperties properties,DispatcherServletPath dispatcherServletPath) {this.properties = properties;this.dispatcherServletPath = dispatcherServletPath;}@Overridepublic void registerErrorPages(ErrorPageRegistry errorPageRegistry) {ErrorPage errorPage = new ErrorPage(this.dispatcherServletPath.getRelativePath(this.properties.getError().getPath()));errorPageRegistry.addErrorPages(errorPage);}@Overridepublic int getOrder() {return 0;}}
}public class ErrorProperties {/*** Path of the error controller.*/@Value("${error.path:/error}")private String path = "/error";}

public class ErrorMvcAutoConfiguration {// 系统出现错误以后来到error请求进行处理;(相当于web.xml注册错误页面规则)
    @Beanpublic ErrorPageCustomizer errorPageCustomizer() {return new ErrorPageCustomizer(this.serverProperties, this.dispatcherServletPath);}/*** {@link WebServerFactoryCustomizer} that configures the server's error pages.*/private static class ErrorPageCustomizer implements ErrorPageRegistrar, Ordered {private final ServerProperties properties;private final DispatcherServletPath dispatcherServletPath;protected ErrorPageCustomizer(ServerProperties properties,DispatcherServletPath dispatcherServletPath) {this.properties = properties;this.dispatcherServletPath = dispatcherServletPath;}@Overridepublic void registerErrorPages(ErrorPageRegistry errorPageRegistry) {ErrorPage errorPage = new ErrorPage(this.dispatcherServletPath.getRelativePath(this.properties.getError().getPath()));errorPageRegistry.addErrorPages(errorPage);}@Overridepublic int getOrder() {return 0;}}@Configuration@ConditionalOnProperty(prefix = "server.error.whitelabel", name = "enabled", matchIfMissing = true)@Conditional(ErrorTemplateMissingCondition.class)protected static class WhitelabelErrorViewConfiguration {//默认的SpringBoot错误页面private final SpelView defaultErrorView = new SpelView("<html><body><h1>Whitelabel Error Page</h1>"+ "<p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p>"+ "<div id='created'>${timestamp}</div>"+ "<div>There was an unexpected error (type=${error}, status=${status}).</div>"+ "<div>${message}</div></body></html>");@Bean(name = "error")@ConditionalOnMissingBean(name = "error")public View defaultErrorView() {return this.defaultErrorView;}// If the user adds @EnableWebMvc then the bean name view resolver from// WebMvcAutoConfiguration disappears, so add it back in to avoid disappointment.
        @Bean@ConditionalOnMissingBeanpublic BeanNameViewResolver beanNameViewResolver() {BeanNameViewResolver resolver = new BeanNameViewResolver();resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 10);return resolver;}}
}public class ErrorProperties {/*** Path of the error controller.*/@Value("${error.path:/error}")private String path = "/error";}

public class ErrorMvcAutoConfiguration {@Bean@ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)public BasicErrorController basicErrorController(ErrorAttributes errorAttributes) {return new BasicErrorController(errorAttributes, this.serverProperties.getError(),this.errorViewResolvers);}}public abstract class AbstractErrorController implements ErrorController {private final ErrorAttributes errorAttributes;private final List<ErrorViewResolver> errorViewResolvers;public AbstractErrorController(ErrorAttributes errorAttributes) {this(errorAttributes, null);}//解析错误页面protected ModelAndView resolveErrorView(HttpServletRequest request,HttpServletResponse response, HttpStatus status, Map<String, Object> model) {for (ErrorViewResolver resolver : this.errorViewResolvers) {ModelAndView modelAndView = resolver.resolveErrorView(request, status, model);if (modelAndView != null) {return modelAndView;}}return null;}}/**取出配置項:server.error.path中的值。如果沒有,則取error.path的值,如果還沒有,則默認為/error路徑*/
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {@RequestMapping(produces = "text/html")//产生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);        //如果为空,返回error视图(在ErrorMvcConfiguration中配置的@Bean)return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);}//产生json数据,其他客户端来到这个方法处理;
    @RequestMapping@ResponseBodypublic ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {Map<String, Object> body = getErrorAttributes(request,isIncludeStackTrace(request, MediaType.ALL));HttpStatus status = getStatus(request);return new ResponseEntity<>(body, status);}
}public class DefaultErrorViewResolver implements ErrorViewResolver, Ordered {private static final Map<Series, String> SERIES_VIEWS;

   private final ResourceProperties resourceProperties;static {Map<Series, String> views = new EnumMap<>(Series.class);views.put(Series.CLIENT_ERROR, "4xx");views.put(Series.SERVER_ERROR, "5xx");SERIES_VIEWS = Collections.unmodifiableMap(views);}@Overridepublic ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status,Map<String, Object> model) {ModelAndView modelAndView = resolve(String.valueOf(status), model);if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {modelAndView = resolve(SERIES_VIEWS.get(status.series()), model);}return modelAndView;}private ModelAndView resolve(String viewName, Map<String, Object> model) {//默认SpringBoot可以去找到一个页面? error/404String errorViewName = "error/" + viewName;//模板引擎可以解析这个页面地址就用模板引擎解析TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName, this.applicationContext);if (provider != null) {       //模板引擎可用的情况下返回到errorViewName指定的视图地址return new ModelAndView(errorViewName, model);}     //模板引擎不可用return resolveResource(errorViewName, model);}//private ModelAndView resolveResource(String viewName, Map<String, Object> model) {//从静态资源文件夹下解析对应的页面 error/404.htmlfor (String location : this.resourceProperties.getStaticLocations()) {try {Resource resource = this.applicationContext.getResource(location);resource = resource.createRelative(viewName + ".html");if (resource.exists()) {return new ModelAndView(new HtmlResourceView(resource), model);}}catch (Exception ex) {}}return null;}
}

静态资源文件夹路径

@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)
public class ResourceProperties {private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {"classpath:/META-INF/resources/", "classpath:/resources/","classpath:/static/", "classpath:/public/" };/*** Locations of static resources. Defaults to classpath:[/META-INF/resources/,* /resources/, /static/, /public/].*/private String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS;}

2)、如果定制错误响应

1、如何定制错误的页面
  1)、有模板引擎的情况下;error/状态码; 【将错误页面命名为 错误状态码.html 放在模板引擎文件夹里面的error文件夹下】,发生此状态码的错误就会来到 对应的页面;
      我们可以使用4xx和5xx作为错误页面的文件名来匹配这种类型的所有错误,精确优先(优先寻找精确的状态码.html);
      页面能获取的信息:
      timestamp:时间戳
      status:状态码
      error:错误提示
      exception:异常对象
      message:异常消息
      errors:JSR303数据校验的错误都在这里
  2)、没有模板引擎(模板引擎找不到这个错误页面),静态资源文件夹下找
  3)、以上都没有错误页面,就是默认来到SpringBoot默认的错误提示页面

2、如何定制错误的json数据;
  1)、自定义异常处理&返回定制json数据;

一、页面请求出错


1. 自定义异常:

public class UserNotExistException extends RuntimeException {private static final long serialVersionUID = -7200824453209817228L;public UserNotExistException() {super("用户不存在");}
}

2. Controller调用

@Controller
public class HelloController {@RequestMapping("/hello")@ResponseBodypublic String createInvoice(@RequestParam("user") String user) {if(user.equals("aaa")) {throw new UserNotExistException();}return "hello world";}
}

3. 5xx.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>5xx.html</title>
</head>
<body>timestamp:[[${timestamp}]]    <br>status:[[${status}]]    <br>error:[[${error}]]    <br>exception:[[${exception}]]    <br>errors:[[${errors}]]    <br>message:[[${message}]]    <br>
</body>
</html>

4. 正确结果

5. 错误结果

 二、json错误定制


1.编写异常处理器

@ControllerAdvice
public class MyExceptionHandler {//1、浏览器客户端返回的都是json
    @ResponseBody@ExceptionHandler(UserNotExistException.class)public Map<String,Object> handleException(Exception e){Map<String,Object> map = new HashMap<>();map.put("code","user.notexist");map.put("message",e.getMessage());return map;}
}

请求:

页面也显示json数据

但若想让浏览器返回错误页面,客户端返回json数据,且是自适应的,怎么办呢?

源码解析

@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {@RequestMapping(produces = MediaType.TEXT_HTML_VALUE)public ModelAndView errorHtml(HttpServletRequest request,HttpServletResponse response) {HttpStatus status = getStatus(request); //status就是端口号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) ? modelAndView : new ModelAndView("error", model);}}public abstract class AbstractErrorController implements ErrorController {protected HttpStatus getStatus(HttpServletRequest request) {Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");if (statusCode == null) {return HttpStatus.INTERNAL_SERVER_ERROR;}try {return HttpStatus.valueOf(statusCode);}catch (Exception ex) {return HttpStatus.INTERNAL_SERVER_ERROR;}}
}

@ControllerAdvice
public class MyExceptionHandler {@ExceptionHandler(UserNotExistException.class)public String handleException(Exception e, HttpServletRequest request){Map<String,Object> map = new HashMap<>();//传入我们自己的错误状态码  4xx 5xx/*** Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");*/request.setAttribute("javax.servlet.error.status_code",500);map.put("code","user.notexist");map.put("message","用户出错啦");request.setAttribute("ext",map);  //下面自定义异常返回结果时,将获取到此request作用域中的数据//转发到/errorreturn "forward:/error";}
}

但是这种方式无法返回map对象里自定义的数据到页面

Spring Boot 默认的实现原理如下:

public class BasicErrorController extends AbstractErrorController {   //SpringBoot 默认的返回错误html页面代码@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, isIncludeStackTrace(request, MediaType.TEXT_HTML)));response.setStatus(status.value());ModelAndView modelAndView = resolveErrorView(request, response, status, model);return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);}
  //Spring Boot 默认的返回json数据请求@RequestMappingpublic ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {Map<String, Object> body = getErrorAttributes(request,isIncludeStackTrace(request, MediaType.ALL));HttpStatus status = getStatus(request);return new ResponseEntity<>(body, status);}
}

public abstract class AbstractErrorController implements ErrorController {private final ErrorAttributes errorAttributes;protected Map<String, Object> getErrorAttributes(HttpServletRequest request,boolean includeStackTrace) {WebRequest webRequest = new ServletWebRequest(request);return this.errorAttributes.getErrorAttributes(webRequest, includeStackTrace);}
}@Order(Ordered.HIGHEST_PRECEDENCE)
public class DefaultErrorAttributesimplements ErrorAttributes, HandlerExceptionResolver, Ordered {@Overridepublic Map<String, Object> getErrorAttributes(WebRequest webRequest,boolean includeStackTrace) {Map<String, Object> errorAttributes = new LinkedHashMap<>();errorAttributes.put("timestamp", new Date());addStatus(errorAttributes, webRequest);addErrorDetails(errorAttributes, webRequest, includeStackTrace);addPath(errorAttributes, webRequest);return errorAttributes; }
}

3)、将我们的定制数据携带出去
出现错误以后,会来到/error请求,会被BasicErrorController处理,响应出去可以获取的数据是由
getErrorAttributes得到的(是AbstractErrorController(ErrorController)规定的方法);
  1、完全来编写一个ErrorController的实现类【或者是编写AbstractErrorController的子类】,放在容器中;
  2、页面上能用的数据,或者是json返回能用的数据都是通过errorAttributes.getErrorAttributes得到;
容器中DefaultErrorAttributes.getErrorAttributes();默认进行数据处理的;

@AutoConfigureBefore(WebMvcAutoConfiguration.class)
@EnableConfigurationProperties({ ServerProperties.class, ResourceProperties.class,WebMvcProperties.class })
public class ErrorMvcAutoConfiguration {private final ServerProperties serverProperties;//当容器中没有ErrorAttributes类型的bean时,才走默认的,所以我们自定义ErrorAttributes的实现类就可以实现定制化
    @Bean@ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT)public DefaultErrorAttributes errorAttributes() {return new DefaultErrorAttributes(this.serverProperties.getError().isIncludeException());}
}

Spring Boot1.5.10版本

//给容器中加入我们自己定义的ErrorAttributes,用其实现类,避免重写多个无需改造的方法
@Component
public class MyErrorAttributes extends DefaultErrorAttributes {@Overridepublic Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes,boolean includeStackTrace) {Map<String, Object> map = super.getErrorAttributes(requestAttributes,includeStackTrace);map.put("company","everjiankang"); //自定义属性    map.put("name","超轶绝尘");return map;}
}

Spring Boot 2.0 版本

import java.util.Map;
//
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;  servlet的可以成功执行
//import org.springframework.boot.web.reactive.error.DefaultErrorAttributes;   reactive 也有这个类,但是执行不了
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.WebRequest;@Component
public class MyErrorAttributes extends DefaultErrorAttributes{@Overridepublic Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {    //获取到上文中异常处理类中设置到request作用域中的“ext”属性  requeste.setAtrribute("exgt",map);     Map<String,Object> extMap = (Map<String,  Object) webRequest.getAttribute("ext", RequestAttributes.SCOPE_REQUEST);
        Map<String,Object> map =  super.getErrorAttributes(webRequest, includeStackTrace);map.put("name", "xiaochao");     map.put("ext", extMap); //将异常处理类中的自定义信息返回给页面      return map;}}

public interface WebRequest extends RequestAttributes {   

}

 public interface RequestAttributes {

    int SCOPE_REQUEST = 0;

    int SCOPE_SESSION = 1;

 }


Spring Webflux 版本,执行未成功

在Spring boot 2.1.0版本中,第一个参数变成了org.springframework.web.reactive.function.server.ServerRequest类型,需要引入jar包

但是此段代码不能适用。如何自定义详情查看Spring Boot官方文档

Spring 5 之 Spring Webflux 开发 Reactive 应用

<!-- 此依赖 会依赖于Netty -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId>    <!--【改】增加“flux”四个字符-->
</dependency>

//import org.springframework.boot.web.reactive.error.DefaultErrorAttributes;   reactive 也有这个类,但是执行不了


转载于:https://www.cnblogs.com/guchunchao/p/10011332.html

16. Spring boot 错误页面相关推荐

  1. Spring/Spring Boot错误页面处理的多种方式(404 not found等)

    Spring/Spring Boot错误页面处理的多种方式(404 not found等) 简单来说, tomcat容器会根据error-page的内容forward到指定location(会再走一次 ...

  2. SpringBoot2.1.5(16)--- Spring Boot的日志详解

    SpringBoot2.1.5(16)--- Spring Boot的日志详解 市面上有许多的日志框架,比如 JUL( java.util.logging), JCL( Apache Commons ...

  3. Spring Boot错误–创建在类路径资源DataSourceAutoConfiguration中定义的名称为“ dataSource”的bean时出错...

    大家好,如果您使用的是Spring Boot,并且遇到诸如"无法为数据库类型NONE确定嵌入式数据库驱动程序类"或"在类路径资源ataSourceAutoConfigur ...

  4. Spring Boot错误处理机制以及定制自己的错误页面

    在我们使用Spring Boot的过程中肯定有遇到过发生错误的时候,这个时候可能页面上出现的就是Spring Boot默认的错误界面,有的时候我们希望能显示我们自己设置的错误界面,或者携带我们自己的错 ...

  5. Spring boot错误处理机制

    错误处理机制 当程序发生错误的时候 浏览器访问 Spring boot提供了一个默认的错误页面 包括错误状态码.错误类型.提示消息.时间 客户端访问 当程序发生错误的时候 默认响应了一个json数据 ...

  6. Spring Boot html页面解析之jsoup

    目的 我们要对一个页面进行数据抓取,并导出doc文档 html解析器 jsoup 直接解析某个URL地址.HTML文本内容.它提供了一套非常省力的API,可通过DOM,CSS以及类似于JQuery的操 ...

  7. spring boot错误: 找不到或无法加载主类

    eclipse启动spring boot项目时出现问题:springboot错误: 找不到或无法加载主类 解决办法: 通过cmd命令行,进入项目目录进行,mvn clean install 进行编译, ...

  8. Spring boot错误处理原理

    错误处理原理 ErrorMvcAutoConfiguration 错误处理自动配置 自动配置 给容器中添加了以下组件 1.DefaultErrorAttributes 2.BasicErrorCont ...

  9. Spring Boot 错误 Configuration Annotation Proessor not found in classpath

    出现spring boot Configuration Annotation Proessor not found in classpath的提示是在用了@ConfigurationPropertie ...

  10. 16. Spring Boot使用Druid(编程注入)【从零开始学Spring Boot】

    转载:http://blog.csdn.net/linxingliang/article/details/52001744 在上一节使用是配置文件的方式进行使用druid,这里在扩散下使用编程式进行使 ...

最新文章

  1. VS2015占内存大吗?_手游越来越占内存,80%的手机安装一个大游戏就满了,厂商肉搏...
  2. Java设计模式 - 单例模式详解(下)
  3. hdu5720_贪心
  4. android jar导出,Android项目导出jar包的小技巧
  5. 快速在指定文件夹打开命令行
  6. linux手动rpm升级glibc,升级glibc库到glibc-2.14.1
  7. 学习SQL Server这一篇就够了
  8. java语言的入门开始介绍
  9. ideaIU安装教程
  10. 电脑ps计算机磨皮,入门:PS最简单的磨皮方法
  11. Win10样式管理与夜间模式
  12. Android内存泄漏总结,成功拿下大厂offer
  13. DEV编写C语言方法简介
  14. 多线程实现 qq 群聊的服务端和客户端
  15. python bmp转jpg_python bmp转换为jpg 并删除原图
  16. 运行yolov5-5.0出现AttributeError: Can‘t get attribute ‘SPPF‘ 正确解决方法
  17. 用AI画一只漂亮的羽毛
  18. java获取中文字符串汉语拼音和首字母
  19. 数据中心机房监控室效果图
  20. dmesg 命令详解

热门文章

  1. 邮件助手工具哪个好用?哪个企业群发邮件的软件好用?
  2. 「LOJ#10015」「一本通 1.2 练习 2」扩散(并查集
  3. 瑞数系列_商标局公告采集
  4. Chloe.Orm多表连接查询 (二)
  5. 怎么用ping命令测试网速
  6. cad图纸怎么看懂_快速看懂cad图纸的教程全解
  7. 必要的系统组件未能正常运行,请修复Adobe Flash Player
  8. MySQL服务器的超级管理员名称是_mysql服务器忘记了超级管理员root密码
  9. Python学习笔记:第十四站 百宝箱
  10. JavaScript 实现延迟合并处理任务