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對象指當(dāng)前的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 當(dāng)做一個用來改變響應(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.lang.IllegalStateException:Duplicate key異常問題
java.lang.IllegalStateException:Duplicatekey異常在將List轉(zhuǎn)換為Map時出現(xiàn),解決方法是使用toMap()的重載方法,如果已經(jīng)存在則不再修改,直接使用上一個數(shù)據(jù)2025-03-03
通過實例了解Java Integer類和int的區(qū)別
這篇文章主要介紹了通過實例了解Java Integer類和int的區(qū)別,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-03-03
使用eclipse導(dǎo)入javaWeb項目的圖文教程
這篇文章主要介紹了如何使用eclipse導(dǎo)入別人的javaWeb項目,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-07-07
SpringBoot如何取消內(nèi)置Tomcat啟動并改用外接Tomcat
這篇文章主要介紹了SpringBoot如何取消內(nèi)置Tomcat啟動并改用外接Tomcat,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-11-11
SpringMVC實現(xiàn)controller中獲取session的實例代碼
本篇文章主要介紹了SpringMVC實現(xiàn)controller中獲取session的實例代碼,具有一定的參考價值,有興趣的可以了解一下。2017-02-02

