SpringBoot錯(cuò)誤處理機(jī)制以及自定義異常處理詳解
上篇文章我們講解了使用Hibernate Validation來校驗(yàn)數(shù)據(jù),當(dāng)校驗(yàn)完數(shù)據(jù)后,如果發(fā)生錯(cuò)誤我們需要給客戶返回一個(gè)錯(cuò)誤信息,因此這節(jié)我們來講解一下SpringBoot默認(rèn)的錯(cuò)誤處理機(jī)制以及如何自定義異常來處理請(qǐng)求錯(cuò)誤。
一、SpringBoot默認(rèn)的錯(cuò)誤處理機(jī)制
我們?cè)诎l(fā)送一個(gè)請(qǐng)求的時(shí)候,如果發(fā)生404 SpringBoot會(huì)怎么處理呢?我們來發(fā)送一個(gè)不存在的請(qǐng)求來驗(yàn)證一下看看頁面結(jié)果。如下所示:
當(dāng)服務(wù)器內(nèi)部發(fā)生錯(cuò)誤的時(shí)候,頁面會(huì)返回什么呢?
@GetMapping("/user/{id:\\d+}") public User get(@PathVariable String id) { throw new RuntimeException(); }
我們會(huì)發(fā)現(xiàn)無論是發(fā)生什么錯(cuò)誤,SpringBoot都會(huì)返回一個(gè)狀態(tài)碼以及一個(gè)錯(cuò)誤頁面,這個(gè)錯(cuò)誤頁面是怎么來的呢?
我們來看看SpringBoot錯(cuò)誤處理模塊的源碼就會(huì)非常清楚,默認(rèn)的發(fā)生錯(cuò)誤,它會(huì)將請(qǐng)求轉(zhuǎn)發(fā)到BasicErrorController控制器來處理請(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方法來映射錯(cuò)誤請(qǐng)求,為什么會(huì)是兩個(gè)呢?其實(shí)errorHtml方法映射的是瀏覽器發(fā)送來的請(qǐng)求,而error方法映射的是不是瀏覽器而是其他軟件app客戶端發(fā)送的錯(cuò)誤請(qǐng)求。
看了上面的源碼后,我們是否可以自己定義404或者500的錯(cuò)誤頁面返回給客戶端呢?當(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> 親,您所訪問的頁面不存在 </body> </html>
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>500</title> </head> <body> 服務(wù)器內(nèi)部錯(cuò)誤 </body> </html>
不過注意的是上面的這種自定義頁面的方式只在瀏覽器端有效,而不是瀏覽器發(fā)送的請(qǐng)求不會(huì)生效。因此下面我們就講一下如何自定義異常處理來解決這個(gè)問題。
二、自定義異常處理
怎么自定義異常處理客戶端發(fā)送的錯(cuò)誤信息呢?如果我們查詢一個(gè)用戶,該用戶不存在,我們是否可以將不存在的用戶的id返回給客戶呢?這樣的效果不是給客戶更好地體驗(yàn)嗎?下面我們來實(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è)方法中來處理異常 @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ī)制以及我們自定義異常來處理錯(cuò)誤請(qǐng)求,這更有利于我們的開發(fā),帶給用戶更佳的使用效果。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
idea下如何設(shè)置項(xiàng)目啟動(dòng)的JVM運(yùn)行內(nèi)存大小
這篇文章主要介紹了idea下如何設(shè)置項(xiàng)目啟動(dòng)的JVM運(yùn)行內(nèi)存大小問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12idea?maven項(xiàng)目啟動(dòng)項(xiàng)目不編譯target?文件的問題及解決方法
代碼編輯器中無編譯錯(cuò)誤,通過maven 的clean 、compile、package進(jìn)行各種操作也都沒問題,但是單擊綠色箭頭運(yùn)行(默認(rèn)會(huì)先執(zhí)行IDE本身的Build操作)卻報(bào):程序包xxx不存在,這篇文章主要介紹了解決idea maven項(xiàng)目啟動(dòng)項(xiàng)目不編譯target文件問題,需要的朋友可以參考下2023-05-05Java實(shí)現(xiàn)堆排序(Heapsort)實(shí)例代碼
這篇文章主要介紹了Java實(shí)現(xiàn)堆排序(Heapsort)實(shí)例代碼,有需要的朋友可以參考一下2013-12-12Java實(shí)現(xiàn)樹形結(jié)構(gòu)管理的組合設(shè)計(jì)模式
Java組合模式是一種結(jié)構(gòu)型設(shè)計(jì)模式,它允許將對(duì)象組合成樹形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu)。組合模式使得用戶可以使用統(tǒng)一的方式處理單個(gè)對(duì)象和對(duì)象組合,從而簡(jiǎn)化了系統(tǒng)的設(shè)計(jì)和維護(hù)2023-04-04Java代碼實(shí)現(xiàn)酒店管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了Java代碼實(shí)現(xiàn)酒店管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05Eclipse中Debug時(shí)鼠標(biāo)懸停不能查看變量值解決辦法
這篇文章主要介紹了Eclipse中Debug時(shí)鼠標(biāo)懸停不能查看變量值解決辦法,以及分享了一個(gè)簡(jiǎn)單補(bǔ)全代碼的方法,還是比較不錯(cuò)的,需要的朋友可以參考下。2017-11-11SpringBoot使用異步線程池實(shí)現(xiàn)生產(chǎn)環(huán)境批量數(shù)據(jù)推送
本文主要介紹了SpringBoot使用異步線程池實(shí)現(xiàn)生產(chǎn)環(huán)境批量數(shù)據(jù)推送,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-02-02