1. Problems about JsonResult calling in OpenFeign microservices
When we use Spring Cloud microservices, we usually encapsulate the result by using a JsonResult class, for example, in the following format:
public class JsonResult<T> { /* Response code, 200 is successful */ private Integer code; /* Specific failure information when failure */ private String message; /* Data object on success */ private T data; }
When the caller uses the client defined by Spring Cloud OpenFeign to call a remote service, since the return value of the remote microservice interface is also a JsonResult object, the local interface also needs to use JsonResult to receive, which adds additional Result class to reopen and other work.
Is there any way to implement some custom logic, such as re-opening the unified return Result class and only returning the corresponding business object, or processing specific response codes, etc.?
2. Customize OpenFeign response decoder
In order to implement the above functions, we need to transform the default Decoder. Spring Cloud OpenFeign allows us to specify an additional configuration class when defining a FeignClient, such as:
@FeignClient( name = "xxx-base", path = "/api/base", configuration = /* Custom configuration class */ ) public interface RemoteUserService { //.. }
We can define our own Decoder in CustomizedConfiguration to override the default configuration.
Spring Cloud's packaging and default configuration for Feign can be viewedOfficial Documentation。
Custom Decoder needs to implement interfaces, you can also refer to the default Decoder implementation logic ().
The following implementation can unpack the unified return value Result class and process exception return:
public class CustomizedConfiguration{ @Bean public Decoder feignDecoder() { return new OpenFeignResultDecoder(); } }
public class OpenFeignResultDecoder implements Decoder { @Resource ObjectMapper objectMapper; @Override public Object decode(Response response, Type type) throws IOException, DecodeException, FeignException { String resultJson = (response); try { JavaType rawType = ().constructType(type); JavaType resultType = ().constructParametricType(, ()); JsonResult<?> jsonResult = (resultJson, resultType ); if (() != ()){ throw new DecodeException( (), (), ()); } return (); } catch (Exception ex){ throw new IllegalArgumentException("Object conversion failed: " + ()); } } /* * parse the response body into string */ private static String getResponseBody(Response response) throws IOException { resBody = (); if ((resBody)){ throw new DecodeException( (), "Return body is empty", ()); } String jsonStr; char[] buffer = new char[1024*4]; int len; try ( Reader reader = (StandardCharsets.UTF_8); StringWriter strWriter = new StringWriter() ){ while ((len = (buffer)) != -1){ (buffer, 0, len); } jsonStr= (); } return jsonStr; } }
After implementing Decoder, you only need to configure it into CustomizedConfiguration.
3. Register global configuration for FeignClient
Note that if CustomizedConfiguration adds @Configuration annotation, it will become the default configuration built by Feign Client, so there is no need to specify the configuration class in each @FeignClient annotation:
@Configuration public class OpenFeignConfig { @Bean public Decoder feignDecoder() { return new OpenFeignResultDecoder(); } }
@FeignClient( name = "xxx-base", path = "/api/base" ) public interface RemoteUserService { //.. }
4. Use OpenFeign remote service examples
After adding a custom Decoder, if the definition of a remote interface is like this:
@FeignClient( name = "xxx-base", path = "/api/base" ) public interface RemoteUserService { @GetMapping(value = "/user/detail/{userId}") public User getUserDetailById(@PathVariable Integer userId) }
// ... @Resource RemouteUserService userService public void demoUserService(int userId){ User user = (userId); // .... }
This is the end of this article about SpringCloud OpenFeign custom response decoder. For more related SpringCloud OpenFeign decoder content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!