解决俩个问题:
1> 用户体验:当我们请求路径写错时,浏览器显示一个"Whitelabel Error Page",对用户来说体验不友好。
2> 错误码分类:当浏览器请求出现异常时,有时不仅仅是400/404/500..还有Exception异常,对程序员来说不容易识别错误,此时考虑增加全局错误处理。
以编程方式配置嵌入式servlet容器,可以通过注册实现 WebServerFactoryCustomizer 接口的Spring bean,该接口可以直接修改servlet容器配置。例如:
server.port
),要绑定的接口地址server.address
,等等。server.servlet.session.persistence
),会话超时(server.servlet.session.timeout
),会话数据(server.servlet.session.store-dir
)的位置以及会话cookie配置(server.servlet.session.cookie.*
)。server.error.path
)首先创建一个错误页控制类:MyErrorPageController.java
package com.example.demo.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class MyErrorPageController { @RequestMapping("error-404") public String toPage404(){ return "error/error-404"; } @RequestMapping("error-400") public String toPage400(){ return "error/error-400"; } @RequestMapping("error-500") public String toPage500(){ return "error/error-500"; } }
然后创建错误页类:MyErrorPageConfig.java
package com.example.demo.config; import org.springframework.boot.web.server.ConfigurableWebServerFactory; import org.springframework.boot.web.server.ErrorPage; import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpStatus; @Configuration public class MyErrorPageConfig { /** * 以编程方式配置嵌入式servlet容器,可以通过注册实现该 WebServerFactoryCustomizer 接口的Spring bean * TomcatServletWebServerFactory,JettyServletWebServerFactory并且UndertowServletWebServerFactory 是专用变体, ConfigurableServletWebServerFactory分别为Tomcat,Jetty和Undertow提供了额外的自定义setter方法。 * @return */ @Bean public WebServerFactoryCustomizer<ConfigurableWebServerFactory> webServerFactoryCustomizer() { return new WebServerFactoryCustomizer<ConfigurableWebServerFactory>() { @Override public void customize(ConfigurableWebServerFactory factory) { // 对嵌入式servlet容器的配置 // factory.setPort(8081); /* 注意:new ErrorPage(stat, path);中path必须是页面名称,并且必须“/”开始。 底层调用了String.java中如下方法: public boolean startsWith(String prefix) { return startsWith(prefix, 0); }*/ ErrorPage errorPage400 = new ErrorPage(HttpStatus.BAD_REQUEST, "/error-400"); ErrorPage errorPage404 = new ErrorPage(HttpStatus.NOT_FOUND, "/error-404"); ErrorPage errorPage500 = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error-500"); factory.addErrorPages(errorPage400, errorPage404, errorPage500); } }; } }
最后创建相关的页面:error/error-404.html/error/error-400.html/error/error-500.html
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"/> <title>愿世界没有Bug</title> </head> <body> <h1>对不起遇到了错误400</h1> </body> </html>
接下来验证我们的错误页:输入错误的访问路径,F12查看请求过程及页面展示!
首先定义一个错误的对象信息:ErrorInfo.java
package com.example.demo.bean; public class ErrorInfo { // 错误类别码 public Integer code; // 错误信息 public String message; // 映射路径 public String url; // get/set方法省略 }
然后创建一个控制层切面错误处理类:GlobalExceptionHandler.java
package com.example.demo.advice; import com.example.demo.bean.ErrorInfo; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; @ControllerAdvice // 作为一个控制层的切面处理 // @RestControllerAdvice // Rest风格,作为一个控制层的切面处理 public class GlobalExceptionHandler { private static final String DEFAULT_ERROR_VIEW = "error"; // 定义错误显示页,error.html private static final Integer INIT_ERROR_CODE = 500; // 定义初始错误码 @ExceptionHandler(value = Exception.class) // 所有的异常都是Exception子类 public ModelAndView defaultErrorHandler(HttpServletRequest request, Exception e) { ModelAndView mv = new ModelAndView(DEFAULT_ERROR_VIEW); Integer errorCode = INIT_ERROR_CODE; // 可以自己定制错误分类对象信息 ErrorInfo errorInfo = new ErrorInfo(); // 对错误类型进行分类 String header = request.getHeader("content-type"); if(header != null && header.contains("json")){ errorCode = 300; // json异常 } else if (e instanceof ArithmeticException) { errorCode = 100; // 算术异常 } else if (e instanceof NullPointerException) { errorCode = 200; // 空指针异常 } else { errorCode = 999; // 其他异常 } // 对错误码进行判断 switch (errorCode) { case 100: errorInfo.setCode(errorCode); // 将错误码传递过去 break; case 200: errorInfo.setCode(errorCode); // 将错误码传递过去 break; case 300: errorInfo.setCode(errorCode); // 将错误码传递过去 break; case 500: errorInfo.setCode(INIT_ERROR_CODE); // 将错误码传递过去 break; case 999: errorInfo.setCode(INIT_ERROR_CODE); // 将错误码传递过去 break; default: errorInfo.setCode(1000); // 将错误码传递过去 break; } errorInfo.setMessage(e.getMessage());// 将异常对象传递过去 errorInfo.setUrl(request.getRequestURL().toString());// 获得请求的路径 mv.addObject("errorInfo", errorInfo); mv.setViewName("error/"+DEFAULT_ERROR_VIEW); return mv; } }
最后创建错误页面:error/error.html
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"/> <title>愿世界没有Bug</title> </head> <body> <h1>Sorry,异常了(自定义)</h1> <div> <p th:text="'错误码:' + ${errorInfo.code}"/> <p th:text="'映射路径:' + ${errorInfo.url}"/> <p th:text="'错误信息:' + ${errorInfo.message}"/> </div> </body> </html>
搞定,接下来看一下结果:首先搞一个算术异常,输入访问路径->http://localhost/mul?param=0
@RequestMapping(value = "/mul") public int mulParam(int param) { return 9/param; }
访问结果如下图:
如此可以将所有异常信息展示出来,或是后台搞到数据库中,查找问题时,根据错误码,错误信息精准定位问题。不需要程序员对所有的Exception都了解。上手简单,排难精准。
本文分享自微信公众号 - Java编程指南(JavaXxzyfx),作者:Java编程指南
原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。
原始发表时间:2019-07-16
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
我来说两句