Spring中的@ResponseStatus使用
@ResponseStatus這個注解確實是個令我頭疼的注解.
先記錄下@ResponseStatus注解的定義. 記錄幾個得到的信息:@ResponseStatus聲明在方法、類上, Spring3.0開始才有的, 三個屬性其中 HttpStatus類型的 value 和 code是一個含義, 默認值就是 服務(wù)器 500錯誤的 HttpStatus.
1. 用法一:標注在@RequestMapping方法上
@Controller @RequestMapping("/simple") public class SimpleController { @RequestMapping("/demo2") @ResponseBody @ResponseStatus(code = HttpStatus.OK) public String demo2(){ return "hello world"; } }
上面說了 code 和 value一個意思,這里我就用code了,相對而言比較喜歡code單詞. 這里作用就是改變服務(wù)器響應(yīng)的狀態(tài)碼 ,比如一個本是200的請求可以通過@ResponseStatus 改成404/500等等.
常見的幾個狀態(tài)碼 HttpStatus.OK 就是 200 , HttpStatus.INTERNAL_SERVER_ERROR 就是 500 等等 ,具體的查看 HttpStatus枚舉 有詳細說明.
實現(xiàn)原理呢,注解底層還是通過設(shè)置 response.setStatus來實現(xiàn).
1.1 在@RequestMapping方法執(zhí)行完成
Spring解析返回值之前,進行了responseStatus設(shè)置
代碼片段位于:org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#setResponseStatus
this對象指當前的ServletInvocableHandlerMethod,看到 @ResponseStatus的reason不為空,就調(diào)用response.sendError ; reason為空,就調(diào)用setStatus方法僅僅設(shè)置響應(yīng)狀態(tài)碼.
1.2 記錄下在哪里調(diào)用了這個responseStatus方法 ?
代碼片段位于:org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#invokeAndHandle
發(fā)現(xiàn)如果ServletInvocableHandlerMethod的responseReason有值,也就是@ResponseStatus有reason屬性,@RequestMapping方法返回值都不處理了,直接返回;
也就是說只要有@ResponseStatus的 reason屬性標注在 處理器Controller類或者方法上,比如響應(yīng)狀態(tài)碼code設(shè)置為 404,reason設(shè)置為頁面沒找到 ,那 tomcat 展示界面是這樣大概,展示信息就是我們寫的reason屬性.
@ResponseStatus(code=A,reason=B)標注在 @RequestMapping方法上,作用效果與 response.sendError(A,B)是一樣的.
所以,@ResponseStatus我建議啊, 這種方式下使用千萬不要加 reason, 就把@ResponseStatus 當做一個用來改變響應(yīng)狀態(tài)碼的方式!
2. 用法二:標注在@ControllerAdvice中
@ControllerAdvice @ResponseStatus public class MyControllerAdvice { @ExceptionHandler({ArithmeticException.class}) public ModelAndView fix(Exception e){ Map map=new HashMap(); map.put("ex",e.getMessage()); return new ModelAndView("error",map); } }
@ControllerAdvice標注初衷我想就是程序運行過程中發(fā)生異常,對異常如何處理? 而@ResponseStatus標注在@ControllerAdvice類或者該類下的@ExceptionHandler上,區(qū)別大概就是,
原來比如請求程序拋出異常,異常被捕獲,走@ExceptionHandler,正常走完狀態(tài)碼是200.
@ControllerAdvice或者 @ExceptionHandler標注了@ReponseStatus,那走完狀態(tài)碼就是500.
如果你再給@ResponseStatus添加了reason屬性,不管捕獲異常方法咋返回,都是服務(wù)器的錯誤碼捕獲界面,比如上面我的例子,給@ResponseStatus添加reason=”your defined message”.
不管怎么說,下面界面比一大堆異常堆棧信息看起來更簡潔,但我還是不推薦使用誒,原因啊,界面不友好.
3. 用法三:自定義類型的異常添加注解@ResponseStatus
@ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR,reason = "not an error , just info") public class MyException extends RuntimeException { public MyException() { } public MyException(String message) { super(message); } }
這樣子,在SpringMvc中如果有某個 @RequestMapping方法拋出該異常, 只要開啟<mvc:annotation-driven/>,異常自動展示的界面都是如下的:
4. SpringMvc異常捕獲方法如下
代碼片段位于:org.springframework.web.servlet.DispatcherServlet#processHandlerException
<mvc:annotation-driven/>注冊了三個HandlerExceptionResolver:ExceptionHandlerExceptionResolver用來處理@ExceptionHandler,而ResponseStatusExceptionResolver是用來處理拋出的異常上標注了@ResponseStatus的解析器.
4.1 ResponseStatusExceptionResolver解析異常方式
代碼片段位于:org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver#doResolveException
ex就是@RequestMapping方法拋出自定義的異常,使用工具類解析自定義異常上的@ResponseStatus注解,找到注解就調(diào)用resolveResponseStatus進行響應(yīng)的處理。
protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { ResponseStatus responseStatus = AnnotatedElementUtils.findMergedAnnotation(ex.getClass(), ResponseStatus.class); if (responseStatus != null) { try { return resolveResponseStatus(responseStatus, request, response, handler, ex); } catch (Exception resolveEx) { logger.warn("Handling of @ResponseStatus resulted in Exception", resolveEx); } } else if (ex.getCause() instanceof Exception) { ex = (Exception) ex.getCause(); return doResolveException(request, response, handler, ex); } return null; }
4.2 ResponseStatusExceptionResolver如何根據(jù)異常上的@ResponseStatus處理響應(yīng)?
代碼片段位于:org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver#resolveResponseStatus
獲取了@ReponseStatus的 code reason屬性,reason不為空就 response.sendError(statusCode, reason) ,并且返回一個空的ModelAndView,這里的ModelAndView已經(jīng)沒有意義了,SendError方法簡單來說就是會跳轉(zhuǎn)到web.xml中配置的 錯誤狀態(tài)碼 對應(yīng)的頁面, 沒有配置就是默認的服務(wù)器的那種錯誤界面,且只展示 前面的reason信息,即響應(yīng)類型為text/html .
5. 總結(jié)
不管哪種方式,@ReponseStatus最后都是通過response.setStatus或response.sendError來處理.
如果只是為了返回狀態(tài)碼,建議只使用 @ResponseStatus(code=xxxx)這樣來設(shè)置響應(yīng)狀態(tài)碼;
如果拋出異常呢,不建議@ControllerAdvice里面的 @ResponseStatus和 自定義異常上的 @ResponseStatus一起使用, 按照我的閱讀理解,兩個一起使用肯定是一個生效,而且是 @ControllerAdvice中的@ResponseStatus生效.
場景分析:假設(shè)拋出異常不是我們自定義的異常,我們想改變響應(yīng)的狀態(tài)碼,通過@ExceptionHandler來處理異常,并在@ExceptionHandler方法上也可以設(shè)置@ResponseStatus來達到效果;
假如拋出自定義的異常,自己沒有定義異常處理界面,那在異常上標注@ResponseStatus就可以走 服務(wù)器默認的界面展示,或者通過web.xml 配置error-code \ error-page來自定義界面處理異常;
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java語言簡介(動力節(jié)點Java學(xué)院整理)
Java是一門面向?qū)ο缶幊陶Z言,不僅吸收了C++語言的各種優(yōu)點,還摒棄了C++里難以理解的多繼承、指針等概念,因此Java語言具有功能強大和簡單易用兩個特征,下面通過本文給大家分享java語言的簡介,感興趣的朋友一起看看吧2017-03-03java 開發(fā)中網(wǎng)絡(luò)編程之IP、URL詳解及實例代碼
這篇文章主要介紹了java 開發(fā)中網(wǎng)絡(luò)編程之IP、URL詳解及實例代碼的相關(guān)資料,需要的朋友可以參考下2017-03-03解決"XML Parser Error on line 1: 前言中不允許有內(nèi)容"錯誤
解決用windows自帶的記事編輯xml文件后出現(xiàn) "XML Parser Error on line 1: 前言中不允許有內(nèi)容。"的錯誤2018-02-02Java中Buffer緩沖區(qū)的ByteBuffer類詳解
這篇文章主要介紹了Java中Buffer緩沖區(qū)的ByteBuffer類詳解,ByteBuffer類是Java NIO庫中的一個重要類,用于處理字節(jié)數(shù)據(jù),它提供了一種靈活的方式來讀取、寫入和操作字節(jié)數(shù)據(jù),ByteBuffer類是一個抽象類,可以通過靜態(tài)方法創(chuàng)建不同類型的ByteBuffer對象,需要的朋友可以參考下2023-10-10springboot集成開發(fā)實現(xiàn)商場秒殺功能
這篇文章主要介紹了springboot集成實現(xiàn)商品秒殺功能,秒殺系統(tǒng)業(yè)務(wù)流程,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-12-12