Spring中的@ControllerAdvice和ResponseBodyAdvice詳解
@ControllerAdvice
@ControllerAdvice作用于@Controller修飾的類里面的所有方法。
它主要有兩種作用:
對Controller的入?yún)⑦M行預(yù)處理
對Controller中的異常進行全局統(tǒng)一處理
ResponseBodyAdvice
ResponseBodyAdvice作用于@ResponseBody注解修飾的方法,它可以對這些方法的返回值進行修改。
它是一個接口,這個接口有兩個函數(shù):
/**
* @param returnType 可以得到方法和參數(shù)的相關(guān)信息(注解呀,類型呀)
* @param converterType HttpMessageConverter的實現(xiàn)類
* @return 是否對某個接口(被@ResponseBody修飾)的返回值進行修改。如果為true就會調(diào)用
* beforeBodyWrite方法
*/
boolean supports(MethodParameter returnType,
Class<? extends HttpMessageConverter<?>> converterType);
/**
* @param body 被@ResponseBody修飾方法的返回值(區(qū)別于returnType)
* @param returnType 可以得到方法和參數(shù)的相關(guān)信息(注解呀,類型呀)
* @param selectedContentType 選中的媒體類型,即以什么格式寫出數(shù)據(jù)(json、xml、text...)
* @param selectedConverterType HttpMessageConverter的實現(xiàn)類的具體類型
* @param request 請求對象
* @param response 響應(yīng)對象
* @return
*/
T beforeBodyWrite(@Nullable T body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType,
ServerHttpRequest request, ServerHttpResponse response);
類上注釋如下:
Allows customizing the response after the execution of an @ResponseBody or a ResponseEntity controller method but before the body is written with an HttpMessageConverter.
根據(jù)類上的注釋可以得知如果滿足以下兩個條件,則返回值會被ResponseBodyAdvice的beforeBodyWrite方法修改,修改之后的值被HttpMessageConverter寫出,返回給前端瀏覽器。
Controller里的方法被@ResponseBody修飾或者Controller里的方法返回ResponseEntityResponseBodyAdvice的supports方法返回true 注意兩者的執(zhí)行順序
如果針對異常情況和正常情況我們都做了統(tǒng)一處理,要留意不要重復(fù)處理。
示例
新建一個Advice類,它被@ControllerAdvice修飾,又實現(xiàn)了ResponseBodyAdvice接口。我們希望在這個類里面既能實現(xiàn)全局異常處理,又能對后端返回的數(shù)據(jù)統(tǒng)一封裝。
返回結(jié)果封裝類
在Controller里可以返回任意類型,他們都會被封裝到Result的data屬性中。
public class Result {
private int code;
private String data;
// getter and seter
}
全局處理異常,全局封裝返回值
@ControllerAdvice
public class Advice implements ResponseBodyAdvice {
//因為這里也加了@ResponseBody注解,所以它的返回值也會被ResponseBodyAdvice 處理一遍
@ExceptionHandler(Exception.class)
@ResponseBody
public Result he(Exception e) {
Result res = new Result();
res.setCode(500);
res.setData(e.getMessage());
return res;
}
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
//返回任意類型都要封裝
return true;
}
ObjectMapper objectMapper = new ObjectMapper();
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType,
MediaType selectedContentType, Class selectedConverterType,
ServerHttpRequest request, ServerHttpResponse response) {
Result res = new Result();
res.setCode(200);
//如果返回值是String,直接放到Result里
if (body instanceof String) {
res.setData((String) body);
return res;
}
//如果返回值是標準返回格式,就不需要再次封裝了
//如果不加這個判斷,異常的結(jié)果會被封裝兩次
else if (body instanceof Result) {
return body;
}
String dataStr = null;
try {
dataStr = objectMapper.writeValueAsString(body);
res.setData(dataStr);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return res;
}
}
注意:Advice類加了@ControllerAdvice注解,并實現(xiàn)了ResponseBodyAdvice
接口
簡單起見,直接在啟動類里面寫RESTful接口。一個拋出異常,一個返回一個實體類。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@Controller
public class Demo1Application {
public static void main(String[] args) {
SpringApplication.run(Demo1Application.class, args);
}
@GetMapping("ex")
@ResponseBody
public String ex() throws Exception {
throw new Exception("異常信息");
}
@GetMapping("stu")
@ResponseBody
public Stu s() {
final Stu stu = new Stu();
stu.setName("zcx");
stu.setAge(22);
return stu;
}
}
class Stu {
private String name;
private int age;
//getter and setter
}
原理
因為被@ResponseBody注解注釋的返回值都會被RequestResponseBodyMethodProcessor處理,它里面的 HttpMessageConverter在寫出數(shù)據(jù)時,會先拿到一個RequestResponseBodyAdviceChain,先用RequestResponseBodyAdviceChain里面的responseBodyAdvice對Controller返回值進行處理,再寫到瀏覽器。
拓展
與ResponseBodyAdvice類似的有RequestBodyAdvice,它可以對@RequestBody注釋的參數(shù)進行額外處理,在使用時注意不要在beforeBodyRead里面把inputMessage的body讀出來,否則會有I/O異常??梢允褂胊fterBodyRead對參數(shù)進行修改。
到此這篇關(guān)于Spring中的@ControllerAdvice和ResponseBodyAdvice詳解的文章就介紹到這了,更多相關(guān)@ControllerAdvice和ResponseBodyAdvice內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java內(nèi)存區(qū)域與內(nèi)存溢出異常分析與解決
在?Java?開發(fā)中,內(nèi)存管理和內(nèi)存溢出異常是一個至關(guān)重要的主題,本文將深入探討?Java?的內(nèi)存區(qū)域及其對應(yīng)的內(nèi)存溢出異常,希望對大家有所幫助2025-05-05
Spring Cloud Feign實現(xiàn)動態(tài)URL
本文主要介紹了Spring Cloud Feign實現(xiàn)動態(tài)URL,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-02-02
Java實現(xiàn)簡易學(xué)籍管理系統(tǒng)
這篇文章主要為大家詳細介紹了Java實現(xiàn)簡易學(xué)籍管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-02-02
Java使用Spire.Presentation在PowerPoint中添加或刪除表格行與列
在日常開發(fā)中,Java 開發(fā)者常需自動化生成報告PPT,手動編輯PowerPoint 表格行與列效率低下,尤其批量操作時易出錯,Spire.Presentation for Java 庫提供高效解決方案,本文分享實用代碼與步驟,助你快速上手,需要的朋友可以參考下2026-02-02
Druid(新版starter)在SpringBoot下的使用教程
Druid是Java語言中最好的數(shù)據(jù)庫連接池,Druid能夠提供強大的監(jiān)控和擴展功能,DruidDataSource支持的數(shù)據(jù)庫,這篇文章主要介紹了Druid(新版starter)在SpringBoot下的使用,需要的朋友可以參考下2023-05-05

