spring boot2 (五)web中获取请求参数及原理

我反正开发三年多,最常用的还是正常参数的形式传递获取。不过这个路径传参据说是restful风格的常用方式(我是个土鳖,restful风格也没实际用过)。
所以针对多种传参方式,这里也简单的记录一下:

路径传参

这个不仅仅是restful风格可以用,其实本质就是从路径的某段中获取参数,只要使用一个注释:

@PathVariable

下面是简单的使用 demo:


路径传参方法

然后我们去接口访问这个方法:


访问结果

事实证明,路径上带参数,我们用@PathVariable注解获取到了。
至于最后一个获取map的用法,其实在注解中是有说到的。
获取所有路径传参,用map<String,String>类型

获取请求头信息

这个其实也挺有用的,很多时候token都是放在请求头的,当然了还有别的东西也都ok。而获取请求头的方法除了我们在方法中用request获取,也可以直接获取。

@RequestHeader

其实这个方法和上面那个差不多。可以指定获取,也可以用map获取全部的。如下demo:


获取请求头全部信息

虽然看上去不怎么好看,但是起码证明确实获取到请求头了。这个就过了。

获取参数

这个就是正常参数了,依然一个注解:

@RequestParam

使用方法和上面一样,指定参数名称,或者获取全部参数(全部参数的话必须是String,String 的)。


获取全部参数

获取cookie

依旧一个注解开始:

@CookieValue

需要注意的是这个cookie是没有map的,看官网文档的说法,要用cookie接收:


cookie类型

因为我没前端页面都,所以这个访问要用postman来添加cookie再测试:


image.png

cookie的接收测试完毕。

常用的就这几个,接下来重点说参数获取的原理(这里用debug一步一步调试):

首先我们的测试代码是这样的:


请求

其实这个是继续上文说找到那个请求处理器以后的发展了,上文说通过DispatcherServlet类的getHandler方法,找到url所对应的方法全名称。这里仍然debug一步一步走:


走到这个方法

这里有一个小窍门:一般带注释的方法都是值得一看的。我是习惯性百度翻译一下看看的。然后继续往下走到下一个方法:
走到这个方法,进入方法中

ps:这里很多走到接口,然后进入实现方法的。反正见到方法就进入就行了


走到这个方法

其实这个类应该是个很重要的类,毕竟大量invoke方法。然后我们一步一步往下走:


下一步就走到这个方法

因为我这个方法就是普通方法,所以走到这个方法中。其实从它的名字中午文翻译:反射 处理器 方法。大概可以猜测是方法反射的处理器。
点进去以后继续一步一步走:


进入方法中

这个方法中代码很多,但是首先我觉得set本身不会存在赋值行为,所以说前面所有的set我都一路往下。最终走到一个看名字就高大上是方法:
看名字就觉得是有用的方法

然后点进这个方法:


点进这个方法中第一行代码又进入一个invoke的方法,所以再点进去

往里走接下来我手欠走过了,如下截图:
参数已经找到了

到我当前断点的位置,参数都已经赋值了,因为我断点已经过了, 所以直接看看走过的代码:
给参数赋值的代码

其实这个代码逻辑还算是简单,首先创建了一个参数长度的Object数组用来存参数。然后还是一个个 去找参数的值(中间用到了参数解析器)。找到以后continue,去找下一个参数。这里有一点要注意:找不到的话,会报错的!就是我常见的那个错:


找不到参数报错

哎,因为断点跟丢了现在好难受,我从新走一遍吧。
继续上面说的,给参数赋值的方法如下:


给参数赋值方法

点进去查看:
实现赋值方法

继续点进去:


判断当前参数类型是否支持

这个就用到了我们上面说的spring boot自带的26个参数类型解析器。可以点进去瞅瞅:
是一个方法的是否为空的判断

进方法中看:
方法就是一个简单的for循环比对

这里重点的是我圈起来的:argumentResolvers这个参数就是spring boot默认的所有解析器的集合。
如果这里返回null说明当前参数类型不支持,所以为空,最终出去就直接报错了。
spring boot不支持的参数类型就在这里报错

当有这个类型以后去赋值,继续往下走到了赋值的方法:
赋值方法

其实这里又查找了下,确定是有这个类型的。继续往下走:


26种参数解析器类型
根据类型不同去找对应的解析器的方法

其实这里很有意思,大家可以注意这个解析器和注解的名称密切相关啊。比如我demo中用的两个注解:一个@PathVariable一个@RequestParam。都分别有map和普通单个的解析。而且大多数都挺见名知意的,有空可以详细琢磨琢磨这26个解析器。

这里单独说一下我们的实体类是怎么解析的。正常来讲传一个实体对象,然后debug就行了,我这里直接说结果了:
实体类的参数解析器是这个:ServletModelAttributeMethodProcessor
接下来咱们在代码中一步一步走:


测试接口

debug代码走向:


首先这是作为一个参数传过来的

然后我们看看哪个类型解析器解析了这个实体类参数:
for循环中比对

这个因为类型解析器有26个,比较多。所以debug 的时候千万要看好。我就跟丢两次。然后有些一看就不是的注解就不用进去了。比如这个第一个@RequestParam类型的,绝对不可能直接往下走,省的耽误时间。我直接说比对完是哪个类型了:ServletModelAttributeMethodProcessor。我们可以看下走进去的代码:
解析器类型:ServletModelAttributeMethodProcessor

然后我们走进去看看是怎么绑定属性的:


首先获取参数名称

这个方法我也是跟着走了好几次代码。。这里调试一定要慢,宁可每个方法都进去走无用功也别贪快错过去。
反正遇到方法就进

这里主要用反射创建这个类的实例
反射创建这个类的实例

这个时候这个实例是空的,里面没有任何值:
反射创建出来的实例是空的

然后重点来了,赋值的方法是这:bindRequestParameters(binder, webRequest);我来回调试了三四次才确定了这么一个方法。执行前attribute没值,执行后有了。。一眨眼就错过:
这个方法很重要

反正是点点点进到了这个方法,获取实体类的属性并赋值
获取实体属性

从doBind方法进入,然后再进入父类的doBind方法:
父类的doBind方法

到这里可以一步一步进入看了,也算做到了见名知意(虽然我是进了方法才知道干嘛用的)。简单说下,第一步看有没有不许出现的属性。第二步需要的属性。


检查不许出现的属性

这个方法是比对属性是否可以传。我们可以设置实体对象种某些属性不能这么传入。如果不能传的属性现在传过来就会报错:
百度翻译这个报错信息

第二步检查需要的属性:
因为我这个类没设置,所以需要的是空,直接返回了

第三步走进来赋值:
赋值

这一步也会报一个常见的错:xxx属性不存在

就是这一步把实现了给attribute赋值。
再出来已经赋完值了

接下来我们继续往下走:
这里有个判断,attrubute能不能转化成参数类型

这里只要数据类型是对的,一定是可以转化的吧。我暂时没走过不是的分支。。
最后一直往后走,return attribute,然后我们的参数已经是这个对象了。就完事了。

其实这里可能是因为框架完善的原因,很多设计是为了扩展性或者维护性啥。所以debug的时候要不断父子类方法跳,而且还有我上面说的都是大致走向,很多细节还有重要的方法都没怎么说。总结一下我对这块的理解吧:

  1. 获取参数个数。
  2. 判断参数是不是spring boot能解析的类型(这里涉及到spring boot默认的解析器)。
  3. 获取参数上的注释和指定名称(如果指定名称的参数不存在则报错)。
  4. 将参数名称和实际值对应起来。
  5. 有些复杂类型数据用web数据绑定器,将请求参数的值绑定到指定的JavaBean里面。WebDataBinder 利用它里面的 Converters 将请求数据转成指定的数据类型。再次封装到JavaBean中。
  6. 所有的参数都这么走一遍。
    然后就over了。说起来简简单单,各种断点跳转方法几十个。来回走经常容易丢。。真的佩服写spring 的大佬。
    本篇笔记就到这里,如果稍微帮到你了记得点个喜欢点个关注,也祝大家工作顺顺利利!另外如果文中哪里表述不严瑾或者有问题欢迎指出!
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容