springboot多态_springboot 同一请求入口,根据不同入参用不同实体类接收&调用不同接口实现类(枚举、泛型、多态综合运用)...
1.情景展示
请求入参:
这是一个对外提供的请求总入口,入参interfaceMethod对应不同的接口名称,具体的接口请求参数封装到xcParams里面。
对外只提供一个接口,而不是不同接口提供不同地址,这样一来,无论是接口提供方还是接口调用方只要遵循这种规范,就可以完成不同接口的调用,也利于后期接口的启用、禁用、扩展新接口,提高系统的可维护性。
像这样,用实体类接收到请求入参,获取将要调取的接口方法,根据不同接口名称匹配调用不同的业务实现类进行业务处理。
2.现状分析
在实际开发过程中,公司与公司之间或者公司内部项目与项目之间往往会存在这种需求,A提供接口,B调用接口,如果是多个接口,那么就想上面那样搞一个总入口就可以了。
使用switch判断具体需要调用哪一个接口,以及负责处理的业务实现类就可以了。
以上的代码是完全没有问题的,已经满足了实际业务需要,这种入门级的代码,基本不要动什么脑子;
但是,如果我们想要使用高逼格的代码实现这种功能,能够让我们用更多java知识应用到实际开发过程中,学以致用,使自己的能力得到升华,换句话说就是:想装X,请欣赏下面的高逼格代码。
(其实,对于产品来说,不管你是低级代码还是高级代码实现,只要能满足产品需求就是OK的,这一点我们一定要摆好自己位置,不能沾沾自喜)
3.高级代码实现
先看效果
请求入参使用了泛型控制,不同接口使用不同实体类接收
调对应接口时,一行代码搞定,无需手动加判断该调哪个业务实现类。
想实现这种效果,就继续往下看哈。
用实体类接收请求入参是本文的重中之重,先来看一下
第一,注解@Getter、@Setter;
使用的是lombok插件,其作用是生成私有属性的Get、Set方法,不想用或者没有的,自己手动生成替代就可以了(类的属性私有化,再对外提供Get和Set方法,其实就是java三大特性之一:封装)。
第二,注解@ApiModelProperty;
对请求参数进行介绍,使用的是knife4j,为接口提供的API文档,最终效果如下图所示:
这样一来,接口的请求参数、响应参数都有详细介绍,与别人对接接口的时候再也不用一遍一遍的跟不同的人解释了,把文档地址扔给他,清晰明了。
注意:这不是本文介绍的重点,有时间会专门写文章介绍的。
第三,注解@JsonProperty;
反序列化:将json对象的key与实体类的指定属性对照起来,并完成赋值操作;
@JsonProperty,隶属于Jackson,springboot内部集成,请求入参转实体类默认使用的就是Jackson;
由于将请求参数与泛型进行映射,所以,每个属性都需要加上@JsonProperty注解进行对照。
第四,注解@NotBlank
字符串非空校验:只用在String上,表示传进来的值不能为null,而且调用trim()后,长度必须大于0,即:必须有实际字符。
说明:泛型无法使用注解进行非空校验,所以,上图中的注解@NotNull无效
第五,用枚举类来接收请求入参的其中一个参数值;
在这里,是用枚举类CzInterfaceEnum来接收请求参数InterfaceMethod的值,这个说法并不对,因为枚举类往往不止有一个属性,而InterfaceMethod却只有一个值,按正常逻辑来想,json是完全不能实现发序列化的。
这我们就不得不提及注解@JsonValue啦
被加上注解@JsonValue的属性,将会完成值的映射,也就是InterfaceMethod的值最终被赋值到枚举类的interfaceName属性上,这样就没有一点问题了。
第六,往枚举类注入对象;
如果枚举类只有这一点点作用,那我们也不用废这么劲用它接收,干脆用String类来接收岂不方便?
如果这样想,就大错特错了,再来回想一下,如果我们用String类来接收InterfaceMethod的值,那我们岂不是又回到了原点:后续还得用switch来判断,进而调用不同的业务实现类。
之所以想用枚举类来接收InterfaceMethod,是因为,这个时候,我们已经拿到了InterfaceMethod的值,换句话说,我们这个时候就已经知道,它调用的是哪个接口,该用哪个接口实现类来处理!
难点在于:如何往枚举类注入对象?
如上图所示,在枚举类中也是可以使用@Resource或@Autowired注入对象,一开始我以为不可以,后来发现其实也是可以哒;
只不过,平常我们在类中注入对象是写在类的最前面(作为类的私有属性),而在枚举中,枚举对象需要在最上面;
这就会出现一个问题,因为枚举类在最上面,而注入的对象在下面(代码先后顺序问题),所以,我们无法在添加枚举类的时候,就为属性interfaceType赋值;
这就很尴尬,不过好在有注解@Postconstruct,被该注解声明的方法,会在注解@Resource或@Autowired执行后,再执行;
这样一来,我们就可以在postContruct()方法中拿到注入的bean对象,进而就可以为指定的枚举类重新为属性interfaceType赋值;
这样,就实现了:为不同的接口注入不同的业务实现类,也就是不同接口自动调用各自的业务处理类。
但是,在实际测试中发现,注入的bean对象还是为空,只得采取这种方式实现:
@Getter
@AllArgsConstructor
public enum CzInterfaceEnum {
// 下面有枚举类的构造方法
INTERFACE_CZ5101("cz5101");
@JsonValue
private String interfaceName;
// 接口类型
@Setter
private InterfaceCz interfaceType;
/**
* 为枚举类注入spring管理的bean对象
* @description:
* @attention: 对象的注入必须创建一个单独的类来完成,不然注入的对象都是null
* @author: Marydon
* @date: 2020年10月29日 0029 17:47
* @version: 1.0
* @email: marydon20170307@163.com
*/
@Component
public static class EnumTypeServiceInjector {
// 为该类注入对象
@Resource private InterfaceCz cz5101Impl;
/*
* 将注入的对象添加到对应的枚举类中
* @attention:
* @date: 2020年11月13日 0013 19:02
* @param:
* @return: void
*/
// @Autowired, @Resource执行后会走该注解
@PostConstruct
private void postConstruct() {
INTERFACE_CZ5101.setInterfaceType(cz5101Impl);
}
}
/*
* 创建只有一个参数的构造方法
* @explain: 创建枚举类(只给一个属性赋值)
* 另一个属性通过EnumTypeServiceInjector注入对象并赋值
* @attention:
* @date: 2020年11月13日19:13:01
* @param: interfaceName 接口名称
* @return:
*/
CzInterfaceEnum(String interfaceName) {
this.interfaceName = interfaceName;
}
}
第七,不同接口的请求使用不同实体类接收;
通过注解@JsonTypeInfo和@JsonSubTypes结合实现
由最开始的时候,我们得知:不同的接口虽然请求参数不同,但都会塞到CzParams这个参数中,所以,我们就能根据参数InterfaceMethod来判断当前请求该用哪个请求实体类来接收;
所以,CzParams的类型只能用泛型来接收(只有在运行调用的时候,才能知道它是谁);
这样一来,请求实体类只需继承抽象类CzRequestParams,并设置@JsonSubType.Type注解即可。
如此,就能实现刚开始提到的效果;
对于高频接口,还可以开启多线程,解决并发问题(本文未做展示)。
4.多态的另一种用法
2020-12-15
关于用泛型接收类的方式,其实也是可以去掉的,只是,可能会让看代码的人一脸懵逼。
上面说的很清楚,这个地方用的是泛型,并在class类上用了泛型限定,这样方便其它人员维护,看到立马就知道实际接收参数的是CzRequestParams的子类。
既然是子类,那我们何不用的干脆一点?
把泛型干掉,直接用父类接收完事(向上泛型),实际负责接收的还是那些子类。
5.嵌套实体类校验不生效问题
2020-12-16
使用@Valid或@Validator注解进行非空检验时,会造成嵌套类上相关校验不生效的问题,比如:
CzRequestDto类能够使用注解进行校验,这没有一点问题。
问题是:CzRequestDto类里又使用其他实体类接收请求参数,例如:上图中的泛型,它对应的其中一个实体类是下面这个类,
这就是所谓的嵌套。
在这个类里面,使用参数校验注解,不会生效。
如何解决这个问题?
这个问题困扰了我很久,其实很简单,在嵌套实体类的地方,再次声明校验注解就完事了。
写在最后
哪位大佬如若发现文章存在纰漏之处或需要补充更多内容,欢迎留言!!!
相关推荐:
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)