requestparam注解_源码剖析@ApiImplicitParam对
@Request。。。
问题起源
使⽤SpringCloud构建项⽬时,使⽤Swagger⽣成相应的接⼝⽂档是推荐的选项,Swagger能够提供页⾯访问,直接在⽹页上调试后端系统的接⼝, ⾮常⽅便。最近却遇到了⼀个有点困惑的问题,演⽰接⼝⽰例如下(原有功能接⼝带有业务实现逻辑,这⾥简化了接⼝):
/**
* @description: 演⽰类
* @author: Huang Ying
**/
@Api(tags = "演⽰类")
@RestController
@Slf4j
public class DemoController {
@ApiOperation(value = "测试接⼝")
@ApiImplicitParams({
@ApiImplicitParam(name = "uid", value = "⽤户ID", paramType = "query", dataType = "Long")
})
@RequestMapping(value = "/api/json/demo", method = RequestMethod.GET)
public String auth(@RequestParam(value = "uid") Long uid) {
System.out.println(uid);
return "the uid: " + uid;
}
}
问题出在接⼝参数uid的必填性上,@RequestParam注解⾥require默认为true,要求必填,但@ApiImplicitParam注解⾥require默认为false,要求⾮必填,该业务接⼝在进⾏功能联调时,uid居然能得到⼀个null值,按照⼀般认知习惯@ApiImplicitParam注解的主要作⽤是⽣成接⼝⽂档,不应该对@RequestParam的属性有侵⼊性才对,⽬前反馈的bug,让我怀疑@ApiImplicitParam是不是会侵
⼊@RequestParam的require属性?
框架选型、版本及主要功能
项⽬搭建
SpringBoot版本:2.1.6.RELEASE SpringCloud版本:Greenwich.SR3
业务模块
SpringCloud业务模块使⽤的swagger:
swagger bootstrap ui 1.9.6 增强swagger ui样式 spring4all-swagger 1.9.0.RELEASE 配置化swagger参数,免去代码开发
业务⽹关
SpringCloud业务⽹关使⽤的swagger:
knife4j 2.0.1 增强swagger ui样式(⽹关⽤gateway搭建,swagger使⽤knife4j-spring-boot-starter依赖,可以聚合业务模块的swagger⽂档)
此次的范围只针对SpringCloud业务模块,暂时不涉及业务⽹关的Swagger⽂档。
测试⼯具
测试⼯具⽬前有两个:swagger doc:使⽤浏览器进⾏访问,如下图:
postman:⼿动配置接⼝参数,⽰例:
案例实战
接⼝测试1
接⼝⽰例如开篇所⽰,我们先使⽤如下接⼝,全部使⽤默认值,即@ApiImplicitParam的required为false,@RequestParam的required 为true:
@ApiOperation(value = "测试接⼝")
@ApiImplicitParams({
@ApiImplicitParam(name = "uid", value = "⽤户ID", paramType = "query", dataType = "Long")
})
@RequestMapping(value = "/api/json/demo", method = RequestMethod.GET)
public String auth(@RequestParam(value = "uid") Long uid) {
System.out.println(uid);
return "the uid: " + uid;
}
看swagger的结果:
看postman的结果:
接⼝测试2
我们修改@ApiImplicitParam的required值为true,@RequestParam不变,重启模块@ApiImplicitParam(name = "uid", value = "⽤户ID", paramType = "query", required = true, dataType = "Long")
看swagger的结果:
通过调试浏览器可以发现,为空校验是js完成的,js判断为空后,并未发起请求到后端,这样我们可以认为swagger内@ApiImplicitParam 的required参数⽣效了。
接⼝测试3
在前⾯我们使⽤postman测试接⼝时,发现参数项是空的,我们加上参数,但不写值测试后,结果让⼈诧异:
并且⽆论@ApiImplicitParam的required值如何修改,结果都是⼀样的,肯定有⼀个地⽅是搞错了,导致我们误判。
后来仔细查阅资料,发现是我们对@RequestParam的required参数理解错了,这个required为true的含义是:接⼝参数名⼀定要存在,但参数后⾯有没有值它管不着。拿刚刚的例⼦来说:
这两个请求是通过的:
localhost:8080/api/json//demo?uid
localhost:8080/api/json//demo?uid=
只有这种请求是不通过的:
localhost:8080/api/json//demo?
⼩结论
经过上述三个接⼝的测试场景,我们⾄少可以明确3点:
1. @ApiImplicitParam的required参数不会对@RequestParam的required值造成侵⼊,它们俩不相关。
2. @ApiImplicitParam的required参数会影响swagger doc的js逻辑判断,为空校验是在js层⾯上完成的。
3. @RequestParam的required参数默认情况下只会校验是否有该参数名,不校验它是否有值。
源码剖析
swagger部分
上⼀节当中提及swagger读取@ApiImplicitParam注解的required参数,最终会体现在js上,通过浏览器F12的追踪,定位到swaggerbootstrapui.js⽂件上,这⾥摘抄部分源码:
# 点击发送按钮时,逐⾏读取参数信息,并提取required参数
paramBody.find("tr").each(function () {
var paramtr=$(this);
var cked=paramtr.find("td:first").find(":checked").prop("checked");
var _urlAppendflag=true;
//that.log(cked)
if (cked){
//如果选中,留意此⾏的required:paramtr.data("required")信息提取
var trdata={name:paramtr.find("td:eq(2)").find("input").val(),in:paramtr.data("in"),required:paramtr.data("required"),type:paramtr.data("type"),emflag:paramtr.        //that.log("")
//that.log(trdata);
//获取key
//var key=paramtr.find("td:eq(1)").find("input").val();
var key=trdata["name"];
//获取value
var value="";
var reqflag=false;
// 后⾯代码省略
}
})
js上判断该属性required是否为true的处理,js源码如下:
//判断是否required
if (trdata.hasOwnProperty("required")){
var required=trdata["required"];
if (required){
if(!reqflag){
//必须,验证value是否为空
if(value==null||value==""){
validateflag=true;
var des=trdata["name"]
//validateobj={message:des+"不能为空"};
validateobj={message:ssage.debug.fieldNotEmpty};
return false;
}
}
}
param name
}
SpringCloud业务模块部分

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。