SpringMvc 的动态绑定是怎么获得到参数的名字的呢?

2017-04-14 13:25:26 +08:00
 yang2yang

SpringMvc 的 Controller 的函数调用,可以通过反射来,但是假设传递过来两个 String 的对象,比如说 name=abc&password=123,controller 的函数中也有两个 String 的对象分别是 name 和 password,但是想不到啊,到底是怎么做才能将两个东西对应到两个变量上面呢?通过反射也仅仅只能获得到参数类型而已,,,

希望大佬解惑啊,最好有源码例子之类的。。

2632 次点击
所在节点    Java
16 条回复
LeeSeoung
2017-04-14 14:38:17 +08:00
用 @QueryParam("name") 或者直接用对象接收
yang2yang
2017-04-14 15:12:02 +08:00
@LeeSeoung 恩,其实就是想知道不用 @QueryParam 注解的时候,直接使用对象接收的时候,到底 SpringMvc 是怎么做到的?
LeeSeoung
2017-04-14 15:15:35 +08:00
反射是可以通过 getMethod 获取到对象的方法名称的,然后就是匹配的事了
yang2yang
2017-04-14 15:49:24 +08:00
@LeeSeoung 恩,方法名称是可以的,参数类型也可以,但是就是参数名不行。。。这样当两个同样类型的参数尝试绑定的时候,用反射的话就无法知道绑定到哪一个了。。
xiaxiaocao
2017-04-14 16:04:38 +08:00
Spring 是用 asm 从 debug 信息里的 Local Variable Table 读出来的。
在 Java8 之后编译指定了-parameters 参数也能用反射拿到参数名
LeeSeoung
2017-04-14 16:07:25 +08:00
参数名?你用对象接收的时候应该用对应的变量名吧,然后生成对应的 get 和 set 方法,通过 get 和 set+变量名不是可以直接对变量操作么。。你现在的目的是什么?直接用 SpringMvc 不是用对象接收就完事了么 不用你自己再去管哪个匹配哪个吧。
chocotan
2017-04-15 12:14:33 +08:00
onice
2017-04-15 15:42:40 +08:00
```
Class<?> pojoClass = pojo.getClass(); //获取实体类的 Class 对象
Field[] fields = pojoClass.getDeclaredFields(); //获取实体类的字段名
Enumeration<String> parameters = req.getParameterNames(); //获取前端传递的参数名
while(parameters.hasMoreElements()){ //遍历封装参数
String paramName = parameters.nextElement();
for(int i=0;i<fields.length;i++){
if(paramName.equals(fields[i].getName())){
fields[i].setAccessible(true);
fields[i].set(pojo, req.getParameter(paramName));
}
}
}
```

上面是一个 DEMO 。拿到前端传过来的值,然后通过反射对实体类的成员进行名称遍历。名称一致则注入。
onice
2017-04-15 15:43:35 +08:00
@onice 不知道怎么回事,回复的时候使用 markdown 语法,结果没有渲染出代码块。楼主自行美化下了哈。
yang2yang
2017-04-16 09:23:40 +08:00
@onice 非常感谢可以用代码来解释,但是可能误会了我的意思,你这个代码是将前段的参数注入到成员变量中,但是其实我的本意是将其注入到一个成员方法的参数中。。。
thinkmore
2017-04-19 15:43:05 +08:00
你的意思是这个吗?比如前段传过来参数 name=zhangsan&email=test@163.com,然后对应到方法
getAccount(String name,String email)中?
@yang2yang
thinkmore
2017-04-19 16:49:47 +08:00
@yang2yang 其实内部还是使用了注解,当然需要根据字节码进行解析,解析字节码最好的工具当然是 ASM 了。
你可以参考这个,应当可以解答你的疑惑 http://blog.csdn.net/mhmyqn/article/details/47294485
yang2yang
2017-04-19 19:56:35 +08:00
@thinkmore 嗯,很有帮助,但是有一个问题就是,什么叫做内部还是使用了注解?如果是解析字节码中的本地变量表来获得参数并注入参数的话,那么其实并不是使用了注解把?
后来了解了 asm 之后,还有一个疑问,也像你这篇文章讲的这样,必须要带上-g 参数才可以获得参数,但是平常在使用 spring 的时候,难道都默认带上了这个-g 参数吗?一般在 idea 中自己打包。。难道真的是每次编译打包的时候都默认带上了调试信息?
thinkmore
2017-04-20 10:02:36 +08:00
@yang2yang 内部使用了注解是我打错了,当时在想另外一个事情,不好意思

java8 现在可以直接获取参数名称了, java8 以下的话你可以看下 spring 的实现

可以参考下 Spring 的 LocalVariableTableParameterNameDiscoverer

https://github.com/spring-projects/spring-framework/blob/master/spring-core/src/main/java/org/springframework/core/LocalVariableTableParameterNameDiscoverer.java
thinkmore
2017-07-24 10:28:54 +08:00
@yang2yang
经过最近的了解,我来打自己脸了,之前的回答很抱歉应该给你造成了不小的误导,我的说法应该是错的。

关于 springmvc 如何获得参数,是因为在编译的时候保留了 debug 信息(参数名称,行号等),然后 springmvc 在使用的时候可以根据保留的参数名称和前台传递过来的参数名称进行一一对应。

如果你在 @RequestParameter(name="name") String name,中没有指定 @RequestParameter name 属性,那么一旦你没有保留 debug 信息,就会报错,大概意思是没法找到对应的参数。

所以使用 Ant 打包的时候需要指定<javac debug="true" ....>

使用 maven 编译的时候,默认会保留 debug 信息,即 debug=true,当然你也可以进行设置
```
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<debug>true</debug>
<debuglevel>lines,vars,source</debuglevel>
</configuration>
</plugin>
```
yang2yang
2017-07-24 11:05:21 +08:00
@thinkmore 嗯,感谢,其实也没有对我产生误导,我结合你的回答和楼上其他人的回答,之后看了很多资料也是明白的,是需要在编译的时候保留 debug 信息的。可能你觉得没有给我讲到 debug 信息方面的事情,只是提到了 LocalVariableTableParameterNameDiscoverer,所以对我产生误导,其实我也是在知道 debug 信息的情况下,继续参看你的回答的,所以也没有什么误导。不过,maven 默认都会保存 debug 信息和在不对 debug 信息进行保留的情况下,程序会报错这个点,感谢告知,之后自己也没有去做过例子,又加深了理解了呢。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/354834

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX