#1.概述 使用SpringMVC进行开发,controller 内的方法最终都不是我们自己去调用的,
而是由SpringMVC根据请求映射,处理...一系列步骤后去调用了我们编写的
controller中的方法。那么SpringMVC是如何按照我们定义的参数列表将参数
传递的呢?本篇中先对SpringMVC的参数绑定的使用进行讲解说明,不会过
多的设计到源码和原理。后续的章节将会详细剖析源码和原理,让SpringMVC
的爱好者或者热爱学习的同学们对SpringMVC框架有更加深刻透彻的认识。
(不加班,将实践总结为理论的过程也是很有乐趣的:)
1.1 基本原理
使用Java的同学都知道反射机制,SpringMVC之所以能够调用我们在controller
内的方法就是使用了反射机制实现的,如果还记得反射调用方法的代码那么它
大概应该是这个样子的:
public Object invoke(Object obj, Object... args)
SpringMVC 的源代码也是如此实现的:
// org.springframework.web.method.support.InvocableHandlerMethod 中
protected Object doInvoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(getBridgedMethod());
try {
return getBridgedMethod().invoke(getBean(), args);
}
// ......
}
大多数同学现在应该也猜到了,参数绑定的秘密就在于 args 这个参数的产生过程。
#1.web元素绑定 在进行WEB开发的时候我们经常需要使用到HttpServletRequest 、
HttpServletResponse 、HttpSession 这些对象进行操作。只要我们 代码工作在Servlet容器中那么我们总是能够获取到这些对象的。使用 过或者熟悉 struts2 的同学应该还记得,如果我们希望获取到这些对象 那么我们的Action就需要去继承一些XXXAware类,这样做的缺点就是 框架对我们的代码有较大的侵入性。而且就从使用角度来讲这样也不是
很受广大程序员的喜爱。 同样的功能SpringMVC提供了更加简洁的方式,让你的代码变得 clean
// 绑定 HttpServletRequest 对象
public ModelAndView requestBindHandler(HttpServletRequest request){ // ... }
// 绑定 HttpServletResponse 对象
public ModelAndView responseBindHandler(HttpServletResponse response) { // ... }
// 绑定 HttpSession 对象
public ModelAndView sessionBindHandler(HttpSession session) {// ... }
// 绑定 Cookie
public ModelAndView cookieBindHandler(@CookieValue("JSESSIONID") String cookie)
// 绑定 RequestHeader
public ModelAndView headerBindHandler(@RequestHeader("Accept-Language") String acceptLanguage)
2.简单数据类型绑定
- int & Integer
public ModelAndView intBindHandler(int integer) { // ... }
public ModelAndView integerBindHandler(Integer integer) { // ... }
这两种方式都可以完成参数的绑定,前端只需要按照这里的参数名称(如:integer)
为参数名进行参数的传递即可,如图:
**以上两种方式最大的区别就在于,参数为 int 的时候如果前端没有传递这个参数过来那么SpringMVC会抛出 IllegalStateException , 而 Integer 则不会,只会接收到一个 null **。
- byte & Byte , short & Short , long & Long , float & Float ,
double & Double 行为和 int & Integer 一致 。 - String 类型也和上述行为差不多,只不过 String 是引用类型不会出现
如果没有传递该参数就抛出异常的问题。 - boolean & Boolean 的行为比较特殊 , 如果前端没有传递请求参数
SpringMVC会默认将参数设置为 false :
private Object handleNullValue(String name, Object value, Class<?> paramType) {
if (value == null) {
if (Boolean.TYPE.equals(paramType)) {
return Boolean.FALSE;
}
else if (paramType.isPrimitive()) {
throw new IllegalStateException("Optional " + paramType.getSimpleName() + " parameter '" + name +
"' is present but cannot be translated into a null value due to being declared as a " +
"primitive type. Consider declaring it as object wrapper for the corresponding primitive type.");
}
}
return value;
}
3.简单数据类型数组、集合类型绑定
- 数组绑定
public ModelAndView arrayBindHandler(String[] arr)
- List 绑定
public ModelAndView listBindHandler(@RequestParam List<String> list)
- Set 绑定
public ModelAndView setBindHandler(@RequestParam Set<String> set)
- Map 绑定
public ModelAndView mapBindHandler(@RequestParam Map<Object,Object> map)
- 简单 POJO 绑定
public ModelAndView pojoBindHandler(User user)
- JSON 格式的参数绑定
// 利用 @RequestBody 完成 json 反序列化成 POJO
public ModelAndView jsonBindHandler(@RequestBody User user)
** 需要注意的一点是:如果按照上述例子无法正常实现,抛出 HttpMediaTypeNotSupportedException
,原因是 SpringMVC 的 HandlerMethodArgumentResolver 中没有
MappingJackson2HttpMessageConverter 类型的实例 , 引发这个问题的原应是 classpath 路径下没有jackson 的 jar 包。 **
- 相同参数名称,对应多的变量
public ModelAndView sameNameArgBindHand(User user,String name)
当有一个名称为 "name" 的参数被传递时 , 对象 user 中的 name 属性 , 和另一个参数 name 都会被赋值
- POJO 类型的集合绑定
public ModelAndView listPojoBindHadnler(MultipleUserWrap userWrap)
public class MultipleUserWrap {
List<User> users;
public List<User> getUsers() {
return users;
}
public MultipleUserWrap setUsers(List<User> users) {
this.users = users;
return this;
}
}