在开发微服务项目时通常会做一些组件的封装,将公用的功能进行各种抽离单独使用打成一个 jar 包,在需要的服务中直接使用 maven 依赖即可,能够达到优化服务代码的目的。
但是,也会在各个服务之间也会存在扩展的问题,比如在公用的 jar 中封装统一响应功能。
在做统一响应时大多数是定义一个枚举响应类,在业务中根据结果进行响应成功与失败。如下:
定义一个结果类:
@Getter
@Setter
@ToString
@EqualsAndHashCode
public class Result<T> {
private Integer code;
private String message;
private T data;
public Result() {
}
public String toJson() {
return JacksonUtils.toJson(this);
}
}
定义一个状态码枚举类: ```java public enum BasicErrorCode {
FAILURE(-1, “Failure”),
SUCCESS(0, “Success”);
private final int code;
private final String message;
BasicErrorCode(int code, String message) {
this.code = code;
this.message = message;
}
public int code() {
return code;
}
public String message() {
return message;
}
}
- 最后再来一个响应工具类:
```java
public class ResponseMsgUtil {
private ResponseMsgUtil() {
}
private static <T> Result<T> builderResponse(int code, String message, T data) {
Result<T> result = new Result<>();
result.setCode(code);
result.setMessage(message);
result.setData(data);
return result;
}
/**
* 请求失败
*/
public static <T> Result<T> failure() {
return failure(BasicErrorCode.FAILURE);
}
public static <T> Result<T> failure(String message) {
return builderResponse(BasicErrorCode.FAILURE.code(), message, null);
}
/**
* 请求成功
*/
public static <T> Result<T> success() {
return success(BasicErrorCode.SUCCESS.message());
}
public static <T> Result<T> success(String message) {
return success(message, null);
}
public static <T> Result<T> success(T data) {
return success(BasicErrorCode.SUCCESS.message(), data);
}
public static <T> Result<T> success(String message, T data) {
return builderResponse(BasicErrorCode.SUCCESS.code(), message, data);
}
}
在使用时返回返回成功或失败,直接使用 ResponseMsgUtil
调用定义的方法即可。比如请求失败:
return ResponseMsgUtil.failure();
但是微服务架构是分模块的,而在公用类中定义的枚举状态码是完全无法满足不同服务的定制化响应。比如在用户系统中,用户登录账号或密码错误该公用的枚举状态码就无法满足。
所以就有这么个需求:对枚举进行扩展。
但是,我们都知道: java 枚举类是一个 final 类,内部定义的枚举值其实都是常量,所以想要使用继承等方式来达到扩展的目的是不可能的事。
不过呢,我们可以反过来想一种实现方式,那就是面向接口编程。看下下面的例子:
public interface Animal {
void printName();
}
public class Cat implements Animal {
@Override
public void printName() {
System.out.println("i am a cat");
}
}
public class Dog implements Animal {
@Override
public void printName() {
System.out.println("i am a dog");
}
}
面向接口编程时我们会发现,不管是 Cat 还是 Dog 它都是属于 Animal 这个类型,在作参数传递时我们将参数设置为 Animal 是不是就可以接受这个接口的任何实例了?
所以,枚举类虽然是个 final 类,但是我们可以定义一个接口,让枚举类去实现它,这样是不是就达到对枚举响应码进行扩展的目的了?
看下如何处理,我们只需要将开始定义的枚举类做下修改即可:
- 定义一个枚举接口类:
public interface ErrorCode {
int code();
String message();
}
让枚举状态码实现该接口:
enum BasicErrorCode implements ErrorCode {
FAILURE(-1, "Failure"),
SUCCESS(0, "Success"),
;
private final int code;
private final String message;
BasicErrorCode(int code, String message) {
this.code = code;
this.message = message;
}
@Override
public int code() {
return code;
}
@Override
public String message() {
return message;
}
}
而响应工具类 ResponseMsgUtil
只需要增加一个方法:
/**
* 扩展使用
*/
public static <T> Result<T> failure(ErrorCode errorCode) {
return builderResponse(errorCode.code(), errorCode.message(), null);
}
在这个扩展方法中接收的参数的类型是 ErrorCode,而该类型是一个接口。这样其他服务如果有扩展枚举响应码需求的话只需要定义一个枚举类实现该接口进行响应的扩展即可,如:
public enum ExampleErrorCode implements ErrorCode {
// 根据各自服务业务需求在这里定义扩展响应码
// 如用户系统, 用户密码错误
USER_OR_PASSWORD_ERROR(10001, "用户名或密码错误"),
// other
;
// 下面的代码不需要变化, 直接拷贝即可
private final int code;
private final String message;
ExampleErrorCode(int code, String message) {
this.code = code;
this.message = message;
}
@Override
public int code() {
return code;
}
@Override
public String message() {
return message;
}
}
响应:
return ResponseMsgUtil.failure(ExampleErrorCode.USER_OR_PASSWORD_ERROR);
这样是不是就达到我们的目的了?