SpringBoot——定制错误页面及原理

news2025/1/10 20:50:30

优质博文:IT-BLOG-CN

一、SpringBoot 默认的错误处理机制

【1】浏览器返回的默认错误页面如下:

浏览器发送请求的请求头信息如下: text/html会在后面的源码分析中说到。

【2】如果是其他客户端,默认则响应错误的 JSON字符串,如下所示:

其他客户端发送请求的请求头信息如下: */* 源码中解释。

二、原理分析

参照ErrorMvcAutoConfiguration类: 错误处理的自动配置类,以下4项为此类的重要信息。

【1】ErrorMvcAutoConfiguration.ErrorPageCustomizer: 当系统出现 4xx或者 5xx之类的错误时,ErrorPageCustomizer就会生效(定制错误的响应规则),根据如下源码可知,将会来到/error请求。

@Bean
public ErrorMvcAutoConfiguration.ErrorPageCustomizer errorPageCustomizer() {
	return new ErrorMvcAutoConfiguration.ErrorPageCustomizer(this.serverProperties);
}

//进入ErrorPageCustomizer方法,发现registerErrorPages方法:注册一个错误也
private static class ErrorPageCustomizer implements ErrorPageRegistrar, Ordered {
	private final ServerProperties properties;

	protected ErrorPageCustomizer(ServerProperties properties) {
		this.properties = properties;
	}

	public void registerErrorPages(ErrorPageRegistry errorPageRegistry) {
		ErrorPage errorPage = new ErrorPage(this.properties.getServletPrefix() + 
								this.properties.getError().getPath());
		errorPageRegistry.addErrorPages(new ErrorPage[]{errorPage});
	}
}

//进入this.properties.getError().getPath()方法,获取如下信息,得到/error请求。
@Value("${error.path:/error}")
private String path = "/error";//系统出现错误以后来到error请求进行处理;(web.xml注册的错误页面规则)

【2】BasicErrorController 处理 /error错误请求: 注意:text/html*/*就是在此处生效。

@Bean
@ConditionalOnMissingBean(
    value = {ErrorController.class},
    search = SearchStrategy.CURRENT
)
public BasicErrorController basicErrorController(ErrorAttributes errorAttributes) {
    return new BasicErrorController(errorAttributes, this.serverProperties.getError(), this.errorViewResolvers);
}

//进入BasicErrorController对象,获取如下信息
@Controller
@RequestMapping({"${server.error.path:${error.path:/error}}"})
public class BasicErrorController extends AbstractErrorController {
    private final ErrorProperties errorProperties;

    public BasicErrorController(ErrorAttributes errorAttributes, ErrorProperties errorProperties) {
        this(errorAttributes, errorProperties, Collections.emptyList());
    }

    @RequestMapping(
        produces = {"text/html"}//产生html类型的数据;浏览器发送的请求来到这个方法处理
    )
    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
    @ResponseBody//产生json数据,其他客户端来到这个方法处理;
    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);
    }
}

如上代码中提到的错误页面解析代码,进入此方法: this.resolveErrorView(request, response, status, model);

protected ModelAndView resolveErrorView(HttpServletRequest request, HttpServletResponse response, HttpStatus status, Map<String, Object> model) {
	Iterator var5 = this.errorViewResolvers.iterator();
	ModelAndView modelAndView;
	do {
		//从所有的ErrorViewResolver得到ModelAndView
		if(!var5.hasNext()) {
			return null;
		}

		ErrorViewResolver resolver = (ErrorViewResolver)var5.next();
		modelAndView = resolver.resolveErrorView(request, status, model);
	} while(modelAndView == null);

	return modelAndView;
}

【3】最终的响应页面是由DefaultErrorViewResolver解析得到的: 最重要的信息是,SpringBoot默认模板引擎的/error目录下获取 ‘status’.xml 错误页面,也可以通过4xx.xml来统配 404.xml和 400.xml等等,但是优先获取精准的页面。如果模板引擎中不存在,则会从静态页面中获取错误页面。否则返回系统默认错误页面。

 @Bean
 @ConditionalOnBean({DispatcherServlet.class})
 @ConditionalOnMissingBean
 public DefaultErrorViewResolver conventionErrorViewResolver() {
		return new DefaultErrorViewResolver(this.applicationContext, this.resourceProperties);
	}

//进入DefaultErrorViewResolver类中
public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
	ModelAndView modelAndView = this.resolve(String.valueOf(status), model);
	if(modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {

		//调用时viewname = status ***重要
		modelAndView = this.resolve((String)SERIES_VIEWS.get(status.series()), model);
	}

	return modelAndView;
}

private ModelAndView resolve(String viewName, Map<String, Object> model) {

	//默认SpringBoot可以去找到一个页面? error/404
	String errorViewName = "error/" + viewName;

	//模板引擎可以解析这个页面地址就用模板引擎解析
	TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.
	getProvider(errorViewName, this.applicationContext);

	//模板引擎可用的情况下返回到errorViewName指定的视图地址,
	//当模板引擎不可用,就在静态资源文件夹下找errorViewName对应的页面 error/404.html
	return provider != null?new ModelAndView(errorViewName, model):this.resolveResource(errorViewName, model);
}

【4】DefaultErrorAttributes: 在页面添加错误信息,供我们使用。

@Bean
@ConditionalOnMissingBean(
	value = {ErrorAttributes.class},
	search = SearchStrategy.CURRENT
)
public DefaultErrorAttributes errorAttributes() {
	return new DefaultErrorAttributes();
}

//进入DefaultErrorAttributes类中,发现此方法给视图中添加了status状态等信息,供我们使用。
public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) {
	Map<String, Object> errorAttributes = new LinkedHashMap();
	errorAttributes.put("timestamp", new Date());
	this.addStatus(errorAttributes, requestAttributes);
	this.addErrorDetails(errorAttributes, requestAttributes, includeStackTrace);
	this.addPath(errorAttributes, requestAttributes);
	return errorAttributes;
}

三、定制错误 JSON数据

【1】自定义异常处理类,返回定制的 JSON数据。通过上述的分析,我们得知:
 ①、可以完全编写一个ErrorController的实现类,或者继承AbstractErrorController的子类,放入容器中。
 ②、也可以自定义异常处理类,返回 JSON数据。
 ③、页面上的数据或 JSON返回的数据都是可以通过errorAttributes.getErrorAttributes得到的。我们可以自定义属于自己的ErrorAttributes

//首先我们可以通过自定义异常处理,来确定返回的数据,但这个不够灵活,我们可以与③结合使用
/**
 * @RequestMapping启动应用后,被 @ExceptionHandler、@InitBinder、@ModelAttribute 注解的方法,都会作用在 被 @RequestMapping
 * 注解的方法上。
 */
@ControllerAdvice
public class MyExceptionHandler {
    @ResponseBody
    @ExceptionHandler(UserNotExistException.class)
    public Map<String,Object> handlerException(Exception e, HttpServletRequest request){
        Map<String,Object> map = new HashMap<String,Object>();
        request.setAttribute("javax.servlet.error.status_code","500");
        map.put("code","user.notexist");
        map.put("message",e.getMessage());
        return map;
    }
}

//③自定义ErrorAttributes,一定要加入容器
@Component
public class MyErrorAttributes extends DefaultErrorAttributes{
    @Override
    public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) {
        //获取默认的配置,在此基础上添加自己的需求
        Map<String, Object> map = super.getErrorAttributes(requestAttributes, includeStackTrace);
        //自定义自己需要的属性
        map.put("company","yintong");

        //获取我们在异常处理类中添加的信息,
        /*注意:当我们需要结合使用的时候异常处理必须return "forward:/error";将请求转发出去,不能直接返回map对象,
        同时要去掉@responseBody注解,否则ErrorAttributes不生效*/
        map.put("ext",requestAttributes.getAttribute("ext",requestAttributes.SCOPE_REQUEST));
        return map;
    }
}

【2】效果展示:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1250299.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

redis的性能管理、主从复制和哨兵模式

一、redis的性能管理 redis的数据时缓存在内存中的 查看系统内存情况 info memory used_memory:853688 redis中数据占用的内存 used_memory_rss:10522624 redis向操作系统申请的内存 used_memory_peak:853688 redis使用内存的峰值 系统巡检&#xff1a;硬件巡检、数据库 n…

【从浅识到熟知Linux】基本指令之rmdir和rm

&#x1f388;归属专栏&#xff1a;从浅学到熟知Linux &#x1f697;个人主页&#xff1a;Jammingpro &#x1f41f;每日一句&#xff1a;加油努力&#xff0c;这次写完真的真的真的要去干饭了&#xff01; 文章前言&#xff1a;本文介绍rmdir和rm指令用法并给出示例和截图。 文…

【Java】智慧工地云平台源码(APP+SaaS模式)

在谈论“智慧工地”之前&#xff0c;我们首先得知道传统工地为什么跟不上时代了。 说起传统工地&#xff0c;总有一些很突出的问题&#xff1a;比如工友多且杂&#xff0c;他们是否入场、身体状况如何&#xff0c;管理人员只能依靠巡查、手工纪录来判断&#xff0c;耗时耗力&am…

在CentOS 7.9上搭建高性能的FastDFS+Nginx文件服务器集群并实现外部远程访问

文章目录 引言第一部分&#xff1a;FastDFS介绍与安装1.1 FastDFS简介1.2 FastDFS安装1.2.1 安装Tracker Server1.2.2 安装Storage Server 1.3 FastDFS配置1.3.1 配置Tracker Server1.3.2 配置Storage Server1.3.3 启动FastDFS服务 第二部分&#xff1a;Nginx配置2.1 Nginx安装…

在线定制印刷系统源码/定制云印刷/个性印刷在线DIY定制商城系统/全站DIV+CSS 布局+手机、PC端

源码简介&#xff1a; 在线定制印刷系统源码/定制云印刷&#xff0c;它是个性印刷在线DIY定制商城系统&#xff0c;而且全站采用DIVCSS 布局&#xff0c;可以手机、PC端实时互通。 支持多种产品定制&#xff0c;包括但不限于水杯、雨伞、U盘、T恤、衬衫和四件套。独创的制作间…

Django必备知识点(图文详解)

目录 day02 django必备知识点 1.回顾 2.今日概要 3.路由系统 3.1 传统的路由 3.2 正则表达式路由 3.3 路由分发 小结 3.4 name 3.5 namespace 3.4 最后的 / 如何解决&#xff1f; 3.5 当前匹配对象 小结 4.视图 4.1 文件or文件夹 4.2 相对和绝对导入urls​编辑…

使用git下载远程所有分支到本地

使用git下载远程所有分支到本地&#xff1a; 打开gitbash 输入以下命令即可&#xff1a; git clone git地址 cd git文件夹 git branch -r | grep -v \-> | while read remote; do git branch --track "${remote#origin/}" "$remote"; done git fetch -…

深度学习第1天:深度学习入门-Keras与典型神经网络结构

☁️主页 Nowl &#x1f525;专栏《机器学习实战》 《机器学习》 &#x1f4d1;君子坐而论道&#xff0c;少年起而行之 文章目录 神经网络 介绍 结构 基本要素 Keras 介绍 导入 定义网络 模型训练 前馈神经网络 特点 常见类型 代码示例 反馈神经网络 特点 …

VC++彻底理解链接器:四,重定位

重定位 程序的运行过程就是CPU不断的从内存中取出指令然后执行执行的过程&#xff0c;对于函数调用来说比如我们在C/C语言中调用简单的加法函数add&#xff0c;其对应的汇编指令可能是这样的: call 0x4004fd 其中0x4004fd即为函数add在内存中的地址&#xff0c;当CPU执行这条…

全国测绘资质管理信息系统测绘资质申报流程

讲解一期关于测绘资质申请如何操作&#xff0c;在哪操作的问题&#xff0c;想要知道的按以下流程操作即可 &#xff08;注&#xff1a;以下操作为资质系统操作&#xff0c;想要能把资质申请下来&#xff0c;还需满足以下要求&#xff0c;后面会和系统操作一起统一讲解&#xf…

K8S如何部署ActiveMQ(单机、集群)

前言 大家好&#xff0c;在今天的讨论中&#xff0c;我们将深入研究如何将ActiveMQ迁移到云端&#xff0c;以便更好地利用Kubernetes的容器调度和资源管理能力&#xff0c;确保ActiveMQ的高可用性和可扩展性。 ActiveMQ是Apache开源组织推出的一款开源的、完全支持JMS1.1和J2…

IBM X3650M4安装ESXI6.5卡在/lsl_mr3.v00

环境&#xff1a;IBM X3650M4服务器双盘配置raid1&#xff0c;通过rufus制作启动U盘&#xff0c;安装VMware Vsphere 5.5系统 问题&#xff1a;卡在/lsi_mr3.v00界面无法往下运行&#xff08;两台配置一样的机器遇到同样的问题&#xff09; 解决方案&#xff1a; 直接在U盘根…

软件设计中如何画各类图之二深入解析数据流图(DFD):系统设计与分析的关键视觉工具

目录 1 前言2 数据流图&#xff08;DFD&#xff09;的重要性3 数据流图的符号说明4 清晰的数据流图步骤4.1 确定系统边界4.2 识别数据流4.3 定义处理过程4.4 确认数据存储4.5 建立数据流动的连线4.6 细化和优化 5 数据流图的用途6 使用场景7 实际应用场景举例8 结语 1 前言 当…

Eclipse 设置try-cacth 默认格式

设置面板 第一处 第二处 其中NsRuntimeException是自定义的异常处理。这样设置后&#xff0c;打开代码补全功能&#xff0c;输入try回车就会默认显示设置的代码

雅可比矩阵(Jacobian Matrix)

假设给定一个从n维欧式空间到m维欧式空间的变换: 雅可比矩阵就是将一阶偏导数排列成一个m行、n列形式的矩阵&#xff0c;记作&#xff1a; 举一个例子&#xff1a; 雅可比矩阵等于&#xff1a;

新手如何对一个web网页进行一次渗透测试

新手如何对一个web网页进行一次渗透测试 什么是渗透测试? 在获得web服务运营的公司书面授权的情况下&#xff0c;模拟攻击者的行为&#xff0c;以确定系统的脆弱性&#xff0c;并为保护系统提供有效的建议。 渗透测试和红蓝对抗的区别 渗透测试和红蓝对抗别再傻傻分不清楚…

ChatGPT重磅升级!集简云支持GPT4 Turbo Vision, GPT4 Turbo, Dall.E 3,Whisper等最新模型

在11月7日凌晨&#xff0c;OpenAI全球开发者大会宣布了 GPT-4的一次大升级&#xff0c;推出了 GPT-4 Turbo号称为迄今为止最强的大模型。 此次GPT-4的更新和升级在多个方面显示出强大的优势和潜力。为了让集简云用户能快速体验新模型的能力&#xff0c;我们第一时间整理了大会发…

Leetcode103 二叉树的锯齿形层序遍历

二叉树的锯齿形层序遍历 题解1 层序遍历双向队列 给你二叉树的根节点 root &#xff0c;返回其节点值的 锯齿形层序遍历 。&#xff08;即先从左往右&#xff0c;再从右往左进行下一层遍历&#xff0c;以此类推&#xff0c;层与层之间交替进行&#xff09;。 提示&#xff1a…

力扣每日一题-统计和小于目标的下标对数目-2023.11.24

力扣每日一题&#xff1a;统计和小于目标的下标对数目 开篇 今天这道力扣打卡题写得我好狼狈&#xff0c;一开始思路有点问题&#xff0c;后面就是对自己的代码到处缝缝补补&#xff0c;最后蒙混过关。只能分享一下大佬的代码&#xff0c;然后我帮大家分享代码的思路。 题目链…

迈巴赫S480升级主动式氛围灯 浪漫婉转的气氛

主动式氛围灯有263个可多色渐变的LED光源&#xff0c;营造出全情沉浸的动态光影氛围。结合智能驾驶辅助系统&#xff0c;可在转向或检测到危险时&#xff0c;予以红色环境光提示&#xff0c;令光影艺术彰显智能魅力。配件有6个氛围灯&#xff0c;1个电脑模块。 1、气候&#xf…