SpringBoot中定制異常頁(yè)面的實(shí)現(xiàn)方法
定制異常頁(yè)面,可以避免用戶(hù)產(chǎn)生恐慌心理,使得產(chǎn)品有更好的用戶(hù)體驗(yàn)。今天來(lái)學(xué)習(xí)在 SpringBoot 中如何定制開(kāi)發(fā)異常頁(yè)面
一、歷史回顧
在 SpringMVC 年代,我們的異常頁(yè)面一般配置在 web.xml 文件中,如下:
<!-- 配置404頁(yè)面 --> <error-page> <error-code>404</error-code> <location>/error/404.html</location> </error-page>
這里我們指定了異常請(qǐng)求狀態(tài)碼 404,然后配置了 404 異常請(qǐng)求的頁(yè)面地址,這就意味著如果某一個(gè)請(qǐng)求發(fā)生了 404 異常,則會(huì)出現(xiàn) 404.html 界面
二、SpringBoot中配置
1、默認(rèn)異常頁(yè)面

這是 SpringBoot 中默認(rèn)的異常頁(yè)面,返回的是一堆異常信息和異常狀態(tài)碼,那用戶(hù)固然是看不懂這些信息的,容易使得用戶(hù)產(chǎn)生恐慌的心里,從而影響產(chǎn)品的用戶(hù)體驗(yàn)
2、定制異常頁(yè)面
SpringBoot 中定制異常頁(yè)面非常簡(jiǎn)單,我們需要一個(gè)配置文件 ExceptionPageConfig.java
import org.springframework.boot.web.server.ConfigurableWebServerFactory;
import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
/**
* 統(tǒng)一異常頁(yè)面處理
*
* @Author Lizhou
**/
@Configuration
public class ExceptionPageConfig {
/**
* SpringBoot2.0以上版本
* WebServerFactoryCustomizer代替之前版本的EmbeddedWebServerFactoryCustomizerAutoConfiguration
*
* @return
*/
@Bean
public WebServerFactoryCustomizer<ConfigurableWebServerFactory> webServerFactoryCustomizer() {
return (container -> {
ErrorPage error400Page = new ErrorPage(HttpStatus.BAD_REQUEST, "/400");
ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/404");
ErrorPage error500Page = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/500");
container.addErrorPages(error400Page, error404Page, error500Page);
});
}
}
可以看出,這里我們配置了 400、404、500 三種異常頁(yè)面,然后我們需要編寫(xiě) API 請(qǐng)求異常頁(yè)面 SysExceptionController.java
import com.zyxx.common.utils.PasswordUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.shiro.SecurityUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
/**
* <p>
* 前端控制器
* </p>
*
* @author lizhou
* @since 2020-07-15
**/
@Api(tags = "后臺(tái)管理端--異常處理")
@Controller
public class SysExceptionController {
@ApiOperation(value = "請(qǐng)求400頁(yè)面", notes = "請(qǐng)求400頁(yè)面")
@GetMapping("400")
public String badRequest() {
return "sys/exception/400";
}
@ApiOperation(value = "請(qǐng)求404頁(yè)面", notes = "請(qǐng)求404頁(yè)面")
@GetMapping("404")
public String notFound() {
return "sys/exception/404";
}
@ApiOperation(value = "請(qǐng)求500頁(yè)面", notes = "請(qǐng)求500頁(yè)面")
@GetMapping("500")
public String serverError() {
return "sys/exception/500";
}
}
API 寫(xiě)好,下面我們就需要開(kāi)發(fā)異常頁(yè)面的展示信息了,這里貼一張頁(yè)面吧,404.html
import com.zyxx.common.utils.PasswordUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.shiro.SecurityUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
/**
* <p>
* 前端控制器
* </p>
*
* @author lizhou
* @since 2020-07-15
**/
@Api(tags = "后臺(tái)管理端--異常處理")
@Controller
public class SysExceptionController {
@ApiOperation(value = "請(qǐng)求400頁(yè)面", notes = "請(qǐng)求400頁(yè)面")
@GetMapping("400")
public String badRequest() {
return "sys/exception/400";
}
@ApiOperation(value = "請(qǐng)求404頁(yè)面", notes = "請(qǐng)求404頁(yè)面")
@GetMapping("404")
public String notFound() {
return "sys/exception/404";
}
@ApiOperation(value = "請(qǐng)求500頁(yè)面", notes = "請(qǐng)求500頁(yè)面")
@GetMapping("500")
public String serverError() {
return "sys/exception/500";
}
}
然后所需要的 exception.css
.error .clip .shadow {
height: 180px;
}
.error .clip:nth-of-type(2) .shadow {
width: 130px;
}
.error .clip:nth-of-type(1) .shadow, .error .clip:nth-of-type(3) .shadow {
width: 250px;
}
.error .digit {
width: 150px;
height: 150px;
line-height: 150px;
font-size: 120px;
font-weight: bold;
}
.error h2 {
font-size: 32px;
}
.error .msg {
top: -190px;
left: 30%;
width: 80px;
height: 80px;
line-height: 80px;
font-size: 32px;
}
.error span.triangle {
top: 70%;
right: 0%;
border-left: 20px solid #535353;
border-top: 15px solid transparent;
border-bottom: 15px solid transparent;
}
.error .container-error-404 {
top: 50%;
margin-top: 250px;
position: relative;
height: 250px;
padding-top: 40px;
}
.error .container-error-404 .clip {
display: inline-block;
transform: skew(-45deg);
}
.error .clip .shadow {
overflow: hidden;
}
.error .clip:nth-of-type(2) .shadow {
overflow: hidden;
position: relative;
box-shadow: inset 20px 0px 20px -15px rgba(150, 150, 150, 0.8), 20px 0px 20px -15px rgba(150, 150, 150, 0.8);
}
.error .clip:nth-of-type(3) .shadow:after, .error .clip:nth-of-type(1) .shadow:after {
content: "";
position: absolute;
right: -8px;
bottom: 0px;
z-index: 9999;
height: 100%;
width: 10px;
background: linear-gradient(90deg, transparent, rgba(173, 173, 173, 0.8), transparent);
border-radius: 50%;
}
.error .clip:nth-of-type(3) .shadow:after {
left: -8px;
}
.error .digit {
position: relative;
top: 8%;
color: white;
background: #1E9FFF;
border-radius: 50%;
display: inline-block;
transform: skew(45deg);
}
.error .clip:nth-of-type(2) .digit {
left: -10%;
}
.error .clip:nth-of-type(1) .digit {
right: -20%;
}
.error .clip:nth-of-type(3) .digit {
left: -20%;
}
.error h2 {
font-size: 24px;
color: #A2A2A2;
font-weight: bold;
padding-bottom: 20px;
}
.error .tohome {
font-size: 16px;
color: #07B3F9;
}
.error .msg {
position: relative;
z-index: 9999;
display: block;
background: #535353;
color: #A2A2A2;
border-radius: 50%;
font-style: italic;
}
.error .triangle {
position: absolute;
z-index: 999;
transform: rotate(45deg);
content: "";
width: 0;
height: 0;
}
@media (max-width: 767px) {
.error .clip .shadow {
height: 100px;
}
.error .clip:nth-of-type(2) .shadow {
width: 80px;
}
.error .clip:nth-of-type(1) .shadow, .error .clip:nth-of-type(3) .shadow {
width: 100px;
}
.error .digit {
width: 80px;
height: 80px;
line-height: 80px;
font-size: 52px;
}
.error h2 {
font-size: 18px;
}
.error .msg {
top: -110px;
left: 15%;
width: 40px;
height: 40px;
line-height: 40px;
font-size: 18px;
}
.error span.triangle {
top: 70%;
right: -3%;
border-left: 10px solid #535353;
border-top: 8px solid transparent;
border-bottom: 8px solid transparent;
}
.error .container-error-404 {
height: 150px;
}
}
所需要的 exception.js
.error .clip .shadow {
height: 180px;
}
.error .clip:nth-of-type(2) .shadow {
width: 130px;
}
.error .clip:nth-of-type(1) .shadow, .error .clip:nth-of-type(3) .shadow {
width: 250px;
}
.error .digit {
width: 150px;
height: 150px;
line-height: 150px;
font-size: 120px;
font-weight: bold;
}
.error h2 {
font-size: 32px;
}
.error .msg {
top: -190px;
left: 30%;
width: 80px;
height: 80px;
line-height: 80px;
font-size: 32px;
}
.error span.triangle {
top: 70%;
right: 0%;
border-left: 20px solid #535353;
border-top: 15px solid transparent;
border-bottom: 15px solid transparent;
}
.error .container-error-404 {
top: 50%;
margin-top: 250px;
position: relative;
height: 250px;
padding-top: 40px;
}
.error .container-error-404 .clip {
display: inline-block;
transform: skew(-45deg);
}
.error .clip .shadow {
overflow: hidden;
}
.error .clip:nth-of-type(2) .shadow {
overflow: hidden;
position: relative;
box-shadow: inset 20px 0px 20px -15px rgba(150, 150, 150, 0.8), 20px 0px 20px -15px rgba(150, 150, 150, 0.8);
}
.error .clip:nth-of-type(3) .shadow:after, .error .clip:nth-of-type(1) .shadow:after {
content: "";
position: absolute;
right: -8px;
bottom: 0px;
z-index: 9999;
height: 100%;
width: 10px;
background: linear-gradient(90deg, transparent, rgba(173, 173, 173, 0.8), transparent);
border-radius: 50%;
}
.error .clip:nth-of-type(3) .shadow:after {
left: -8px;
}
.error .digit {
position: relative;
top: 8%;
color: white;
background: #1E9FFF;
border-radius: 50%;
display: inline-block;
transform: skew(45deg);
}
.error .clip:nth-of-type(2) .digit {
left: -10%;
}
.error .clip:nth-of-type(1) .digit {
right: -20%;
}
.error .clip:nth-of-type(3) .digit {
left: -20%;
}
.error h2 {
font-size: 24px;
color: #A2A2A2;
font-weight: bold;
padding-bottom: 20px;
}
.error .tohome {
font-size: 16px;
color: #07B3F9;
}
.error .msg {
position: relative;
z-index: 9999;
display: block;
background: #535353;
color: #A2A2A2;
border-radius: 50%;
font-style: italic;
}
.error .triangle {
position: absolute;
z-index: 999;
transform: rotate(45deg);
content: "";
width: 0;
height: 0;
}
@media (max-width: 767px) {
.error .clip .shadow {
height: 100px;
}
.error .clip:nth-of-type(2) .shadow {
width: 80px;
}
.error .clip:nth-of-type(1) .shadow, .error .clip:nth-of-type(3) .shadow {
width: 100px;
}
.error .digit {
width: 80px;
height: 80px;
line-height: 80px;
font-size: 52px;
}
.error h2 {
font-size: 18px;
}
.error .msg {
top: -110px;
left: 15%;
width: 40px;
height: 40px;
line-height: 40px;
font-size: 18px;
}
.error span.triangle {
top: 70%;
right: -3%;
border-left: 10px solid #535353;
border-top: 8px solid transparent;
border-bottom: 8px solid transparent;
}
.error .container-error-404 {
height: 150px;
}
}
三、測(cè)試
項(xiàng)目啟動(dòng)后,我們?cè)L問(wèn)一個(gè)并不存在的 API

那,通過(guò)訪(fǎng)問(wèn)一個(gè)項(xiàng)目中并不存在的 API,得到 404 頁(yè)面,頁(yè)面可以提示一些友好的文字,從而安撫用戶(hù)緊張的心理,其實(shí)也是一個(gè)不錯(cuò)的選擇吧
到此這篇關(guān)于SpringBoot中定制異常頁(yè)面的實(shí)現(xiàn)方法的文章就介紹到這了,更多相關(guān)SpringBoot 定制異常頁(yè)面內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot關(guān)于List集合的校驗(yàn)方式
這篇文章主要介紹了SpringBoot關(guān)于List集合的校驗(yàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07
java中超過(guò)long范圍的超大整數(shù)相加算法詳解(面試高頻)
這篇文章主要介紹了java中超過(guò)long范圍的超大整數(shù)相加算法(面試高頻),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08
Spring?boot?自定義?Starter及自動(dòng)配置的方法
Starter?組件是?Spring?boot?的一個(gè)核心特性,Starter組件的出現(xiàn)極大的簡(jiǎn)化了項(xiàng)目開(kāi)發(fā),這篇文章主要介紹了Spring?boot?自定義?Starter?及?自動(dòng)配置,需要的朋友可以參考下2022-12-12
Java如何實(shí)現(xiàn)kaptcha網(wǎng)頁(yè)驗(yàn)證碼驗(yàn)證
在做關(guān)于SSM項(xiàng)目之商鋪系統(tǒng)時(shí),了解到了kaptcha實(shí)現(xiàn)網(wǎng)頁(yè)驗(yàn)證碼驗(yàn)證,感覺(jué)就很有趣,所以便開(kāi)始學(xué)習(xí)記錄了起來(lái),復(fù)制粘貼即可用2025-01-01
Java Comparator.comparing比較導(dǎo)致空指針異常的解決
這篇文章主要介紹了Java Comparator.comparing比較導(dǎo)致空指針異常的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07
Java中Aspose組件進(jìn)行多文檔間的轉(zhuǎn)換方法總結(jié)
在本篇文章里我們給大家分享了關(guān)于Java中Aspose組件進(jìn)行多文檔間的轉(zhuǎn)換方法內(nèi)容,需要的朋友們學(xué)習(xí)下吧。2019-02-02
詳解Spring Cloud Gateway基于服務(wù)發(fā)現(xiàn)的默認(rèn)路由規(guī)則
這篇文章主要介紹了詳解Spring Cloud Gateway基于服務(wù)發(fā)現(xiàn)的默認(rèn)路由規(guī)則,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-05-05

