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;
    }
}

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

移动端:

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

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

相关文章

  • mybatis中的扩展实现源码解析

    mybatis中的扩展实现源码解析

    这篇文章主要介给大家绍了关于mybatis中扩展实现的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-01-01
  • 新手入门Jvm--Jvm垃圾回收

    新手入门Jvm--Jvm垃圾回收

    JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的
    2021-06-06
  • 详解Struts2标签遍历

    详解Struts2标签遍历

    这篇文章主要介绍了Struts2标签遍历,以及相关的用法示例,需要的朋友可以参考下。
    2017-09-09
  • Java中的Random()函数及两种构造方法

    Java中的Random()函数及两种构造方法

    Java中存在着两种Random函数分别是java.lang.Math.Random和java.util.Random,文中给大家介绍了random()的两种构造方法,感兴趣的朋友跟随小编一起看看吧
    2018-11-11
  • 2022最新Java泛型详解(360度无死角介绍)

    2022最新Java泛型详解(360度无死角介绍)

    Java泛型(generics)是JDK5中引入的一个新特性,泛型提供了 编译时类型安全监测机制,该机制允许我们在编译时检测到非法的类型数据结构,这篇文章主要介绍了java泛型的基本概念及使用详解,感兴趣的朋友跟随小编一起看看吧
    2022-10-10
  • Java线程本地变量导致的缓存问题解决方法

    Java线程本地变量导致的缓存问题解决方法

    使用缓存可以缓解大流量压力,显著提高程序的性能,我们在使用缓存系统时,尤其是大并发情况下,经常会遇到一些疑难杂症,这篇文章主要给大家介绍了关于Java线程本地变量导致的缓存问题的解决方法,需要的朋友可以参考下,
    2024-08-08
  • Eclipse操作SVN时中断锁定,文件的解锁方法

    Eclipse操作SVN时中断锁定,文件的解锁方法

    这篇文章主要介绍了Eclipse操作SVN时中断锁定,文件的解锁方法,需要的朋友可以参考下
    2014-08-08
  • SpringBoot集成P6spy实现自定义SQL日志打印

    SpringBoot集成P6spy实现自定义SQL日志打印

    本文主要介绍了SpringBoot集成P6spy实现自定义SQL日志打印,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • Spring中字段格式化的使用小结

    Spring中字段格式化的使用小结

    Spring提供的一个core.convert包 是一个通用类型转换系统。它提供了统一的 ConversionService  API和强类型的Converter SPI,用于实现从一种类型到另一种类型的转换逻辑,这篇文章主要介绍了Spring中字段格式化的使用详解,需要的朋友可以参考下
    2022-06-06
  • java中的FileInputStream三种read()函数用法

    java中的FileInputStream三种read()函数用法

    这篇文章主要介绍了java中的FileInputStream三种read()函数用法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-12-12

最新评论