SpringBoot錯(cuò)誤處理機(jī)制以及自定義異常處理詳解
上篇文章我們講解了使用Hibernate Validation來(lái)校驗(yàn)數(shù)據(jù),當(dāng)校驗(yàn)完數(shù)據(jù)后,如果發(fā)生錯(cuò)誤我們需要給客戶返回一個(gè)錯(cuò)誤信息,因此這節(jié)我們來(lái)講解一下SpringBoot默認(rèn)的錯(cuò)誤處理機(jī)制以及如何自定義異常來(lái)處理請(qǐng)求錯(cuò)誤。
一、SpringBoot默認(rèn)的錯(cuò)誤處理機(jī)制
我們?cè)诎l(fā)送一個(gè)請(qǐng)求的時(shí)候,如果發(fā)生404 SpringBoot會(huì)怎么處理呢?我們來(lái)發(fā)送一個(gè)不存在的請(qǐng)求來(lái)驗(yàn)證一下看看頁(yè)面結(jié)果。如下所示:

當(dāng)服務(wù)器內(nèi)部發(fā)生錯(cuò)誤的時(shí)候,頁(yè)面會(huì)返回什么呢?
@GetMapping("/user/{id:\\d+}")
public User get(@PathVariable String id) {
throw new RuntimeException();
}

我們會(huì)發(fā)現(xiàn)無(wú)論是發(fā)生什么錯(cuò)誤,SpringBoot都會(huì)返回一個(gè)狀態(tài)碼以及一個(gè)錯(cuò)誤頁(yè)面,這個(gè)錯(cuò)誤頁(yè)面是怎么來(lái)的呢?
我們來(lái)看看SpringBoot錯(cuò)誤處理模塊的源碼就會(huì)非常清楚,默認(rèn)的發(fā)生錯(cuò)誤,它會(huì)將請(qǐng)求轉(zhuǎn)發(fā)到BasicErrorController控制器來(lái)處理請(qǐng)求,下面是該controller類的源碼:
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {
private final ErrorProperties errorProperties;
/**
* Create a new {@link BasicErrorController} instance.
* @param errorAttributes the error attributes
* @param errorProperties configuration properties
*/
public BasicErrorController(ErrorAttributes errorAttributes,
ErrorProperties errorProperties) {
this(errorAttributes, errorProperties,
Collections.<ErrorViewResolver>emptyList());
}
/**
* Create a new {@link BasicErrorController} instance.
* @param errorAttributes the error attributes
* @param errorProperties configuration properties
* @param errorViewResolvers error view resolvers
*/
public BasicErrorController(ErrorAttributes errorAttributes,
ErrorProperties errorProperties, List<ErrorViewResolver> errorViewResolvers) {
super(errorAttributes, errorViewResolvers);
Assert.notNull(errorProperties, "ErrorProperties must not be null");
this.errorProperties = errorProperties;
}
@Override
public String getErrorPath() {
return this.errorProperties.getPath();
}
@RequestMapping(produces = "text/html")
public ModelAndView errorHtml(HttpServletRequest request,
HttpServletResponse response) {
HttpStatus status = getStatus(request);
Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(
request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
response.setStatus(status.value());
ModelAndView modelAndView = resolveErrorView(request, response, status, model);
return (modelAndView == null ? new ModelAndView("error", model) : modelAndView);
}
@RequestMapping
@ResponseBody
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
Map<String, Object> body = getErrorAttributes(request,
isIncludeStackTrace(request, MediaType.ALL));
HttpStatus status = getStatus(request);
return new ResponseEntity<Map<String, Object>>(body, status);
}
從上面的源碼我們可以看到,它有兩個(gè)RequestMapping方法來(lái)映射錯(cuò)誤請(qǐng)求,為什么會(huì)是兩個(gè)呢?其實(shí)errorHtml方法映射的是瀏覽器發(fā)送來(lái)的請(qǐng)求,而error方法映射的是不是瀏覽器而是其他軟件app客戶端發(fā)送的錯(cuò)誤請(qǐng)求。
看了上面的源碼后,我們是否可以自己定義404或者500的錯(cuò)誤頁(yè)面返回給客戶端呢?當(dāng)然可以,我們可以在src/main/resources路徑下新建文件夾reources/error文件夾,然后新建404.html和500.html然后編寫自己的錯(cuò)誤內(nèi)容即可:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>404</title> </head> <body> 親,您所訪問(wèn)的頁(yè)面不存在 </body> </html>
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>500</title> </head> <body> 服務(wù)器內(nèi)部錯(cuò)誤 </body> </html>
不過(guò)注意的是上面的這種自定義頁(yè)面的方式只在瀏覽器端有效,而不是瀏覽器發(fā)送的請(qǐng)求不會(huì)生效。因此下面我們就講一下如何自定義異常處理來(lái)解決這個(gè)問(wèn)題。
二、自定義異常處理
怎么自定義異常處理客戶端發(fā)送的錯(cuò)誤信息呢?如果我們查詢一個(gè)用戶,該用戶不存在,我們是否可以將不存在的用戶的id返回給客戶呢?這樣的效果不是給客戶更好地體驗(yàn)嗎?下面我們來(lái)實(shí)現(xiàn)這個(gè)功能。
首先我們需要編寫一個(gè)exception類繼承RuntimeException類:
package cn.shinelon.exception;
/**
* @author Shinelon
*
*/
public class UserNotExistException extends RuntimeException{
/**
*
*/
private static final long serialVersionUID = 1L;
private String id;
public UserNotExistException(String id) {
super("user not exist");
this.id=id;
}
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
}
接著我們需要編寫一個(gè)handler類處理controller層拋出的異常:
/**
*
*/
package cn.shinelon.exception;
import java.util.HashMap;
import java.util.Map;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
/**
* 控制器的異常處理類
* @author Shinelon
*
*/
//這個(gè)注解是指這個(gè)類是處理其他controller拋出的異常
@ControllerAdvice
public class ControllerExceptionHandler {
//這個(gè)注解是指當(dāng)controller中拋出這個(gè)指定的異常類的時(shí)候,都會(huì)轉(zhuǎn)到這個(gè)方法中來(lái)處理異常
@ExceptionHandler(UserNotExistException.class)
//將返回的值轉(zhuǎn)成json格式的數(shù)據(jù)
@ResponseBody
//返回的狀態(tài)碼
@ResponseStatus(value=HttpStatus.INTERNAL_SERVER_ERROR) //服務(wù)內(nèi)部錯(cuò)誤
public Map<String,Object> handlerUserNotExistException(UserNotExistException ex){
Map<String,Object> result=new HashMap<String,Object>();
result.put("id", ex.getId());
result.put("message", ex.getMessage());
return result;
}
}
這個(gè)類加上@ControllerAdvice注解將會(huì)處理controller層拋出的對(duì)應(yīng)的異常,這里我們處理controller拋出的UserNotExistException自定義異常,并且將錯(cuò)誤信息以及用戶id以json串的格式返回給客戶。
接著,我們?cè)赾ontroller的請(qǐng)求方法中拋出這個(gè)異常,會(huì)看到在瀏覽器中的異常是我們自定義的異常返回的json數(shù)據(jù)。
Controller層代碼:
@GetMapping("/user/{id:\\d+}")
//@RequestMapping(value="/user/{id:\\d+}",method=RequestMethod.GET)
@JsonView(User.DetailJsonView.class)
public User get(@PathVariable String id) {
throw new UserNotExistException(id);
}

到這里,我們就介紹了SpringBoot默認(rèn)的錯(cuò)誤處理機(jī)制以及我們自定義異常來(lái)處理錯(cuò)誤請(qǐng)求,這更有利于我們的開發(fā),帶給用戶更佳的使用效果。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
@CacheEvict + redis實(shí)現(xiàn)批量刪除緩存
這篇文章主要介紹了@CacheEvict + redis實(shí)現(xiàn)批量刪除緩存方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10
SpringBoot枚舉類型參數(shù)認(rèn)證的實(shí)現(xiàn)代碼
項(xiàng)目當(dāng)中經(jīng)常需要接口參數(shù)是否在一個(gè)可選的范圍內(nèi),也就是驗(yàn)證類枚舉參數(shù)的需求,所以本文我們將使用SpringBoot實(shí)現(xiàn)枚舉類型參數(shù)認(rèn)證,文中有詳細(xì)的代碼示例,需要的朋友可以參考下2023-12-12
spring集成httpclient配置的詳細(xì)過(guò)程
spring框架是一個(gè)非常強(qiáng)大的框架這里就不多說(shuō)了,那么主要是介紹spring與httpclient的整合集成過(guò)程,感興趣的朋友跟隨小編一起看看吧2021-07-07
IntelliJ?IDEA?2022.2最新版本激活教程(親測(cè)可用版)永久激活工具分享
Jetbrains官方發(fā)布了?IntelliJ?IDEA2022.2?正式版,每次大的版本更新,都會(huì)有較大的調(diào)整和優(yōu)化,除本次更新全面擁抱?Java?17?外,還有對(duì)IDE?UI界面,安全性,便捷性等都做了調(diào)整和優(yōu)化完善,用戶體驗(yàn)提升不少,相信后面會(huì)有不少小伙伴跟著更新2022-08-08
java實(shí)現(xiàn)簡(jiǎn)易連連看小游戲
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)簡(jiǎn)易連連看小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05
java使用Feign實(shí)現(xiàn)聲明式Restful風(fēng)格調(diào)用
這篇文章主要為大家詳細(xì)介紹了java使用Feign實(shí)現(xiàn)聲明式Restful風(fēng)格調(diào)用,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-04-04
Java成員變量與局部變量(動(dòng)力節(jié)點(diǎn)Java學(xué)院整理)
這篇文章主要介紹了Java成員變量與局部變量的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-04-04

