关于@RequestBody的一些分析

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于@RequestBody的一些分析相关的知识,希望对你有一定的参考价值。

参考技术A 最近在看基于SpringBoot的登录逻辑,项目测试时使用Postman模拟表单登录请求,发现,程序总是报415,也就是不支持的类型。网上查了一圈,猜测可能是前后端参数不匹配导致的问题。排查后发现 @RequestBody 有个坑:无法接收表单登录请求。

基于SpringBoot,准备一个路径跳转Controller:

登录界面如下:

登录请求处理:

User 类以及 Result 不重要,这里就不写出来了, User 类只包含 username 和 password 属性。

登录测试:

但是,如果发送的是"application/json"的话:

通过不断debug,可以得到最后路径和方法的映射关系被保存在了 AbstractHandlerMethodMapping 的 mappingLookup 属性中,可以看到映射方法被封装成了 HandlerMethod 类

登录请求发出后会由 DispatcherServlet 类分配进行后续处理的方法:

DispatcherServlet 的 doDispatch 中的

分配处理器。不断debug,最后在 AbstractHandlerMethodMapping 类中的 getHandlerInternal 中看到了分配结果:

最后又回到了 Dispatch :

正式进入处理流程。

getHandler 方法会返回之前 getHandler 方法返回的处理器。

执行到 RequestMappingHandlerAdapter#invokeHandlerMethod 做一些准备,比如将 HandlerMethod 封装成 ServletInvocableHandlerMethod :

设置参数、返回值解析器:

调用 invokeAndHandlerMethod 进行处理:

毫无疑问, invokeForRequest 用于执行请求:

先获取并解析参数,再通过 doInvoke 方法执行Controller的自定义逻辑。

@RequestBody 的问题就在解析参数上。

接着,不断debug直到进入 HandlerMethodArgumentResolverComposite 的 getArgumentResolver ,事情逐渐明朗:

参数解析类出现了 RequestResponseBodyMethodProcessor ,而这个类正是用来处理 @RequestBody 和 @ResponseBody 注解的。

下面是 RequestResponseBodyMethodProcessor 抽象父类 AbstractMessageConverterMethodProcessor 的参数处理逻辑。

判断能否进行处理的逻辑( AbstractHttpMessageConverter ),其中 supports 方法和 canRead 方法均由具体的实现类提供:

可以看到,发送的JSON字符串可以由MappingJackson2HttpMessageConverter进行处理:

返回值的处理由 AbstractMessageConverterMethodProcessor 的 writeWithMessageConverters 进行,具体就不说了。

没啥结论,要有就是用 @RequestBody 和 @ResponseBody 的时候小心尽量避免表单提交,转而用Ajax或其他传送JSON数据的方式。

这篇文章很不错: Spring MVC源码(三) ----- @RequestBody和@ResponseBody原理解析

记录一些遇见的bug——关于Lombok的一个大坑,使用@RequestBody接收axios请求对象时,对象所有属性均为null

记录一些遇见的bug——关于Lombok的一个大坑,使用@RequestBody接收axios请求对象时,对象所有属性均为null

一、问题

使用axios在前台发送post请求时,后台使用@RequestBody注解接收NoticeAddFo对象,拿不到数据。
拿不到数据问题不大,问题是它也不报错。。。。

//添加公告
const noticeApis = 
    confirmAdd(addNotice)
        return window.axios(
            url:'/api/notice/add',
            method:'post',
            data:addNotice
        )
    


export default noticeApis

二、原因

各种研究各种试,排除了各种错误可能,前台没有多一个或者少一个逗号,后台逻辑也没问题,前台代码后台代码各种方法重写了6遍,还是接收不到。
最后忽然发现:
springboot框架自带的set和get方法长这样子:

而查看编译后的字节码文件,Lombok替我生成的set和get方法长这样子:

以NoticeAddFo类的nContent属性为例:
springboot默认的方法是setnContent(),没有把属性名的首字母大写。
而Lombok利用反射,默认将所有属性的首字母大写来生成set和get方法,写出来的是setNContent()!

三、解决方案

(1) 不用Lombok。
使用idea工具的Generate一键生成的set和get方法与springboot框架的默认方法一样,首字母没有大写,就可以拿到值了。
(2)更改类属性名,不要用首字母小写第二个字母大写这样的格式。

以上是关于关于@RequestBody的一些分析的主要内容,如果未能解决你的问题,请参考以下文章

记录一些遇见的bug——关于Lombok的一个大坑,使用@RequestBody接收axios请求对象时,对象所有属性均为null

记录一些遇见的bug——关于Lombok的一个大坑,使用@RequestBody接收axios请求对象时,对象所有属性均为null

@RequestBody的使用

关于@RequestBody

关于Spring @RequestBody 自动映射模型原理

关于@requestbody接收不到参数的问题