在使用SSM框架开发项目时,springmvc负责处理页面的一些请求,然后将数据再通过视图返回给用户的。那么请求是前端通过参数传递到后台在进行执行的。那么这些参数怎么传呢?又有哪些参数可以传递呢?这就是SpringMvc框架中涉及到的参数绑定的问题。
1.参数绑定的过程
在springmvc中,接收页面提交的数据是通过方法形参来接收的。从客户端请求的key/value数据,经过参数绑定,将key/value数据绑定到controller方法的形参上,然后就可以在controller中使用该参数了。来看一下这个过程:
2.默认支持的类型
使用springmvc框架时,有支持的默认类型的绑定。也就是说,直接在controller方法形参上直接定义默认支持的类型的对象,就可以使用这些对象。
SpringMvc默认支持的类型对象:
HttpServletRequest对象
HttpServletResponse对象
HttpSession对象
Model/ModelMap对象
在参数绑定过程中,如果遇到上面4种类型就可以直接进行绑定。也就是说,我们可以在controller的方法的形参中直接定义上面这些类型的参数,springmvc会自动绑定。这里要说明一下的就是Model/ModelMap对象,Model是一个接口,ModelMap是一个接口实现 ,作用是将Model数据填充到request域,跟ModelAndView类似。
3.简单类型的绑定
假设在开发中有个需求:根据商品的id来修改对应商品信息。所以前台页面肯定要传进来这个需要被修改商品的id,然后springmvc的controller进行处理查询出要修改的数据。也就是数据库中根据id进行查询的sql语句。
前台页面通过url将参数传递过来,请求的路径是editItems.action。
<td><a href="${pageContext.request.contextPath }/editItems.action?id=${item.id}">修改</a></td>
在Controller层中的方法为:
@Controller
public class Controller(){
@RequestMapping("/editItems")
public String editItems(Model model, Integer id) throws Exception {
//根据id查询对应的Items
ItemsCustom itemsCustom = itemsService.findItemsById(id);
model.addAttribute("itemsCustom", itemsCustom);
//通过形参中的model将model数据传到页面
//相当于modelAndView.addObject方法
return "/WEB-INF/jsp/items/editItems.jsp";
}
}
从上面的代码中可以看出model可以直接作为参数,springmvc默认会绑定它,然后使用model将查询到的数据放到request域中,这样就可以在前台页面取出该数据了。
注意:简单类型的绑定中,方法形参中的参数名要和前台传进来的名一样才能完成参数的绑定。那么,如果参数名不一致了想让它绑定成功,那咋整呢?有解决办法么?有!我们可以使用注解@RequestParam对简单的类型进行参数绑定,如下:
通过@RequestParam中的required属性指定参数是否必须要传入,如果设置为true,没有传入参数就会报错。
4.POJO类型的绑定
4.1普通的POJO类型
继续上面的案例,当页面根据id查询展示了商品详细信息后,我在信息上做了一些修改,然后点击提交这个页面数据,后台应该将我提交的这些数据全部更新到数据库的items表中,相当于数据库中的修改的sql语句。这个时候提交的参数就不是一个了,可能是两个、三个、四个甚至更多。这个时候我们可以将这些修改页面信息的属性封装到一个pojo中,直接将这个pojo对象作为参数绑定。
数据库Items表中的属性:
绑定很简单,对于基本类型,要求页面中input标签的name属性值和controller的pojo形参中的属性名称一致,即可将页面中数据绑定到pojo。也就是说前台页面传进来的name要和要封装的pojo属性名一模一样,然后就可以将该pojo作为形参放到controller的方法中,如下:
这样就能将前台表单传进来的不同属性值封装到ItemsCustom中了。但是运行一下就会发现报错,报错的信息是无法将String类型转换成java.util.Date类型,因为上面Items中有一个属性是Date类型的createtime。这就需要我们自己定义转换器了,这也是这部分的重点,下面我们自己定义一个日期转换器:
//需要实现Converter接口,这里是将String类型转换成Date类型
public class CustomDateConverter implements Converter<String, Date> {
@Override
public Date convert(String source) {
//实现 将日期串转成日期类型(格式是yyyy-MM-dd HH:mm:ss)
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
//转成直接返回
return simpleDateFormat.parse(source);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//如果参数绑定失败返回null
return null;
}
}
定义好了转换器后,需要在springmvc.xml中进行如下配置:
此时就可以了。但有时候会提交之后发现提交的数据有乱码现象,那么就配置一个过滤器来进行解决。在web.xml中配置:
4.2 包装的POJO类型
这个包装类型pojo与上面普通的pojo有啥区别呢?包装类型pojo指的是pojo中有另一个也是pojo的属性,即pojo中套pojo。
看一下下面这个包装类型的pojo:
图中显示,在ItemsQueryVo的这个类中又包含着itemsCustom包装类,这就是包装的pojo类型。
那么使用包装的pojo类型时,这个ItemsCustom中有name属性,假如我们要想将前台传进来的name属性封装到ItemsCustom中的name属性中,该如何传入呢?这就是包装类型的pojo参数绑定问题。
前端的属性绑定:
然后controller中方法的形参传入包装类型的pojo,即ItemsQueryVo,打个断点,即可查看值有没有传进来。如下:
5.集合类型的绑定
5.1 数组的绑定
数组的绑定指的是前台传来多个同一类型的数据,在controller中使用数组形参来接收前台传来的数据。比如现在我们要批量删除商品,那么我们需要勾选好几个商品,这些商品都有id号,在controller中,我们需要将这些id号全部获取并放到一个数组中,然后再根据数组中的id号挨个删除数据库中对应的项。那么该如何绑定呢?如下:
前端传入的参数:
添加到包装类中:
Controller层中的代码:
5.2 List绑定
我们进行修改一个商品提交时,需要绑定一个pojo类,通常在需要批量提交数据时,就将提交的数据绑定到list<pojo>类
中,比如:成绩录入(录入多门课成绩,批量提交),在这里我们假设有需求:批量商品修改,在页面输入多个商品信息,将多个商品信息提交到controller方法中,即一次性更新多个商品信息。
所以思路是在上述扩展类ItemsQueryVo中新添加一个List<ItemsCustom>
,然后将不同商品的信息都存到这个List中,所以修改如下:
Controller层中的代码:
前端jsp页面中是如何传入参数的呢?这是我们所关心的问题,因为后台形参中接收数据用的就是包装类ItemsQueryVo。看下面:
前端的name属性是通过类似于list[i].name这种形式来传递参数的。list[i]表示第i个ItemsCustom,然后 list[i].属性 表示第i个ItemsCustom中对应的属性。
问题:如果我在形参上不绑定ItemsQueryVo,直接绑定List<ItemsCustom> itemsList可以吗?
回答:不可以,这样做springmvc不认识,所以只有先封装进QueryVo中,再进行执行。
5.3 Map的绑定
Map的绑定其实和List的绑定是差不多的,首先也是在包装的pojo中新添加一个Map类型的属性,如(我随便举个例子,跟本例无关了)
我定义一个QueryVo 的包装pojo类:
关键是前端传递参数时候和List传参有所区别,Map是这样传参的:
我们可以看到,Map的参数绑定传来的是Map中的key,然后value值会直接自动绑定到Map中的那个对象的属性中。