Springboot错误页面和错误信息定制操作

网友投稿 230 2022-09-22


Springboot错误页面和错误信息定制操作

目录1、错误页面自定义2、错误数据2.1 默认错误数据2.2 自定义错误数据

SpringBoot2.1.4错误处理机制

前面一片已经介绍了springboot错误处理的机制,其实从整个分析过程中我们已经大概知道如何定制了。

1、错误页面自定义

springboot有个默认的错误页面,但是开发时错误页面肯定是自己定义的。那该如何定义?

在DefaultErrorViewResolver类中有下面几个方法,

private ModelAndView resolve(String viewName, Map model) {

// 定义视图名,这里我们可以确定视图名:error/错误码,例如:error/404,

String errorViewName = "error/" + viewName;

// 这里结合上面的errorViewName,其实就是在template目录下的error目录进行查找

// 我们默认情况下是没有error目录,这里的provide最终值为null,代码较多就不一一展示,有兴趣的可以跟下去

TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName, this.applicationContext);

// 根据判定,这里会接着调用下面的resolveResource方法

return provider != null ? new ModelAndView(errorViewName, model) : this.resolveResource(errorViewName, model);

}

private ModelAndView resolveResource(String viewName, Map model) {

// getStaticLocations()获取的是静态资源路径:"classpath:/META-INF/resources/", "classpath:/resources/","classpath:/static/", "classpath:/public/"

String[] var3 = this.resourceProperties.getStaticLocations();

int var4 = var3.length;

// 遍历上面的4个静态资源路径

for(int var5 = 0; var5 < var4; ++var5) {

String location = var3[var5];

try {

Resource resource = this.applicationContext.getResource(location);

// 创建resource对象,例如error/404.html

resource = resource.createRelative(viewName + ".html");

// 查找在对应静态资源目录下是否有上面的这个资源对象,有就创建视图对象

if (resource.exists()) {

return new ModelAndView(new DefaultErrorViewResolver.HtmlResourceView(resource), model);

}

} catch (Exception var8) {

;

}

}

// 都没找到就返回null,默认情况下是不存在error目录的,所以这里最终返回null

return null;

}

在解析错误视图界面时,会依次去这几个目录:template/、 classpath:/META-INF/resources/ 、 classpath:/resources/、 classpath:/static/ 、classpath:/public/,在这些目录下的error目录里找文件名是错误状态码的页面文件(404、500…)。

所以我们可以在这些目录下创建error目录,在里面创建HTML页面,但是在template下面的页面才能被thymeleaf模板引擎识别。

现在再去访问不存在路径时效果如下,因为是404错误

但是,错误状态码是很多的,不可能将所有的页面全部写出来,在DefaultErrorViewResolver类中有下面一段静态代码:

static {

Map views = new EnumMap(Series.class);

views.put(Series.CLIENT_ERROR, "4xx");

views.put(Series.SERVER_ERROR, "5xx");

SERIES_VIEWS = Collections.unmodifiableMap(views);

}

向map中添加了两个数据"4xx"、“5xx”,这个表示4开头或者5开头的错误,并且看到下面的:

public ModelAndView resolveErrorView(HttpServletRequehttp://st request, HttpStatus status, Map model) {

// 按状态码精确查找

ModelAndView modelAndView = this.resolve(String.valueOf(status.value()), model);

// 若精确查找未找到再来模糊查找

// status.series()方法可以自己看一下,就是在获取错误码的首位

if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {

modelAndView = this.resolve((String)SERIES_VIEWS.get(status.series()), model);

}

return modelAndView;

}

上面注释写的很清楚了,springboot首先按错误精确查找,若为找到再以错误码首位模糊查找,所以我们也可以将错误页面文件定义成 4xx.html 或者 5xx.html。

2、错误数据

2.1 默认错误数据

页面搞定了,那默认的错误数据有哪些呢?响应浏览器或者移动端错误请求的两个方法中都同时用到了getErrorAttributes方法,这个方法就是用来获取错误数据的。

public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {

HttpStatus status = this.getStatus(request);

Map model = Collections.unmodifiableMap(this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.TEXT_HTML)));

response.setStatus(status.value());

ModelAndView modelAndView = this.resolveErrorView(request, response, status, model);

return modelAndView != null ? modelAndView : new ModelAndView("error", model);

}

@RequestMapping

public ResponseEntity> error(HttpServletRequest request) {

Map

HttpStatus status = this.getStatus(request);

return new ResponseEntity(body, status);

}

这个方法是属于DefaultErrorAttributes类的,用来定义默认错误属性。

public Map getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {

Map errorAttributes = new LinkedHashMap();

errorAttributes.put("timestamp", new Date());

this.addStatus(errorAttributes, webRequest);

this.addErrorDetails(errorAttributes, webRequest, includeStackTrace);

this.addPath(errorAttributes, webRequest);

return errorAttributes;

}

从这个方法及其里面调用其他几个方法跟踪可以知道有如下错误属性:

timestamp:时间戳

status:错误码

error:错误名

exception:异常类型

message:异常信息

trace:错误栈

path:错误路径

2.2 自定义错误数据

下面模拟一个场景,发起一个请求,然后触发一个自定义异常,自己添加一些错误信息,在页面上显示出来。 exception:

public class MyException extends RuntimeException {

public MyException() {

super("发生异常了");

}

}

Controller:

@ResponseBody

@RequestMapping("/hello")

public String hello(@RequestParam("username") String username){

// 当username值为aaa是抛出异常

if(username.equals("aaa")){

throw new MyException();

}

return "hello";

}

为了处理异常还要定义个异常处理器,关键点1:注意设置状态码的注释:

@ControllerAdvice

public class ExceptionController {

@ExceptionHandler(MyException.class)

public String f(HttpServletRequest request){

// 这里要更改状态码,前面访问路径是没有问题的,所以状态码为200

// 若想要进入springboot错误处理流程,必须重设状态码

// 并且其key值为:javax.servlet.error.status_code

request.setAttribute("javax.servlet.error.status_code",500);

// 这里可以添加信息到request中,到后面的取出添加到map中

request.setAttribute("data","我的错误消息");

// 转发到 /error请求,交给springboot处理

return "forward:/error";

}

}

关键点2,因为我们的错误信都是在DefaultErrorAttributes类中的getErrorAttributes方法中获取的,若只是到上面步骤为止,那么在移动端将无法获取到添加的data,所以为止同时使用浏览器和移动端,我们还必须创建一个类继承DefaultErrorAttributes类,重写getErrorAttributes方法,在这里才是真正的添加自定义的数据。

MyErrorAttribute:

// 注意,给类必须添加到容器中,否则不生效

// 添加后将会覆盖原有的DefaultErrorAttributes,采用我们自己的MyErrorAtribute

@Component

public class MyErrorAtribute extends DefaultErrorAttributes {

@Override

public Map getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {

// 获取包含错误信息的map

Map map = super.getErrorAttributes(webRequest, includeStackTrace);

// 添加自己的错误数据

map.put("company","lr");

//获取转发过来时添加的数据

// 第二个参数表示在哪个域中获取,0:request,1:session

String data = (String)webRequest.getAttribute("data", 0);

map.put("data",data); // 添加到map

return map;

}

}

然后我们测试,浏览器端:

移动端:

这样,我们错误页面,错误消息自定义,浏览器和移动端适配都解决了。

HttpStatus status = this.getStatus(request);

return new ResponseEntity(body, status);

}

这个方法是属于DefaultErrorAttributes类的,用来定义默认错误属性。

public Map getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {

Map errorAttributes = new LinkedHashMap();

errorAttributes.put("timestamp", new Date());

this.addStatus(errorAttributes, webRequest);

this.addErrorDetails(errorAttributes, webRequest, includeStackTrace);

this.addPath(errorAttributes, webRequest);

return errorAttributes;

}

从这个方法及其里面调用其他几个方法跟踪可以知道有如下错误属性:

timestamp:时间戳

status:错误码

error:错误名

exception:异常类型

message:异常信息

trace:错误栈

path:错误路径

2.2 自定义错误数据

下面模拟一个场景,发起一个请求,然后触发一个自定义异常,自己添加一些错误信息,在页面上显示出来。 exception:

public class MyException extends RuntimeException {

public MyException() {

super("发生异常了");

}

}

Controller:

@ResponseBody

@RequestMapping("/hello")

public String hello(@RequestParam("username") String username){

// 当username值为aaa是抛出异常

if(username.equals("aaa")){

throw new MyException();

}

return "hello";

}

为了处理异常还要定义个异常处理器,关键点1:注意设置状态码的注释:

@ControllerAdvice

public class ExceptionController {

@ExceptionHandler(MyException.class)

public String f(HttpServletRequest request){

// 这里要更改状态码,前面访问路径是没有问题的,所以状态码为200

// 若想要进入springboot错误处理流程,必须重设状态码

// 并且其key值为:javax.servlet.error.status_code

request.setAttribute("javax.servlet.error.status_code",500);

// 这里可以添加信息到request中,到后面的取出添加到map中

request.setAttribute("data","我的错误消息");

// 转发到 /error请求,交给springboot处理

return "forward:/error";

}

}

关键点2,因为我们的错误信都是在DefaultErrorAttributes类中的getErrorAttributes方法中获取的,若只是到上面步骤为止,那么在移动端将无法获取到添加的data,所以为止同时使用浏览器和移动端,我们还必须创建一个类继承DefaultErrorAttributes类,重写getErrorAttributes方法,在这里才是真正的添加自定义的数据。

MyErrorAttribute:

// 注意,给类必须添加到容器中,否则不生效

// 添加后将会覆盖原有的DefaultErrorAttributes,采用我们自己的MyErrorAtribute

@Component

public class MyErrorAtribute extends DefaultErrorAttributes {

@Override

public Map getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {

// 获取包含错误信息的map

Map map = super.getErrorAttributes(webRequest, includeStackTrace);

// 添加自己的错误数据

map.put("company","lr");

//获取转发过来时添加的数据

// 第二个参数表示在哪个域中获取,0:request,1:session

String data = (String)webRequest.getAttribute("data", 0);

map.put("data",data); // 添加到map

return map;

}

}

然后我们测试,浏览器端:

移动端:

这样,我们错误页面,错误消息自定义,浏览器和移动端适配都解决了。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:BGP协议与配置(bgp网络协议)
下一篇:路由器双wan口如何做到主备无感冗余?(副路由器wan口)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~