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也是同一个对象!

 

posted @ 2022-05-08 21:42  努力的达子  阅读(290)  评论(0编辑  收藏  举报