1. 问题
实际开发中遇到的问题:业务类型一样,传参基本一样,有个别参数不同,我们需要将其封装成一个接口,这该怎么实现呢?
2. 简单解决方案
使用switch判断具体需要调用哪一个接口,以及负责处理的业务实现类就可以了。
这样的写法是完全没有问题的,已经满足了实际业务需要,这种入门级的代码,基本不要动什么脑子;
但是,如果想要使用高逼格的代码实现这种功能,能够让我们用更多Java知识应用到实际开发过程中,学以致用,使自己的能力得到升华。
3. 高级解决方案
1. RequestParam
@Data
public class RequestParam<T extends AbstractRequestParam> {
@JsonProperty("type")
private String type;
@JsonProperty("param")
private ParamTypeEnum type;
@JsonProperty("version")
private String version;
// 作用于类/接口/属性,被用来开启多态类型处理
@JsonTypeInfo(
// use:必选,使用哪一种类型识别码
use = JsonTypeInfo.Id.NAME, // 使用指定名称作为识别码
// 可选,指定识别码是如何被包含进去的
include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
// 可选,指定识别码的属性名称
property = "param"
)
private T params;
}
@JsonProperty注解
反序列化:将json对象的key与实体类的指定属性对照起来,并完成赋值操作;
@JsonProperty,隶属于Jackson,springboot内部集成,请求入参转实体类默认使用的就是Jackson;
由于将请求参数与泛型进行映射,所以,每个属性都需要加上@JsonProperty注解进行对照。
往枚举类注入对象
如果枚举类只有这一点点作用,那我们也不用废这么劲用它接收,干脆用String类来接收岂不方便?
如果这样想,就大错特错了,再来回想一下,如果我们用String类来接收type的值,那我们岂不是又回到了原点:后续还得用switch来判断,进而调用不同的业务实现类。
之所以想用枚举类来接收type,是因为,这个时候,我们已经拿到了type的值,换句话说,我们这个时候就已经知道,它调用的是哪个接口,该用哪个接口实现类来处理!
难点在于:如何往枚举类注入对象?
不同接口的请求使用不同实体类接收;
通过注解@JsonTypeInfo和@JsonSubTypes结合实现
由最开始的时候,我们得知:不同的接口虽然请求参数不同,但都会塞到params这个参数中,所以,我们就能根据参数type来判断当前请求该用哪个请求实体类来接收;
所以,params的类型只能用泛型来接收(只有在运行调用的时候,才能知道它是谁);
这样一来,请求实体类只需继承抽象类AbstractRequestParam,并设置@JsonSubType.Type注解即可。
2. ParamTypeEnum
@AllArgsConstructor
public enum ParamTypeEnum {
APP("app", "APP"),
WEB("web", "WEB");
@JsonValue
private final String code;
private final String name;
}
用枚举类来接收请求入参的其中一个参数值:
在这里,是用枚举类ParamTypeEnum 来接收请求参数code的值,这个说法并不对,因为枚举类往往不止有一个属性,而param却只有一个值,按正常逻辑来想,json是完全不能实现发序列化的。
这里就不得不提及注解@JsonValue
被加上注解@JsonValue的属性,将会完成值的映射,也就是code的值最终被赋值到枚举类的param属性上,这样就没有一点问题了。
3. AbstractRequestParam
@JsonSubTypes({
// 枚举了多态类型(value对应子类)类型的标识符值(name对应参数type的值对应的实体接受类
@JsonSubTypes.Type(value = AppRequestParam.class, name = "app"),
@JsonSubTypes.Type(value = WebRequestParam.class, name = "web")
})
public abstract class AbstractRequestParam {
}
4. AppRequestParam
@EqualsAndHashCode(callSuper = true)
@Data
public class AppRequestParam extends AbstractRequestParam {
private String name;
private String service;
}
请求实体类只需继承抽象类AbstractRequestParam,并设置@JsonSubType.Type注解即可。
5. WebRequestParam
@EqualsAndHashCode(callSuper = true)
@Data
public class WebRequestParam extends AbstractRequestParam {
private String name;
private String ipPath;
}
请求实体类只需继承抽象类AbstractRequestParam,并设置@JsonSubType.Type注解即可。
6. TestController
@RestController
public class TestController {
@PostMapping("/test")
public <T extends AbstractRequestParam> String test(@RequestBody RequestParam<T> params) {
System.out.println("获取到参数信息"+ params);
ObjectMapper objectMapper = new ObjectMapper();
try {
return objectMapper.writeValueAsString(params);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
}