springboot 自定义错误页面

自定义错误页面

背景:当我们访问应用程序不存在的接口路径或者参数传递不规范时,springboot 默认提示 如下页面
在这里插入图片描述
该页面对用户不友好,我们可以自定义展示错误页来改善。

优化后的简洁效果,可对 html 页面进一步美化,这里只说明修改默认错误页方法。
在这里插入图片描述

demo地址

https://gitee.com/stormlong/springboot-errorpage

官方文档

https://docs.spring.io/spring-boot/docs/2.7.18/reference/html/web.html#web.servlet.spring-mvc.error-handling.error-pages
在这里插入图片描述
在这里插入图片描述

静态页面

resources\public\error
不引入任何模板引擎时,在这个目录下寻找
且文件名和错误状态码保持一致

动态页面

resources\templates\error
引入模板引擎时,在这个目录下寻找
例 :

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency>

且文件名和错误状态码保持一致

优先级

html 文件命名也可以为 4xx 或者是 5xx ,这里的 xx 代表了 404, 401等异常错误

不引入任何模板引擎时,优先具体的错误码页面,然后是 4xx页面,即

  1. \public\error\404.html
  2. \public\error\4xx.html

引入模板引擎时,优先级

  1. \templates\error 目录下的 404.html
  2. \public\error 目录下的 404.html
  3. \templates\error 目录下的 4xx.html
  4. \public\error 目录下的 4xx.html

没有任何错误页面时,默认来到 SpringBoot 默认的错误提示页面

总结:优先具体的错误码页面,然后动态目录下的 4xx 页面
在这里插入图片描述

原理解析

处理异常类

在spring boot中,我们可以找到 BasicErrorController,这个类主要用来处理异常

@Controller
//如果没有配置server.error.path就去error.path找,如果没有配置默认路径为/error
@RequestMapping({"${server.error.path:${error.path:/error}}"})
public class BasicErrorController extends AbstractErrorController {...
}

即我们可以通过 server.error.path 来定义错误的目录,缺省则使用默认 /error 目录

server:error:path: /error

默认 yaml 配置

server:port: 8080error:path: /errorspring:thymeleaf:cache: false# 以下均为默认配置 可从该类 ThymeleafProperties 下看到 prefix: classpath:/templates/suffix: .htmlmode: htmlencoding: UTF-8servlet:content-type: text/html

返回错误信息

SpringBoot默认返回的错误信息,通过DefaultErrorAttruites类可以找到

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//package org.springframework.boot.web.servlet.error;import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.error.ErrorAttributeOptions.Include;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;@Order(-2147483648)
public class DefaultErrorAttributes implements ErrorAttributes, HandlerExceptionResolver, Ordered {private static final String ERROR_INTERNAL_ATTRIBUTE = DefaultErrorAttributes.class.getName() + ".ERROR";public DefaultErrorAttributes() {}public int getOrder() {return -2147483648;}public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {this.storeErrorAttributes(request, ex);return null;}private void storeErrorAttributes(HttpServletRequest request, Exception ex) {request.setAttribute(ERROR_INTERNAL_ATTRIBUTE, ex);}public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {Map<String, Object> errorAttributes = this.getErrorAttributes(webRequest, options.isIncluded(Include.STACK_TRACE));if (!options.isIncluded(Include.EXCEPTION)) {errorAttributes.remove("exception");}if (!options.isIncluded(Include.STACK_TRACE)) {errorAttributes.remove("trace");}if (!options.isIncluded(Include.MESSAGE) && errorAttributes.get("message") != null) {errorAttributes.remove("message");}if (!options.isIncluded(Include.BINDING_ERRORS)) {errorAttributes.remove("errors");}return errorAttributes;}private 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;}private void addStatus(Map<String, Object> errorAttributes, RequestAttributes requestAttributes) {Integer status = (Integer)this.getAttribute(requestAttributes, "javax.servlet.error.status_code");if (status == null) {errorAttributes.put("status", 999);errorAttributes.put("error", "None");} else {errorAttributes.put("status", status);try {errorAttributes.put("error", HttpStatus.valueOf(status).getReasonPhrase());} catch (Exception var5) {errorAttributes.put("error", "Http Status " + status);}}}private void addErrorDetails(Map<String, Object> errorAttributes, WebRequest webRequest, boolean includeStackTrace) {Throwable error = this.getError(webRequest);if (error != null) {while(true) {if (!(error instanceof ServletException) || error.getCause() == null) {errorAttributes.put("exception", error.getClass().getName());if (includeStackTrace) {this.addStackTrace(errorAttributes, error);}break;}error = error.getCause();}}this.addErrorMessage(errorAttributes, webRequest, error);}private void addErrorMessage(Map<String, Object> errorAttributes, WebRequest webRequest, Throwable error) {BindingResult result = this.extractBindingResult(error);if (result == null) {this.addExceptionErrorMessage(errorAttributes, webRequest, error);} else {this.addBindingResultErrorMessage(errorAttributes, result);}}private void addExceptionErrorMessage(Map<String, Object> errorAttributes, WebRequest webRequest, Throwable error) {errorAttributes.put("message", this.getMessage(webRequest, error));}protected String getMessage(WebRequest webRequest, Throwable error) {Object message = this.getAttribute(webRequest, "javax.servlet.error.message");if (!ObjectUtils.isEmpty(message)) {return message.toString();} else {return error != null && StringUtils.hasLength(error.getMessage()) ? error.getMessage() : "No message available";}}private void addBindingResultErrorMessage(Map<String, Object> errorAttributes, BindingResult result) {errorAttributes.put("message", "Validation failed for object='" + result.getObjectName() + "'. Error count: " + result.getErrorCount());errorAttributes.put("errors", result.getAllErrors());}private BindingResult extractBindingResult(Throwable error) {return error instanceof BindingResult ? (BindingResult)error : null;}private void addStackTrace(Map<String, Object> errorAttributes, Throwable error) {StringWriter stackTrace = new StringWriter();error.printStackTrace(new PrintWriter(stackTrace));stackTrace.flush();errorAttributes.put("trace", stackTrace.toString());}private void addPath(Map<String, Object> errorAttributes, RequestAttributes requestAttributes) {String path = (String)this.getAttribute(requestAttributes, "javax.servlet.error.request_uri");if (path != null) {errorAttributes.put("path", path);}}public Throwable getError(WebRequest webRequest) {Throwable exception = (Throwable)this.getAttribute(webRequest, ERROR_INTERNAL_ATTRIBUTE);if (exception == null) {exception = (Throwable)this.getAttribute(webRequest, "javax.servlet.error.exception");}webRequest.setAttribute(ErrorAttributes.ERROR_ATTRIBUTE, exception, 0);return exception;}private <T> T getAttribute(RequestAttributes requestAttributes, String name) {return requestAttributes.getAttribute(name, 0);}
}

自定义扩展返回

如果要想自定义扩展返回的信息,我们可以自定义一个类来继承这个类,代码如下:

import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.WebRequest;import java.util.HashMap;
import java.util.Map;@Component
public class CustomDefaultErrorAttribute extends DefaultErrorAttributes {@Overridepublic Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {Map<String, Object> map = new HashMap<>();map.put("compay", "深证腾讯计算公司");//调用父类来添加之前Spring的错误信息map.putAll(super.getErrorAttributes(webRequest, options));return map;}}

页面获取代码如下

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>动态404错误</title>
</head>
<body>
<h1>this is 404 page :(</h1>
<h2>timestamp:[[${timestamp}]]</h2>
<h2>status:[[${status}]]</h2>
<h2>path:[[${path}]]</h2>
<h2>error:[[${error}]]</h2>
<h2>message:[[${message}]]</h2>
<h2>exception:[[${exception}]]</h2>
<h2>trace:[[${trace}]]</h2>
<h2>compay:[[${compay}]]</h2>
</body>
</html>

tomcat 自定义错误页面(扩展)

官方文档:

https://tomcat.apache.org/tomcat-9.0-doc/config/valve.html#Error_Report_Valve

tomcat-404错误,使用自定义页面屏蔽敏感信息

  1. 在项目中新增404页面,例如:/resource/templates/errorpage/400.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Error</title>
</head>
<body>
<h1>400 Bad Request</h1>
</body>
</html>
  1. 在server.xml配置文件里进行配置 配置节点下新增 部分

    https://tomcat.apache.org/tomcat-9.0-doc/config/host.html

    https://tomcat.apache.org/tomcat-9.0-doc/config/context.html

<Host appBase="/app/webapps"><Context path="/abc/def"></Context><Valve className="org.apache.catalina.valves.ErrorReportValve" errorCode.404="/app/webapps/abc/def/WEB-INF/classes/templates/errorpage/400.html" showReport="false" showServerInfo="false" />
</Host>

访问不成功时可尝试 abc/ 替换成 abc#

/app/webapps/abc#def/WEB-INF/classes/templates/errorpage/400.html

配置说明

showReport:如果设置为false,则不会在HTML响应中返回错误报告。默认值:true

showServerInfo:如果设置为false,则不会在HTML响应中返回服务器版本。默认值:true

errorCode.xxx: 要为xxx表示的HTTP错误代码返回的UTF-8编码的HTML文件的位置。例如,errorCode.404指定HTTP 404错误返回的文件。位置可以是相对的或绝对的。如果是相对的,则必须是相对于 $CATALINA_BASE的。

className要使用的实现的Java类名。必须将其设置为 org.apache.catalina.valves.ErrorReportValve 以使用默认的错误报告值。

appBase: 此虚拟主机的应用程序基目录。这是一个目录的路径名,该目录可能包含要在此虚拟主机上部署的Web应用程序。如果未指定,则将使用默认的 webapps。

path: 此Web应用程序的上下文路径,它与每个请求URI的开头相匹配,以选择要处理的适当Web应用程序。特定主机内的所有上下文路径都必须是唯一的。

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

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

相关文章

SpringBoot 集成RabbitMQ 实现钉钉日报定时发送功能

文章目录 一、RabbitMq 下载安装二、开发步骤&#xff1a;1.MAVEN 配置2. RabbitMqConfig 配置3. RabbitMqUtil 工具类4. DailyDelaySendConsumer 消费者监听5. 测试延迟发送 一、RabbitMq 下载安装 官网&#xff1a;https://www.rabbitmq.com/docs 二、开发步骤&#xff1a;…

低代码统一待办:提升任务管理效率的新模式

低代码平台的魔力 低代码平台通过图形化用户界面和简化开发流程&#xff0c;让用户无需具备深厚的编程知识也能快速构建应用程序。这种技术不仅加速了应用开发速度&#xff0c;还大幅降低了开发成本和复杂度&#xff0c;适合各种规模的企业。 构建统一待办系统的优势 集中化管…

itertools模块的combinations很牛

在 Python 中&#xff0c;combinations 是 itertools 模块提供的一个非常有用的函数&#xff0c;用于生成给定序列的所有可能的组合&#xff08;不考虑顺序&#xff09;。combinations 函数可以生成从长度为 r 的所有子集&#xff0c;其中 r 是一个指定的正整数&#xff0c;表示…

React中管理state的方式

使用useState 使用useReducer 既然已经有了useState&#xff0c;为什么还需要useReducer呢&#xff1f; 那么useReducer是如何将解决这些问题的呢&#xff1f; reducer是如何更新state的呢&#xff1f; reducer的工作方式非常类似JavaScript中的reduce方法&#xff0c;随着时…

CSS网页布局综合练习(涵盖大多CSS知识点)

该综合练习就是为这个学校静态网页设置CSS样式&#xff0c;使其变成下面的模样 其基本骨架代码为&#xff1a; <!DOCTYPE html> <html lang"zh"> <head> <meta charset"UTF-8"> <meta name"viewport" content…

放大器的保护机制

在工作中&#xff0c;使用功率放大器或高压放大器这类精密仪器时&#xff0c;为了保护设备不受伤害&#xff0c;确保设备的稳定性和安全性&#xff0c;在设备上需要设置保护机制。保护机制起着至关重要的作用&#xff0c;可以防止设备因过流、过压、过热等因素而受损。放大器的…

JavaSE笔记4】API、包、String类、Object类

目录 一、API 二、包 2.导入不同包下的同名程序 三、String 1. String类是什么&#xff1f; 2. 如何创建String对象?(常用的四种方法&#xff09; 3. String API a. 遍历字符串 b. 判断字符串内容是否相等&#xff1a; c. 截取子串 d. 替换部分内容 e. 匹配子串 f. 匹配开头字…

「C/C++」C/C++ 之 判断语句

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「C/C」C/C程序设计&#x1f4da;全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasoli…

nrm的使用

在安装nrm之前&#xff0c;要先完成node.js的安装。 1、nrm的介绍 ‌nrm&#xff08;npm registry manager&#xff09;是一个npm源管理器&#xff0c;允许用户在不同npm源之间快速切换。 关于npm和nvm的介绍&#xff0c;详见文章nvm的使用-CSDN博客。 解释&#xff1a;比如…

芯片上音频相关的验证

通常芯片设计公司&#xff08;比如QUALCOMM&#xff09;把芯片设计好后交由芯片制造商&#xff08;比如台积电&#xff09;去生产&#xff0c;俗称流片。芯片设计公司由ASIC部门负责设计芯片。ASIC设计的芯片只有经过充分的验证&#xff08;这里说的验证是FPGA&#xff08;现场…

【论文分享】通过太阳轨迹和街景图像测量不同街道网络方向的太阳辐射及其时空分布

本次我们给大家带来一篇SCI论文的全文翻译。该论文利用街景数据和太阳轨迹模拟技术&#xff0c;揭示了不同方向街道上的太阳辐射在时空上的差异&#xff0c;为城市的可持续发展提供了更有针对性的策略。 【论文题目】 Measuring solar radiation and spatio-temporal distrib…

基于springboot+vue实现的公考知识学习平台 (源码+L文+ppt)4-103

4.1 系统功能结构设计 根据对公考知识学习平台的具体需求分析&#xff0c;把系统可以划分为几个不同的功能模块&#xff1a;管理员可以对系统首页、个人中心、用户管理、讲师管理、在线咨询管理、学习资料管理、讲座信息管理、讲座预约管理、学习论坛、练习自测管理、试题管理…

LabVIEW程序员的真实工作状态是怎样的?

LabVIEW程序员的工作状态通常涉及以下几个方面&#xff1a; 1. 项目开发与设计 需求分析&#xff1a;与客户或团队成员沟通&#xff0c;明确项目需求&#xff0c;制定开发计划。 系统设计&#xff1a;根据需求进行系统架构设计&#xff0c;包括硬件选型和软件模块划分。 2.…

搜索引擎算法更新对网站优化的影响与应对策略

内容概要 随着互联网的不断发展&#xff0c;搜索引擎算法也在不断地进行更新和优化。了解这些算法更新的背景与意义&#xff0c;对于网站管理者和优化人员而言&#xff0c;具有重要的指导意义。不仅因为算法更新可能影响到网站的排名&#xff0c;还因为这些变化也可能为网站带…

安装中文版 Matlab R2022a

下载安装包 压缩包有点大&#xff0c;大概20G 百度网盘&#xff1a;下载链接 提取码&#xff1a;rmja 安装 解压后打开目录&#xff0c;右键以管理员身份运行 setup.exe 选择输入安装秘钥 输入秘钥&#xff1a; 50874-33247-14209-37962-45495-25133-28159-33348-18070-6088…

互联网大厂最全Java面试题及答案整理(2024最新版)

很多 Java 工程师的技术不错&#xff0c;但是一面试就头疼&#xff0c;10 次面试 9 次都是被刷&#xff0c;过的那次还是去了家不知名的小公司。 问题就在于&#xff1a;面试有技巧&#xff0c;而你不会把自己的能力表达给面试官。 应届生&#xff1a;你该如何准备简历&#…

[Nginx]快速入门

Nginx概述 介绍 Nginx是一款轻量级的web 服务器/ 反向代理服务器/ 电子邮件(IMAP/POP3)代理服务器。其特点是占有内存少&#xff0c;并发能力强&#xff0c;事实上nginx的并发能力在同类型的网页服务器中表现较好 中国大陆使用nginx的网站有:百度、京东、新浪、网易、腾讯、…

坚持使用kimi搭建小程序2小时(04天/05天)

运用好kimi智能助手里面的存储小程序&#xff0c;{缺乏一个相对稳定的反馈体系&#xff0c;自己所挑选的稳定反馈体系就是编程!} 开源竞争&#xff1a; 当你无法彻底掌握一门技术的时候&#xff0c;就开源这门技术&#xff0c;培养出更多的技术依赖&#xff0c;让更多人完善你…

免费流程图制作工具 draw.io v24.5.3 中文绿色版

draw.io是一款免费的在线图表绘制工具&#xff0c;它提供了强大的功能和易于使用的界面&#xff0c;适用于各种绘图需求。 详细功能 多种类型的图表&#xff1a;draw.io支持创建各种类型的图表&#xff0c;包括流程图、组织结构图、UML图、网络拓扑图、平面图等。自定义图表元…

NVR小程序接入平台/设备EasyNVR多个NVR同时管理多平台级联与上下级对接的高效应用

政务数据共享平台的建设正致力于消除“信息孤岛”现象&#xff0c;打破“数据烟囱”&#xff0c;实现国家、省、市及区县数据的全面对接与共享。省市平台的“级联对接”工作由多级平台共同构成&#xff0c;旨在满足跨部门、跨层级及跨省数据共享的需求&#xff0c;推动数据流通…