spring MVC中接口参数解析的过程详解
作者:007tangtao 发布时间:2023-11-28 09:17:50
前言
前天工作中遇到了这样一个问题,我在接口的参数封装了一个pojo,这是很常见的,当参数一多,惯性的思维就是封装一个pojo.那么在参数前有很多注解可以添加,比如:@requestParam,@requestBody,@pathvariable等。我的理解是这样的,首先我先申明,我并是没有看过源码,只是凭经验理解。@requestParam试用于get请求,参数在http的header中的URL上,具体放在?后面以key=value的形式存在。@requestBody适用于post请求中参数在http的body中。@pathvariable比较特别是restful的写法,把参数放在URL上,不用问号区分是参数还是URL。也许我这样说不是很准确。但我通常也是这么用的。与此同时,还有一种常见的写法,就是参数前不加注解,比如参数是基本类型的不加@requestParam,参数是bean的不加requestBody,也能被springmvc解析得到。我的接口被小组长看到之后他叫我去掉这个@requestBody,因为后端加上这个之后,前端的ajax请求需要显示的声明content-type:"application/json",才能被springmvc解析得到,这样似乎多做了一件不必要的事情。虽然我按照他的要求去掉了,但是我觉得我得弄清楚这到底是怎么回事,加与不加到底有什么区别,对性能有什么影响,或者各自的最佳适用场景,除了百度,还得问问大神。
spring MVC接口参数解析的过程
首先我自己慢慢的通过debug研究了一下源码。在不添加任何注解的情况下:
在开发的过程中consumes和produces一般都没有加,按道理应该要加上,因为可以减少对接口的查找范围。这是一个简单的demo,我只是需要他来检查springmvc接收请求的流程。
首先在tomcat启动之后,所有controller类中的请求路径也就是@requestMapping随着Controller这个bean加载到了spring的容器中。页面请求过来之后找到DispatcherServlet这个servlet,请求走到servlet之后大家都知道servlet有两种初始化方式,一种是随着立即加载,一种是延迟加载,但是无论怎样,都是只调用一次init方法,然后再以后每次都会直接调用service方法,当tomcat关闭之后servlet的destroy方法被调用生命周期就结束了。所以springmvc是对servlet的封装就必定要继承service方法,DispatcherServlet也就是doDispatch这个方法。这个方法中通过HttpServletRequest对象获得请求路径也就是/notJson,然后与容器中的所有url对比,最终取得Controller中的接口所在。找到了接口自然就知道了接口的参数,我这里就是Display,为了方便简单,Display中只有两个参数,就是下面ajax请求中的两个。
springmvc会通过反射的方式获取到pojo中的属性。在这个过程中首先springmvc会先声明一个数组,这个数组的大小是参数的个数,我这里只有一个,其实我相信很多人会和我遇到相同的问题就是,当参数中同时存在bean和基本类型的参数,springmvc将怎么解析,这个我遇到过几次,在没有看源码的情况下,把基本类型也封装到bean中去了,让前端把属性也写在一个对象中。当然我相信这个不是每个人都能接受的做法,我们都希望搞清楚他究竟是怎样解析的,到时候我们就可以任意摆弄了。下面是反射过程,将我的pojo反射之后获得里面的属性和方法。解析了参数之后,为参数赋值。这里也许是最重要的地方了。究竟是怎么赋值的。
从这个方法debug了解到,name为display,也就是pojo类名的小写,这里不知道为什么springmvc做了这个处理(以后再看)。attribute为带有age和name的对象。不过此时都是null。WebDataBinding用于从Web请求参数到JavaBean对象的数据绑定的特殊DataBinder。接上图bindRequestParameters这个方法,跟进去会发现一个很熟悉的地方就是下图,通过String[] values = request.getParameterValues(paramName);
获得参数名,这个是servlet的获取参数方法,那么就可以知道请求的参数的属性名和属性值。
接下来可想而知就是把这个参数名name换成bean的属性name,参数名age换成属性名age。再跟到这个地方,这个oragina就是上面serclet拿到的属性名值对,把这个map在这转化成PropertyValue。(PropertyValue是用于保存单个bean属性的信息和值的对象。 在此处使用对象,而不是仅将所有属性存储在由属性名称键入的映射中,允许更灵活,并且能够以优化的方式处理索引属性等。请注意,该值不需要是最终所需的类型:BeanWrapper实现应该处理任何必要的转换,因为此对象不知道它将应用于哪些对象。),如此一来就有两个PropertyValue对象了。
转化的时候会忽略不知道的属性
上图是具体转化的方法,方法比较长。下面一句直接给bean赋值。从这个过程来看。只要前端的json对象的属性和后端的bean属性一样,ajax不写content-type,用默认的application/x-www-form-urlencoded; charset=UTF-8
,就能直接赋值。
来源:https://www.cnblogs.com/007tangtao/p/9251861.html
猜你喜欢
- 我们经常会看到有一些app的banner界面可以实现循环播放多个广告图片和手动滑动循环的效果。看到那样的效果,相信大家都会想到ViewPag
- 本文实例为大家分享了java实现webservice方式的具体代码,供大家参考,具体内容如下经过测试 jdk1.6.10以下会出现bug 建
- 前言作为一个写java的使用最多的轻量级框架莫过于spring,不管是老项目用到的springmvc,还是现在流行的springboot,都
- 熬夜写完,尚有不足,但仍在努力学习与总结中,而您的点赞与关注,是对我最大的鼓励!在一些本地化项目开发当中,存在这样一种需求,即开发完成的项目
- 一、前言知识补充:Arrays.copyOf函数:public static int[] copyOf(int[] original, in
- 本文实例讲述了Java继承Thread类创建线程类。分享给大家供大家参考,具体如下:一 点睛通过继承Thread类创建线程并启动多线程的步骤
- 背景Swagger 可以提供 API 操作的测试文档,本文记录 Swagger 使用过程中遇到的两个小问题:全局响应结果进行包装后导致 Sw
- 一、spring-boot-devtools在pom中直接引入依赖<dependency> <groupId&
- summarydetail传统的Spring项目会有很多的配置文件,比如我们要使用Redis,一般除了对应的依赖的jar包我们还需要在app
- 本文实例讲述了JAVA设计模式之备忘录模式。分享给大家供大家参考,具体如下:备忘录模式:又叫做快照模式,指在不破坏封装性的前提下,获取到一个
- 1、mapper.xml文件中的sql语句不提示1.1 首先,alt+enter,出现如下窗口随后的窗口选择这样在如下窗口中会增加一个upd
- 本文实例为大家分享了flutter日期时间选择器的具体代码,供大家参考,具体内容如下1 日期选择器 //设置默认显示的日期为当前 DateT
- 简要:EigenFace是基于PCA降维的人脸识别算法,PCA是使整体数据降维后的方差最大,没有考虑降维后类间的变化。 它是将图像
- 工厂方法模式(Factory Method):定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。工
- 概述日常工作中,我们经常会有发送 HTTP 网络请求的需求,概括下我们常见的发送 HTTP 请求的需求内容:可以发送基本的 GET/POST
- 很多童鞋反应在吧项目导入到eclipse(myeclipse)时中文会有乱码,修改了编码格式后还是乱码,这里给大家介绍一下关于中文乱码时修改
- 一、简介ThreadPool相比Thread来说具备了很多优势,但是ThreadPool却又存在一些使用上的不方便。比如:Task支持线程的
- 在使用springMVC框架构建web应用,客户端常会请求字符串、整型、json等格式的数据,通常使用@ResponseBody注解使 co
- 现在Java的大部分项目都是基于Maven, 在Maven项目中使用Selenium2. 非常简单。 首先你需要配置好
- 多数据源创建数据库CREATE DATABASE mybatis_plus_1;USE mybatis_plus_1;CREATE TABL