记一次封装接口返回值问题

Posted _瞳孔

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了记一次封装接口返回值问题相关的知识,希望对你有一定的参考价值。

因为之前的封装都是一个Result然后三个成员code、msg和data,所以无论是否返回数据,返回结果都会有data,于是我为了完整,就做了如下修改:

Result.java:

import lombok.Data;

/**
 * 统一返回格式
 */
public class Result
    /**
     * 成功(无返回数据、默认成功信息)
     * @return Result<Void>
     */
    public static StandardResult<Void> success() 
        NoDataResult noDataResult = new NoDataResult();
        noDataResult.setCode(ResultCode.SUCCESS.getCode());
        noDataResult.setMsg(ResultCode.SUCCESS.getMessage());
        return noDataResult;
    

    /**
     * 成功(无返回数据、自定义成功信息)
     * @return Result<Void>
     */
    public static StandardResult<Void> success(String message) 
        NoDataResult noDataResult = new NoDataResult();
        noDataResult.setCode(ResultCode.SUCCESS.getCode());
        noDataResult.setMsg(message);
        return noDataResult;
    

    /**
     * 成功(有返回数据,默认成功信息)
     * @return Result<V>
     */
    public static <V> StandardResult<V> success(V data) 
        DataResult<V> dataResult = new DataResult<>();
        dataResult.code = ResultCode.SUCCESS.getCode();
        dataResult.msg = ResultCode.SUCCESS.getMessage();
        dataResult.data = data;
        return dataResult;
    

    /**
     * 成功(有返回数据,自定义成功信息)
     * @return Result<V>
     */
    public static <V> StandardResult<V> success(String message, V data) 
        DataResult<V> dataResult = new DataResult<>();
        dataResult.code = ResultCode.SUCCESS.getCode();
        dataResult.msg = message;
        dataResult.data = data;
        return dataResult;
    

    /**
     * 失败(默认错误信息)
     * @return Result<Void>
     */
    public static StandardResult<Void> failure() 
        NoDataResult noDataResult = new NoDataResult();
        noDataResult.setCode(ResultCode.FAILURE.getCode());
        noDataResult.setMsg(ResultCode.FAILURE.getMessage());
        return noDataResult;
    

    /**
     * 失败,使用已定义枚举
     */
    public static StandardResult<Void> failure(ResultCode resultCode) 
        NoDataResult noDataResult = new NoDataResult();
        noDataResult.setCode(resultCode.getCode());
        noDataResult.setMsg(resultCode.getMessage());
        return noDataResult;
    

    /**
     * 失败,使用自定义错误信息
     */
    public static StandardResult<Void> failure(String message) 
        NoDataResult noDataResult = new NoDataResult();
        noDataResult.setCode(ResultCode.FAILURE.getCode());
        noDataResult.setMsg(message);
        return noDataResult;
    

    /**
     * 失败,使用自定义错误码和错误信息
     */
    public static StandardResult<Void> failure(Integer code, String message) 
        NoDataResult noDataResult = new NoDataResult();
        noDataResult.setCode(code);
        noDataResult.setMsg(message);
        return noDataResult;
    

    /**
     * 无数据返回模板
     */
    @Data
    static class NoDataResult implements StandardResult<Void>
        private Integer code;
        private String msg;

        @Override
        public Void getData() 
            return null;
        
    

    /**
     * 有数据返回模板
     */
    @Data
    static class DataResult<V> implements StandardResult<V>
        private Integer code;
        private String msg;
        private V data;
    

ResultCode.java:

/**
 * 状态码类
 */
@Getter
@AllArgsConstructor
public enum ResultCode 
    // 默认成功提示
    SUCCESS(200, "success"),

    // 默认失败提示
    FAILURE(400, "fail"),

    /*
     * 非运行时异常(1000 - 1999)
     */
    PROGRAM_INSIDE_EXCEPTION(1000, "程序内部异常"),

    /*
     * 运行时异常——操作异常(2000 - 5999)
     */
    ILLEGAL_REQUEST_PARAMETER(2000, "非法请求参数"),

    /*
     * 运行时异常——风险异常(6000 - 9999)
     */
    ILLEGAL_REQUEST_ROUTE(6000, "非法路由请求");


    private final Integer code;

    private final String message;

因为是code、msg和data都变成了内部类的成员属性,所以类型都是Result.NoDataResultResult.DataResult之类的,我感觉很难看,于是我让两个内部类都实现一个接口,用以统一返回类型:
StandardResult.java:

public interface StandardResult<T> 
    Integer getCode();

    String getMsg();

    T getData();

这么封装貌似是没有问题的,测试也没有问题:


但由于我这个是微服务项目,在使用feign进行服务调用的时候,就开始报错了:


这个(no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information,我经过查阅资料发现,是因为feign做调用的说话返回值类型不能被反序列化,而我为了类型统一,就实现了StandardResult接口,因此无法被序列化,我也想不出来怎么既可以统一返回类型又可以被序列化,于是只能在feign api内使用内部类类型:


其余地方都使用StandardResult:

注意,如果要使用内部类进行类型约束,需要将Result类中的内部类访问权限改为public:


当然如果不是微服务项目的话,可以直接使用我上面发的封装,如果是微服务项目就得注意我说的那几个修改点

如果有兴趣了解更多相关内容,欢迎来我的个人网站看看:瞳孔的个人网站

以上是关于记一次封装接口返回值问题的主要内容,如果未能解决你的问题,请参考以下文章

记一次前端服务端客户端三方联调的总结

系统上线那点事 - 记一次线上系统故障

记一次使用utl_http方法调用接口,报字符或值错误

记一次接口授权导致的500异常排查

记一次接口授权导致的500异常排查

记一次接口授权导致的500异常排查