SpringCloud OpenFeign自定義結(jié)果解碼器方式
SpringCloud OpenFeign自定義結(jié)果解碼器
我們在定義微服務(wù)接口的時候,通常會使用一個Result類進行封裝,將提示信息,返回對象和狀態(tài)碼等內(nèi)容封裝到一起返回給調(diào)用方,
例如
如下的格式:
public class Result<T> {
/**
* 響應(yīng)碼,200為成功
*/
private Integer code;
/**
* 失敗時的具體失敗信息
*/
private String message;
/**
* 失敗信息是否為用戶提示,如果是的話框架不會主動攔截該錯誤
*/
private boolean userPrompt;
/**
* 響應(yīng)的具體對象
*/
private T data;
}而調(diào)用方在使用Spring Cloud OpenFeign定義的客戶端調(diào)用遠(yuǎn)程服務(wù)時,默認(rèn)的解碼器只能按照定義的方法返回類型對接口的返回結(jié)果進行強制轉(zhuǎn)換,沒辦法實現(xiàn)一些自定義的邏輯,比如將統(tǒng)一返回的Result類重新拆開,僅返回對應(yīng)的業(yè)務(wù)對象,或者對特定的響應(yīng)碼進行處理等等。
為了實現(xiàn)上述功能,我們就需要改造默認(rèn)的Decoder。
Spring Cloud OpenFeign允許我們在定義一個Feign Client的時候,指定一個額外的配置類,比如:
@FeignClient(name = "stores", configuration = CustomizedConfiguration.class)
public interface StoreClient {
//..
}而這個配置類就可以作為我們的擴展點,我們可以在CustomizedConfiguration中定義一個自己的Decoder來覆蓋默認(rèn)的配置。
Spring Cloud對Feign的封裝和默認(rèn)配置可以查看官方文檔。
自定義的Decoder需要實現(xiàn)feign.codec.Decoder接口,也可以參考默認(rèn)的Decoder的實現(xiàn)邏輯(org.springframework.cloud.openfeign.support.ResponseEntityDecoder),下面的實現(xiàn)可以對統(tǒng)一返回值Result類的拆分,并對異常返回進行處理:
public class FeignResultDecoder implements Decoder {
@Override
public Object decode(Response response, Type type) throws IOException, DecodeException, FeignException {
if (response.body() == null) {
throw new DecodeException(response.status(), "沒有返回有效的數(shù)據(jù)", response.request());
}
String bodyStr = Util.toString(response.body().asReader(Util.UTF_8));
//對結(jié)果進行轉(zhuǎn)換
Result result = (Result) JsonUtil.json2obj(bodyStr, type);
//如果返回錯誤,且為內(nèi)部錯誤,則直接拋出異常
if (result.getCode() != ResultCode.SUCCESS.code) {
if (!result.isUserPrompt()) {
throw new DecodeException(response.status(), "接口返回錯誤:" + result.getMessage(), response.request());
}
}
return result.data;
}
}其中如何將response中的json轉(zhuǎn)換為實際的返回類型很費了一些功夫,因為可能存在復(fù)雜的嵌套關(guān)系和泛型定義,最后才發(fā)現(xiàn)jackson框架已經(jīng)有默認(rèn)的實現(xiàn)了…
代碼如下:
public static <T> T json2obj(String jsonStr, Type targetType) {
try {
JavaType javaType = TypeFactory.defaultInstance().constructType(targetType);
return mapper.readValue(jsonStr, javaType);
} catch (IOException e) {
throw new IllegalArgumentException("將JSON轉(zhuǎn)換為對象時發(fā)生錯誤:" + jsonStr, e);
}
}實現(xiàn)了Decoder之后,只需要將其配置到CustomizedConfiguration中即可,注意如果CustomizedConfiguration添加了@Configuration的注解,則會成為Feign Client構(gòu)建的默認(rèn)配置,這樣就不需要在每個@FeignClient注解中都去指定配置類了:
public class CustomizedConfiguration{
@Bean
public Decoder feignDecoder() {
return new FeignResultDecoder();
}
}添加了自定義的Decoder之后,如果一個遠(yuǎn)程接口的定義是這樣的:
@GetMapping("/api/user/detail")
public Result<User> detailById(@RequestParam("id") Integer id) {
User user = userService.getById(id);
return ResultGenerator.genSuccessResult(user);
}我們定義Feign Client方法的時候,方法的返回值可以直接使用Result的泛型類型:
@RequestMapping(value = "/api/user/detail", method = RequestMethod.GET)
public User detailById(@RequestParam("id") Integer id)類似的方式,我們還可以自定義Feign的Encoder,ErrorDecoder等關(guān)鍵配置組件。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
解決spring中redistemplate不能用通配符keys查出相應(yīng)Key的問題
這篇文章主要介紹了解決spring中redistemplate不能用通配符keys查出相應(yīng)Key的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11
Java Stream map, Collectors(toMap, toLis
這篇文章主要介紹了Java Stream map, Collectors(toMap, toList, toSet, groupingBy, collectingAndThen)使用案例,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-09-09
SpringBoot整合Druid數(shù)據(jù)庫連接池的方法
Druid是Java語言中最好的數(shù)據(jù)庫連接池。Druid能夠提供強大的監(jiān)控和擴展功能。這篇文章主要介紹了SpringBoot整合Druid數(shù)據(jù)庫連接池的方法,需要的朋友可以參考下2020-07-07

