Open Feign统一处理返回

Open Feign统一处理返回

首先,你的 Result 统一返回类必须是有泛型的如:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {
​
    public static final Integer SUCCESS_CODE = 200;     // 访问成功状态码
    public static final Integer ERROR_CODE = 500;       // 访问失败状态码
    private Integer status;                               // 状态码
    private String msg;                                 // 提示消息
    private T data = null;
​
    public Result(Integer status, String msg) {
        this.status = status;
        this.msg = msg;
    }
​
    public static   Result ok(Integer status,String msg,Object data){
        return new Result(status,msg,data);
    }
​
    public static   Result ok(String msg,Object data){
        return new Result(SUCCESS_CODE,msg,data);
    }
​
    public static   Result ok(T data){
        return new Result(SUCCESS_CODE,"操作成功",data);
    }
​
    public static Result ok(){
        return new Result(SUCCESS_CODE,"操作成功",null);
    }
​
    public static Result fail(Integer status,String msg){
        return new Result(status,msg);
    }
​
    public static Result fail(String msg){
        return new Result(ERROR_CODE,msg);
    }
​
    public static Result fail(){
        return new Result(ERROR_CODE,"操作失败");
    }
​
    public static Map ok(Map map){
        map.put("status",SUCCESS_CODE);
        map.put("msg","查询成功");
        return map;
    }
​
    public static Map ok(Page pageInfo){
        Map map = new HashMap<>();
        map.put("status",SUCCESS_CODE);
        map.put("msg","查询成功");
        map.put("count",pageInfo.getTotal());
        map.put("data",pageInfo.getRecords());
        return map;
    }
​
}
​

只有这样,在使用 Openfeign调用远程接口时,返回的 Result 中的 data 数据就不是 Object 类型。

我最开始没有使用泛型,就总是将 Object 类型进行强转,但是一直报错。

但上述条件成立时,你可以设置如下:

@FeignClient(value = "user-service")
public interface UserServiceFeign {
​
    @GetMapping("/api/users/{username}")
    Result getUserByUsername(@PathVariable("username") String username);
​
}

Feign接口返回的是 Result 这其实挺麻烦的,因为我们其实只需要 User 类,所以我们又要手动的取出 Result 中的 data 数据,每次都这样,就比较麻烦。

解决方案

这时我们就可以配置 自定义解码器

@Slf4j
@RequiredArgsConstructor
public class ResultFeignDecoder implements Decoder {
​
    private final ObjectMapper objectMapper;
​
    @Override
    public Object decode(Response response, Type type) throws IOException {
        log.info("调用自定义Feign解码器");
​
        // 读取响应中数据,将响应体中数据转为字符串
        String bodyString = Util.toString(response.body().asReader(Util.UTF_8));
​
        // 解析响应体字符串到 Result 对象
        JavaType parameterType = objectMapper.getTypeFactory().constructType(type);
        JavaType resultType = objectMapper.getTypeFactory().constructParametricType(Result.class, parameterType);
        Result result = objectMapper.readValue(bodyString, resultType);
​
        // 如果响应状态为失败,抛出业务异常
        if (!Result.SUCCESS_CODE.equals(result.getStatus())) {
            throw new BusinessException(result.getMsg());
        }
        // 从 Result 中提取 data 字段
        return result.getData();
    }
​
}
@Configuration   
//只要将其设置为配置类,就全局生效
//否则就必须在 FeignClient 上面加上 
//@FeignClient(configuration = FeignConfig.class)
public class FeignConfig {
​
    @Bean
    public ResultFeignDecoder resultFeignDecoder(ObjectMapper objectMapper) {
        return new ResultFeignDecoder(objectMapper);
    }
​
    //创建自定义Feign.Builder,配置decodeVoid(),此配置的含义是当FeignClient接口返回值类型为void时,仍然使用解码器。
    @Bean
    public Feign.Builder decodeVoidFeignBuilder() {
        return Feign.builder().decodeVoid();
    }
​
}

FeignConfig添加 @Configuration 注解,则解码器和Builder会全局生效,也就是对所有的FeignClient生效;如果不添加 @Configuration 注解,则仅对指定的FeignClient生效。

这样配置之后,当调用 Feign 客户端时,如果返回类型为 Result,则会自动提取 T 类型的数据并返回。

总结

之前为什么我的代码有问题?

我返回的是 Result 没有携带任何的 信息,所以取 data 的时候出问题了,因为Java不知道将 data 转换成什么类型,强行转换也失败。

而现在,我们返回的是 Result 携带了信息 T ,这使得我们Java知道该将 data 转换成什么类型。

最后,我们为了统一的返回处理,避免赘余的取 data 数据的逻辑。创建了一个自定义解码器。直接将 data 中的数据取出来返回。

你可能感兴趣的:(java,OpenFeign,微服务)