13.springmvc如何将数据带给页面
1.在参数上写入map
2.在方法上写上model
3.在方法上写上modelMap
4.使用ModelAndView
页面代码一致:利用el表达式从4个域中取数据,看数据存储在哪个域中?
<body>
pageContext:${pageScope.name}<br/>
request:${requestScope.name}<br/>
session:${sessionScope.name}<br/>
appliacation:${applicationScope.name}<br/>
</body>
这里有个注意的地方是:idea创建的web项目中,jsp可能默认关闭了el表达式的支持,具体解决办法参考:
原因是: Web 应用所使用的 web.xml 的版本太低导致的
2.control代码
2.1传入map
@Controller
public class MyFirstController {
@RequestMapping("/hello")
public String hello(Map<String, Object> map){
map.put("name","map");
System.out.println(map.getClass());
return "success";
}
}
页面输出:pageContext:
request:map
session:
appliacation:
结论:发现传递到前台的map数据存储在request域中
2.2传入model
@Controller
public class MyFirstController {
@RequestMapping("/hello")
public String hello(Model model){
model.addAttribute("name","wmd");--->用的是addAttribute方法
System.out.println(model.getClass());
return "success";
}
}
页面输出:
pageContext:
request:wmd
session:
appliacation:
结论:发现传递到前台的map数据存储在request域中
2.3传入ModelMap
@Controller
public class MyFirstController {
@RequestMapping("/hello")
public String hello(ModelMap model){
model.addAttribute("name","wmd");
System.out.println(model.model());
return "success";
}
}
页面输出:
pageContext:
request:wmd
session:
appliacation:
结论:发现传递到前台的map数据存储在request域中
Map/Model/ModelMap在spring中最终的实现是:
1.Map
System.out.println("map:"+map.getClass());
2.Model
System.out.println("model:"+model.getClass());
3.ModelMap
System.out.println("modelMap:"+modelMap.getClass());
若在对应的control类中加上上述的打印语句:
执行结果为:
map:class org.springframework.validation.support.BindingAwareModelMap
model:class org.springframework.validation.support.BindingAwareModelMap
modelMap:class org.springframework.validation.support.BindingAwareModelMap
发现最终工作的类均是:spring中的BindingAwareModelMap
结论:放入BindingAwareModelMap的数据最终存储在了请求域中!
那这几个的关系如何合呢!
使用ModelAndView给页面传值
既包含了视图信息(页面地址),也包含了模型信息(给页面的数据)
而且数据时放在请求域种的
1.第一种做法:使用空的构造器,并使用setViewName指定返回视图名称
@RequestMapping("/hello")
public ModelAndView hello(){
ModelAndView mv = new ModelAndView();
mv.setViewName("success");
mv.addObject("name","wmd");
return mv;
}
2.使用有参构造器指定返回视图名称
@RequestMapping("/hello")
public ModelAndView hello(){
ModelAndView mv = new ModelAndView("success");
mv.addObject("name","wmd");
return mv;
}
给session域中带数据
1.在类上加上@SessionAttributes属性
2.@SessionAttributes注解有两个属性:value 意思是当往前台传入数据的Map/ModelMap/Model和ModelView中,有和value = {"name"} 相同的key时,即对应的map中有name为key的属性时,往session中也放一份
没有就不放:例如:若map.put("nm","wmd"),这里的nm和session要求的name不符,所以不放
3.types = {String.class} 属性,是往上述的四种map中放如数据的类型为String时,均往session中放一份
@Controller
@SessionAttributes(value = {"name"},types = {String.class})
public class MyFirstController {
@RequestMapping("/hello")
public ModelAndView hello(){
ModelAndView mv = new ModelAndView("success");
mv.addObject("name","wmd");
return mv;
}
}
结论:
@SessionAttributes该方法操作session可能会引起异常,尽量少用,还是使用原生的api去操作session即可!
@ModelAttribute
场景:
例如全表更新问题:
例如:有个book类,有很多属性,页面上做对其的更新操作,数据库库中也有对一个的图书记录!
public class Book {
private String bookName;
private Double price;
private String autor;
。。。
}
问题是:因为sql写的是全字段更新的sql,页面如果没有传递某个字段的值,会将默认值null或其他覆盖掉 数据库中本身记录的值
例如(数据库中有条记录:bookName=西游记 price=12 autor=吴承恩),现页面需要改图书价格,传到后台的值是(bookNaem=西游记 price=18 autor=null)
这是会将数据库中该条记录本身autor=吴承恩 改为autor=null,这种场景应该怎么做!
解决思路:在control接收前台传来的值时
@RequestMapping("/hello")
public ModelAndView updateBook(Book book){}
不让spring创建book的新对象进行接收,而是使用从数据库中查询处该条记录作为book,这样book的各个属性均有值,不会出现把已有值更新为null的情况!
使用方法如下:
1.使用@ModelAttribute标注本类的一个方法,并传入参数Map/Modeal/ModealMap用来将查询到的book放入其中,传入的Book book,用来接收页面上传来的值
2.根据页面上传来的book属性查询到数据库的book记录,此处以new为实验
3.将查询到的记录放入到map中,最终都是放入到BindingAwareModelMap中
4.在需要更新图书的目标方法的入参加上@ModelAttribute,告诉spring此处不用新创建Book,而是使用数据库查询出的book,和页面上传入的book进行合并
代码示例:当输入路径为:http://localhost:8080/spring-mvc/hello?bookName=abc
@Controller
public class MyFirstController {
@RequestMapping("/hello")
public String updateBook(@ModelAttribute("hhh") Book book,Model model){
System.out.println("Controller:更新图书操作!");
System.out.println("Controller:"+book);--->此处输出::Book{bookName='abc', price=12.0, autor='吴承恩'}发现其已经进行了合并
return "success";
}
//先执行
@ModelAttribute
public void selectBookByBookname(Map <String,Object> map,Book book){
System.out.println("ModelAttribute:模拟查询书名:"+book.getBookName());
System.out.println("map:"+map.getClass());
//1.模拟从数据库中根据书名查询出该条图书记录
Book book_select=new Book("西游记",12.0 ,"吴承恩");
System.out.println("ModelAttribute查询出的图书记录:"+book_select);---->此处输出:Book{bookName='西游记', price=12.0, autor='吴承恩'}
//2.并将查询出的book放入到传入的Map/Model/ModelMap
map.put("hhh",book_select);
}
}
输出:
book的无参构造器!
ModelAttribute:模拟查询书名:abc
map:class org.springframework.validation.support.BindingAwareModelMap
ModelAttribute查询出的图书记录:Book{bookName='西游记', price=12.0, autor='吴承恩'}
Controller:更新图书操作!
Controller:Book{bookName='abc', price=12.0, autor='吴承恩'}
发现:其执行顺序为,先执行@ModelAttribute的方法,查询记录,放入BindingAwareModelMap,然后再执行目标方法!
注意:带@ModelAttribute传入的map和book与目标方法传入的book和model是同一个对象,map和model底层都是BindingAwareModelMap,且是同一个对象
两个方法传入的book也是同一个对象!