美文网首页
Java高级特性-泛型:泛型实战,封装统一的服务端响应类

Java高级特性-泛型:泛型实战,封装统一的服务端响应类

作者: 该叫什么昵称好 | 来源:发表于2021-01-04 12:27 被阅读0次

    在平时工作中,我们写代码可能都在堆增删改查,很少有机会加上 Java 的高级特性。比如,泛型,你一定在 Mybatis、Hibernate 这些持久化框架中用过。可轮到自己开发的时候,却发现这个东西简直鸡肋,完全用不上。

    相信我,这种感觉很正常。因为开源框架往往要用同一套算法,来应对不同的数据结构,而 Java 的高级特性能减少重复代码,从而提高项目的可维护性。

    然而,我们可能身处小公司,项目做完就直接交给客户了。你在最短时间完成工作就行,项目完全没有维护的必要。

    但是,没有关系。这次我们来解锁泛型,用它来封装一个服务端返回类。

    需求分析

    不知道你有没有接手过一些老项目?那时候,SpringMVC 才刚刚出来,大家对代码规范也没概念。结果,碰上个这么方便的框架,后端开发人员就想也不想,直接把各种实体类返回给前端。

    然而,时间一久,问题就来了。

    首先,数据没法保证一致性。你请求某个接口的时候,如果传入的参数不同,得到的结果肯定也会不同。你看下面这个例子:

    // 获取用户信息,正确返回
    {
        "username": "jiarupc",
        "nickname": "法外狂徒、张三",
        "create_date": "2020-12-31 00:00:00"
    }
    
    // 获取用户信息,错误返回
    {
        "msg": "缺少参数,请传入 token"
    }
    

    然后,前端没法处理。你想想看,一个接口如果有时候就返回一堆用户信息,有时候又只返回一条错误信息,这得写多少 if-else 判断呀?

    最后,没法团队合作。如果碰上复杂的项目,最少也要几个人一起开发。这时候,要是返回格式没有一个标准,每个人都按照自己的想法随便写,那项目迟早得乱套。

    事实上,在接手一些老项目时,你会经常看到这种情况。业务明明不复杂,但只要改了一点东西,好几个前端页面就白屏了。

    这时候,如果你想根本解决问题,就必须封装统一服务端响应类。

    设计-服务端响应类

    服务端响应类有 2 个要点:返回值、错误码。

    先来看返回值。在返回前端的时候,我们必须要有这 3 个信息:

    1. code,响应代码;
    2. data,响应数据;
    3. msg,响应信息;

    其中,我们还要进一步设计响应代码,让它能适配更复杂的环境,这里给出几个常用的响应码,你也可以根据实际情况自己设计。

    1. 200-请求成功
    2. 101-执行错误
    3. 102-参数错误

    整体的设计工作就完成了,看起来没啥技术含量,可值得你重视。软件开发中,有些工作虽然很简单,但影响重大,服务端响应类就是这样。

    那么,接下来就是开发工作了。

    开发-服务端响应类

    首先,定义响应代码,我用的是枚举。

    public enum ResponseCode {
    
        // 成功返回
        SUCCESS(200, "SUCCESS"),
        // 执行错误
        ERROR(101, "ERROR"),
        // 参数错误
        ILLEGAL_ARGUMENT(102, "ILLEGAL_ARGUMENT"));
    
        private final int code;
        private final String desc;
    
        ResponseCode(int code, String desc) {
            this.code = code;
            this.desc = desc;
        }
    
        // 省略 getter 方法
    }
    

    然后,创建服务端响应类。其中,为了让 data-响应数据 适配更多的业务场景,我们用泛型来定义它。

    public class ServerResponse<T> implements Serializable {
        
        // 响应代码
        private int code;
        // 响应信息
        private String msg;
        // 响应数据
        private T data;
    
        /**
         * 构造方法
         */
        private ServerResponse(int code, String msg, T data) {
            this.code = code;
            this.msg = msg;
            this.data = data;
        }
        private ServerResponse(int code, T data) {
            this.code = code;
            this.data = data;
        }
        private ServerResponse(int code, String msg) {
            this.code = code;
            this.msg = msg;
        }
        private ServerResponse(int code) {
            this.code = code;
        }
    
        /**
         * 请求成功
         * @param msg  返回信息
         * @param data 泛型数据
         * @param <T>  返回数据,可以不填
         * @return 1.状态码(默认) 2.返回信息 3.泛型数据
         */
        public static <T> ServerResponse<T> createSuccess(String msg, T data) {
            return new ServerResponse<>(ResponseCode.SUCCESS.getCode(), msg, data);
        }
        public static <T> ServerResponse<T> createSuccess(T data) {
            return new ServerResponse<>(ResponseCode.SUCCESS.getCode(), data);
        }
        public static <T> ServerResponse<T> createSuccess(String msg) {
            return new ServerResponse<>(ResponseCode.SUCCESS.getCode(), msg);
        }
        public static <T> ServerResponse<T> createSuccess() {
            return new ServerResponse<>(ResponseCode.SUCCESS.getCode());
        }
    
        /**
         * 请求失败
         * @param code
         * @param msg
         * @return 1.状态码(自定义) 2.返回信息(自定义)
         */
        public static <T> ServerResponse<T> createError(int code, String msg) {
            return new ServerResponse<>(code, msg);
        }
        public static <T> ServerResponse<T> createError() {
            return new ServerResponse<>(ResponseCode.ERROR.getCode(), ResponseCode.ERROR.getDesc());
        }
        public static <T> ServerResponse<T> createError(String msg) {
            return new ServerResponse<>(ResponseCode.ERROR.getCode(), msg);
        }
    
        
        // 省略 getter 方法
    }
    

    开发工作也完成了,接下来,我们可以做出规定,在 Controller 层Service 层中,返回数据必须是 ServerResponse,不许另起炉灶。

    到了这儿,老项目的数据混乱问题,就被圆满解决了。

    写在最后

    泛型是 Java 的高级特性,但我们很少在工作中用到,但是没有关系。在老项目中,前后端交互没有统一的数据标准,这正好是机会。

    为了解决这个问题,我们封装了统一的服务端返回类 ServerResponse,这其中 data-响应数据 用到了泛型,为的是适应更多的业务场景。

    文章演示代码:点击跳转

    相关文章

      网友评论

          本文标题:Java高级特性-泛型:泛型实战,封装统一的服务端响应类

          本文链接:https://www.haomeiwen.com/subject/lfxvoktx.html