1.传入servlet原生API作为参数
可以在SpringMVC方法传入原生的HttpServletRequest和HttpSession
使用setAttribute(String name,Object o)、getAttribute(String name)来携带数据,在JSP处输出
demo
@RequestMapping("testServletApi")
public String testServletApi(HttpServletRequest request, HttpSession session){
request.setAttribute("msg", "这是request");
session.setAtribute("msg", "这是session");
return "success"
}
在 success.jsp中
request: ${requestScope.msg}<br/>
session: ${sessionScope.msg}<br/>
2.传入Map、Model或者ModelMap
可以在方法传入Map、Model或者ModelMap作为参数
通过setAttribute(String name,Object o)、getAttribute(String name)来携带参数
给这些参数里面保存的所有数据都会放在request请求域中,可以在页面获取
Map、Model与ModelMap之间的关系:
无论传入的参数是Map, Model或ModelMap,其最终都是BindingAwareModelMap在工作
相当于BindingAwareModelMap中保存的东西会被放在request请求域中
3.ModelAndView
控制器处理方法的返回值如果为 ModelAndView, 则其既包含视图信息,也包含模型数据信息,且数据是放在request请求域中
-
添加模型数据
MoelAndView addObject(String attributeName, Object attributeValue) -
设置视图
void setViewName(String viewName)
demo:
@RequestMapping("/hello")
public ModelAndView handle_hello(){
ModelAndView mv = new ModelAndView();
mv.setViewName("success");
/*
使用有参构造器传入view名称 ModelAndView mv = new ModelAndView("success");可以省略设置视图
return String 返回的叫做视图名,视图解析器会帮助我们拼接处最终的页面真实地址009
*/
mv.addObject("msg","你好鸭");
}
4.ModelAttribute注解
使用场景:书城的图书修改为例
-
网页端
显示要修改的图书信息 -
servlet收到修改请求,调用dao
String sql="update bs_book set bname=?, author=?
, price=? ,sales=?, stock=?, img_path=?
where id=? " -
并不是全部字段都修改,有些信息属于不可变的(例如书名bname)
1).不修改的字段可以在页面进行展示但不要提供修改输入框
2).为了简单,Contrller直接在参数位置来写Book对象(传入一个javabean,由SpringMVC自动根据请求参数来对javabean属性赋值)
3).SpringMVC为我们自动封装book(请求中没有带的值为null)
4).如果接下来调用一个全字段更新的DAO操作,可能会导致某个字段为Null
针对上述问题,解决方案有:
- 为每个请求编写一个特定的dao,但这样会出现大量冗余代码
- 在html页面的input标签中带上这些字段,设置type=“hidden”,但引入的新的漏洞(在浏览器中更改了该字段的值,或者更严重的是在REST风格中将post或put请求方法修改成delete请求方法)
- 使用ModelAttribute注解
ModelAttribute注解让SpringMVC在封装请求参数的Book对象时,不是new出来,而是先从数据库中读取数据,赋值给JavaBean,然后再根据请求参数对其覆盖,保证不会出现null
@ModelAttribute注解到方法上,这个方法就会提前于目标方法先运行
因此可在注解的方法中先创建JavaBean,并从数据库中读取数据进行赋值,然后将这个JavaBean对象放入Map(或 Model 或 ModelMap)中
demo:
//类范围变量 Object globle_01
@ModelAttribute
public void testModelAttribute(Map<String, Object> map) {
Book book = new Book();
/*
从数据库中查询数据,并赋值给book
*/
map.put("test1", book);
globle_01 = map;
}
@RequestMapping("/testModelAttribute")
public String handle(@ModelAttribute("test1")Book book, Model model){
/*
@ModelAttribute("test1") Book book 注解到参数上表示
告诉SpringMVC,该book对象不必new,而是从BindingAwareModelMap以key="test1"取出
并自动将请求中携带的参数赋值(覆盖)给book
*/
System.out.println("map == model ?" + (globle_01 == model));
/*
结果为true
*/
Object haha = model.getAttribute("test1");
System.out.println("book == haha ?" + (book == haha));
/*
结果为true
*/
}
注意:
- ModelAttribute标注的方法会运行在controller方法之前,所以controller可以从参数列表获取的参数,ModelAttribute方法也可以以同样的方法获取
- ModelAttribute方法运行在所有controller方法之前,所以需要从请求时获取参数时,推荐使用@RequestParam且required=false确保请求中没有携带该属性时不会保存
5.BindingAwareModelMap的一个细节
在一次请求中,无论是使用Map、Model或者ModelMap创建一个请求域的map,或者@ModelAttribute(“xxx”) Obecjt object来告诉SpringMVC从 BindingAwareModelMap 中获取object对象,其本质都是在对同一 BindingAwareModelMap 实例进行存取
即一个请求中只会创建一个 BindingAwareModelMap 实例
6.SpringMVC确定自定义参数值的流程
- 标注解:保存注解的信息;最终得到这个注解应该对应解析的值(如@Autowire)
- 没标注解:
- 看是否是原生API(如HttpServletRequest)
- 看是否是Model或者是Map(赋值BindingAwareModelMap)
- 都不是,看是否是简单类型
- 也不是,那么
1).先去隐含模型中(BindingAwareModelMap中)查找,如果标注了@ModelAttribute(“xxx”),那么就按key=xxx去查找;没有标注,就使用key=参数的类型首字母小写查找
2).如果标注了@SessionAttribute(),那么就去session中查找(这里找不到会报异常,慎用)
3).没找到,那么就通过反射创建一个