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

 更新时间:2021年10月14日 09:48:33   作者:YO_RUI  
这篇文章主要介绍了Springboot错误页面和错误信息定制操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

SpringBoot2.1.4错误处理机制

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

1、错误页面自定义

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

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

private ModelAndView resolve(String viewName, Map<String, Object> 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<String, Object> 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<Series, String> 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(HttpServletRequest request, HttpStatus status, Map<String, Object> 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<String, Object> 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<Map<String, Object>> error(HttpServletRequest request) {
        Map<String, Object> body = this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.ALL));
        HttpStatus status = this.getStatus(request);
        return new ResponseEntity(body, status);
    }

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

    public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
        Map<String, Object> 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<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
        // 获取包含错误信息的map
        Map<String, Object> 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;
    }
}

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

移动端:

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

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • java使用jacob.jar将word转pdf

    java使用jacob.jar将word转pdf

    这篇文章主要为大家详细介绍了java利用jacob.jar将word转pdf,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-12-12
  • Java如何将字符串String转换为整型Int

    Java如何将字符串String转换为整型Int

    这篇文章主要介绍了Java如何将字符串String转换为整型Int,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的朋友可以参考一下
    2022-08-08
  • Java根据Request获取客户端IP

    Java根据Request获取客户端IP

    这篇文章主要介绍了Java根据Request获取客户端IP的方法,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2017-05-05
  • java中Lamda表达式讲解

    java中Lamda表达式讲解

    本文详细讲解了java中的Lamda表达式,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-12-12
  • 一文带你掌握JPA实体类注解

    一文带你掌握JPA实体类注解

    这篇文章主要给大家详细介绍一下 JPA 实体类中的注解,文中的示例代码讲解详细,对我们学习Java有一定的帮助,感兴趣的小伙伴可以了解一下
    2023-01-01
  • java 基础之JavaBean属性命名规范问题

    java 基础之JavaBean属性命名规范问题

    这篇文章主要介绍了java 基础之JavaBean属性命名规范问题的相关资料,需要的朋友可以参考下
    2017-05-05
  • Java中的SpringAOP、代理模式、常用AspectJ注解详解

    Java中的SpringAOP、代理模式、常用AspectJ注解详解

    这篇文章主要介绍了Java中的SpringAOP、代理模式、常用AspectJ注解详解,Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务,例如审计和事务管理进行内聚性的开发,需要的朋友可以参考下
    2023-09-09
  • Java实现同步枚举类数据到数据库

    Java实现同步枚举类数据到数据库

    这篇文章主要为大家详细介绍了Java实现同步枚举类数据到数据库,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-08-08
  • Spring Cloud入门教程之Zuul实现API网关与请求过滤

    Spring Cloud入门教程之Zuul实现API网关与请求过滤

    这篇文章主要给大家介绍了关于Spring Cloud入门教程之Zuul实现API网关与请求过滤的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2018-05-05
  • Java字节流与基本数据类型的转换实例

    Java字节流与基本数据类型的转换实例

    本篇文章主要介绍了Java字节流与基本数据类型的转换实例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-06-06

最新评论