springboot同⼀请求⼊⼝,根据不同⼊参⽤不同实体类接收调⽤不同接⼝实现类
(枚举、泛。。。
1.情景展⽰
请求⼊参:
这是⼀个对外提供的请求总⼊⼝,⼊参interfaceMethod对应不同的接⼝名称,具体的接⼝请求参数封装到xcParams⾥⾯。
enum类型如何使用
对外只提供这⼀个接⼝,⽽不是不同接⼝提供不同地址,这样⼀来,⽆论是接⼝提供⽅还是接⼝调⽤⽅只要遵循这种规范,就可以完成不同接⼝的调⽤,也利于后期接⼝的启⽤、禁⽤、扩展新接⼝,提⾼系统的可维护性。
像这样,⽤实体类接收到请求⼊参,获取将要调取的接⼝⽅法,根据不同接⼝名称匹配调⽤不同的业务实现类进⾏业务处理。
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的值,
换句话说,我们这个时候就已经知道,它调⽤的是哪个接⼝,该⽤哪个接⼝实现类来处理!
难点在于:如何往枚举类注⼊对象?
见⽂末推荐。
第七,不同接⼝的请求参数使⽤不同实体类接收;
通过注解@JsonTypeInfo和@JsonSubTypes结合实现
由最开始的时候,我们得知:不同的接⼝虽然请求参数不同,但都会塞到CzParams这个参数中,所以,我们就能根据参数InterfaceMethod来判断当前请求该⽤哪个请求实体类来接收;
所以,CzParams的类型只能⽤泛型来接收(只有在运⾏调⽤的时候,才能知道它是谁);
这样⼀来,请求实体类只需继承抽象类CzRequestParams,并在该⽗类中设置@JsonSubType.Type注解即可。
如此,就能实现刚开始提到的效果;
对于⾼频接⼝,还可以开启多线程,解决并发问题(本⽂未做展⽰)。
4.多态的另⼀种⽤法
2020-12-15
关于⽤泛型接收类的⽅式,其实也是可以去掉的,只是,可能会让看代码的⼈⼀脸懵逼。
上⾯说的很清楚,这个地⽅⽤的是泛型,并在class类上⽤了泛型限定<T extends CzRequestParams>,这样⽅便其它⼈员维护,看到⽴马就知道实际接收参数的是
CzRequestParams的⼦类。
既然是⼦类,那我们何不⽤的⼲脆⼀点?
把泛型⼲掉,直接⽤⽗类接收完事(向上泛型),实际负责接收的还是那些⼦类。
5.嵌套实体类校验不⽣效问题
2020-12-16
使⽤@Valid或@Validator注解进⾏相关检验时,会造成嵌套类上相关校验不⽣效的问题(嵌套验证),⽐如:
CzRequestDto类能够使⽤注解进⾏校验,这没有⼀点问题。
问题是:CzRequestDto类⾥⼜使⽤其他实体类接收请求参数,例如:上图中的泛型,它对应的其中⼀个实体类是下⾯这个类, 这就是所谓的嵌套。
在这个类⾥⾯,使⽤参数校验注解,不会⽣效。
如何解决这个问题?
这个问题困扰了我很久,其实很简单,在嵌套实体类的地⽅,再次声明校验注解就完事了。
写在最后
哪位⼤佬如若发现⽂章存在纰漏之处或需要补充更多内容,欢迎留⾔
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论