解决俩个问题:
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 webServerFactoryCustomizer() {
return new WebServerFactoryCustomizer() {
@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
愿世界没有Bug
对不起遇到了错误400
其他页面雷同
接下来验证我们的错误页:输入错误的访问路径,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
愿世界没有Bug
Sorry,异常了(自定义)
搞定,接下来看一下结果:首先搞一个算术异常,输入访问路径->http://localhost/mul?param=0
@RequestMapping(value = "/mul")
public int mulParam(int param) {
return 9/param;
}
访问结果如下图:
如此可以将所有异常信息展示出来,或是后台搞到数据库中,查找问题时,根据错误码,错误信息精准定位问题。不需要程序员对所有的Exception都了解。上手简单,排难精准。