在平时工作中,我们写代码可能都在堆增删改查,很少有机会加上 Java 的高级特性。比如,泛型,你一定在 Mybatis、Hibernate 这些持久化框架中用过。可轮到自己开发的时候,却发现这个东西简直鸡肋,完全用不上。
相信我,这种感觉很正常。因为开源框架往往要用同一套算法,来应对不同的数据结构,而 Java 的高级特性能减少重复代码,从而提高项目的可维护性。
然而,我们可能身处小公司,项目做完就直接交给客户了。你在最短时间完成工作就行,项目完全没有维护的必要。
但是,没有关系。这次我们来解锁泛型,用它来封装一个服务端返回类。
需求分析
不知道你有没有接手过一些老项目?那时候,SpringMVC 才刚刚出来,大家对代码规范也没概念。结果,碰上个这么方便的框架,后端开发人员就想也不想,直接把各种实体类返回给前端。
然而,时间一久,问题就来了。
首先,数据没法保证一致性。你请求某个接口的时候,如果传入的参数不同,得到的结果肯定也会不同。你看下面这个例子:
// 获取用户信息,正确返回
{
"username": "jiarupc",
"nickname": "法外狂徒、张三",
"create_date": "2020-12-31 00:00:00"
}
// 获取用户信息,错误返回
{
"msg": "缺少参数,请传入 token"
}
然后,前端没法处理。你想想看,一个接口如果有时候就返回一堆用户信息,有时候又只返回一条错误信息,这得写多少 if-else 判断呀?
最后,没法团队合作。如果碰上复杂的项目,最少也要几个人一起开发。这时候,要是返回格式没有一个标准,每个人都按照自己的想法随便写,那项目迟早得乱套。
事实上,在接手一些老项目时,你会经常看到这种情况。业务明明不复杂,但只要改了一点东西,好几个前端页面就白屏了。
这时候,如果你想根本解决问题,就必须封装统一服务端响应类。
设计-服务端响应类
服务端响应类有 2 个要点:返回值、错误码。
先来看返回值。在返回前端的时候,我们必须要有这 3 个信息:
- code,响应代码;
- data,响应数据;
- msg,响应信息;
其中,我们还要进一步设计响应代码
,让它能适配更复杂的环境,这里给出几个常用的响应码,你也可以根据实际情况自己设计。
- 200-请求成功
- 101-执行错误
- 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-响应数据
用到了泛型,为的是适应更多的业务场景。
文章演示代码:点击跳转
网友评论