SpringMVC处理模型数据的3种方法(Map;@SessionAttributes; @ModelAttribute)

from:http://www.cnblogs.com/yy3b2007com/p/8204004.html  cctext

Spring MVC提供了以下几种途径输出模型数据:

1)ModelAndView:处理方法返回值类型为ModelAndView时,方法体即可通过该对象添加模型数据;

2)Map及Model:处理方法入参为org.springframework.ui.Model、org.springframework.ui.ModelMap或java.util.Map时,处理方法返回时,Map中的数据会自动被添加到模型中;

3)@SessionAttributes:将模型中的某个属性暂存到HttpSeession中,以便多个请求之间可以共享这个属性;

4)@ModelAttribute:方法入参标注该注解后,入参的对象就会放到数据模型中。

Map及Model

使用示例:

在TestModelData.java类中追加方法:

1     @RequestMapping("/testMap")
2     public String testMap(Map<String, Object> map) {
3         map.put("mapTestKey", "mapTestValue");
4         return SUCCESS;
5     }

修改/WEB-INF/views/success.jsp页面,中

测试地址:http://localhost:8080/SpringMVC_02/testMap

返回页面打印信息:

SUCCESS PAGE 
current time: 
testMap mapTestKey:mapTestValue 

查看此时入参Map实际什么类型,修改TestModelData.java代码:

复制代码
    @RequestMapping("/testMap")
    public String testMap(Map<String, Object> map) {
        map.put("mapTestKey", "mapTestValue");
        System.out.println(map);
        System.out.println(map.getClass());
        return SUCCESS;
    }
复制代码

打印结果:

{mapTestKey=mapTestValue}
class org.springframework.validation.support.BindingAwareModelMap

从打印结果发现,实际上入参Map是BildingAwareModelMap

public class BindingAwareModelMap extends ExtendedModelMap 
public class ExtendedModelMap extends ModelMap implements Model 

由于BildingAwareModelMap继承了ExtendedModelMap,而ExtendedModelMap又继承了ModeMap和实现了Model接口,因此,这里Map入参可以替换为ModelMap和Model。

调试:设置断点在“   map.put("mapTestKey", "mapTestValue");”行处

从调试跟踪发现,入参map最终被解析的类是MapMethodProcessor.java

MapMethodProcessor.java

复制代码
 1 /*
 2  * Copyright 2002-2017 the original author or authors.
 3  *
 4  * Licensed under the Apache License, Version 2.0 (the "License");
 5  * you may not use this file except in compliance with the License.
 6  * You may obtain a copy of the License at
 7  *
 8  *      http://www.apache.org/licenses/LICENSE-2.0
 9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package org.springframework.web.method.annotation;
18 
19 import java.util.Map;
20 
21 import org.springframework.core.MethodParameter;
22 import org.springframework.lang.Nullable;
23 import org.springframework.util.Assert;
24 import org.springframework.web.bind.support.WebDataBinderFactory;
25 import org.springframework.web.context.request.NativeWebRequest;
26 import org.springframework.web.method.support.HandlerMethodArgumentResolver;
27 import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
28 import org.springframework.web.method.support.ModelAndViewContainer;
29 
30 /**
31  * Resolves {@link Map} method arguments and handles {@link Map} return values.
32  *
33  * <p>A Map return value can be interpreted in more than one ways depending
34  * on the presence of annotations like {@code @ModelAttribute} or
35  * {@code @ResponseBody}. Therefore this handler should be configured after
36  * the handlers that support these annotations.
37  *
38  * @author Rossen Stoyanchev
39  * @since 3.1
40  */
41 public class MapMethodProcessor implements HandlerMethodArgumentResolver, HandlerMethodReturnValueHandler {
42 
43     @Override
44     public boolean supportsParameter(MethodParameter parameter) {
45         return Map.class.isAssignableFrom(parameter.getParameterType());
46     }
47 
48     @Override
49     @Nullable
50     public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
51             NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
52 
53         Assert.state(mavContainer != null, "ModelAndViewContainer is required for model exposure");
54         return mavContainer.getModel();
55     }
56 
57     @Override
58     public boolean supportsReturnType(MethodParameter returnType) {
59         return Map.class.isAssignableFrom(returnType.getParameterType());
60     }
61 
62     @Override
63     @SuppressWarnings({ "unchecked", "rawtypes" })
64     public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
65             ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
66 
67         if (returnValue instanceof Map){
68             mavContainer.addAllAttributes((Map) returnValue);
69         }
70         else if (returnValue != null) {
71             // should not happen
72             throw new UnsupportedOperationException("Unexpected return type: " +
73                     returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
74         }
75     }
76 
77 }
复制代码

当页面返回时,该入参会被加载到Request请求域。

3)@SessionAttributes:将模型中的某个属性暂存到HttpSeession中,以便多个请求之间可以共享这个属性;

@SessionAttributes

1)若希望在多个请求之间共享某个模型属性数据,则可以在控制器类上标注@SessionAttributes,Spring MVC将在模型中对应的属性暂存到HttpSession中。

测试1:

在TestModelData.java中添加方法testSessionAttribute:

复制代码
1     @RequestMapping("/testSessionAttribute")
2     public String testSessionAttribute(Map<String, Object> map) {
3         Account account = new Account("user1", "pwd123", "2018-01-07", "127.0.0.1");
4         map.put("account", account);
5 
6         System.out.println("testSessionAttribute:"+map);
7         
8         return SUCCESS;
9     }
复制代码

Account.java

  View Code

修改index.jsp,添加链接HTML:

<a href="testSessionAttribute">test SessionAttribute</a>

修改/WEB-INF/views/success.jsp,添加HTML脚本:

    SUCCESS PAGE<br>
    testSessionAttribute request:${requestScope.account.username }<br>
    testSessionAttribute session:${sessionScope.account.username }<br>

此时访问index.jsp,并点击链接后条状到success.jsp也页面显示信息如下:

测试2:

此时默认情况下,并没有把account实体存放到HttpSession中,如何才能实现呢?-------修改TestModelData.java,在TestModelData类上添加注解@SessionAttributes:

复制代码
 1 @SessionAttributes(value = { "account" })
 2 @Controller
 3 public class TestModelData {
 4     private final String SUCCESS = "success";
 5 
 6     @RequestMapping("/testSessionAttribute")
 7     public String testSessionAttribute(Map<String, Object> map) {
 8         Account account = new Account("user1", "pwd123", "2018-01-07", "127.0.0.1");
 9         map.put("account", account);
10 
11         System.out.println("testSessionAttribute:" + map);
12 
13         return SUCCESS;
14     }
15 }
复制代码

此时重新测试,跳转到success.jsp页面时,显示结果如下:

说明已经把account实体对象存放到map的同时,也存放到了HttpSession中。

2)@SessionAttributes除了可以通过属性名指定需要放到会话中的属性外,还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中。

测试3:

上边是通过指定属性名称的方式将account对象存放到HttpSession中的,实际上我们也可以通过指定对象类型实现把某一类对象存放到HttpSession。

修改TestModelData.java

复制代码
 1 @SessionAttributes(value = { "my_value_key" }, types = { Account.class, Integer.class })
 2 @Controller
 3 public class TestModelData {
 4     private final String SUCCESS = "success";
 5 
 6     @RequestMapping("/testSessionAttribute")
 7     public String testSessionAttribute(Map<String, Object> map) {
 8         Account account = new Account("user1", "pwd123", "2018-01-07", "127.0.0.1");
 9         map.put("account", account);
10         map.put("my_value_key", "my_value");
11         Integer age = 30;
12         map.put("age", age);
13         Float onlineHours = 129.88f;
14         map.put("onlineHours", onlineHours);
15 
16         System.out.println("testSessionAttribute:" + map);
17 
18         return SUCCESS;
19     }
20 }
复制代码

修改/WEB-INF/views/success.jsp页面:

复制代码
 1     SUCCESS PAGE<br>
 2     testSessionAttribute request account.username:${requestScope.account.username }<br>
 3     testSessionAttribute session account.username:${sessionScope.account.username }<br>
 4     <br>
 5     testSessionAttribute request my_value_key:${requestScope.my_value_key }<br>
 6     testSessionAttribute session my_value_key:${sessionScope.my_value_key }<br>
 7     <br>
 8     testSessionAttribute request age:${requestScope.age }<br>
 9     testSessionAttribute session age:${sessionScope.age }<br>
10     <br>
11     testSessionAttribute request age:${requestScope.onlineHours }<br>
12     testSessionAttribute session age:${sessionScope.onlineHours }<br>
复制代码

此时访问链接地址,跳转到success.jsp页面后,显示结果:

 



4)@ModelAttribute:方法入参标注该注解后,入参的对象就会放到数据模型中。

用法示例:

Account.java

复制代码
 1 package com.dx.springlearn.entities;
 2 
 3 public class Account {
 4     public Integer id;
 5     private String username;
 6     private String password;
 7     private String registerDate;
 8     private String registerIP;
 9 
10     public Account() {
11     }
12 
13     public Account(Integer id, String username, String password, String registerDate, String registerIP) {
14         super();
15         this.id = id;
16         this.username = username;
17         this.password = password;
18         this.registerDate = registerDate;
19         this.registerIP = registerIP;
20     }
21 
22     public Account(String username, String password, String registerDate, String registerIP) {
23         super();
24         this.username = username;
25         this.password = password;
26         this.registerDate = registerDate;
27         this.registerIP = registerIP;
28     }
29 
30     public Integer getId() {
31         return id;
32     }
33 
34     public void setId(Integer id) {
35         this.id = id;
36     }
37 
38     public String getUsername() {
39         return username;
40     }
41 
42     public void setUsername(String username) {
43         this.username = username;
44     }
45 
46     public String getPassword() {
47         return password;
48     }
49 
50     public void setPassword(String password) {
51         this.password = password;
52     }
53 
54     public String getRegisterDate() {
55         return registerDate;
56     }
57 
58     public void setRegisterDate(String registerDate) {
59         this.registerDate = registerDate;
60     }
61 
62     public String getRegisterIP() {
63         return registerIP;
64     }
65 
66     public void setRegisterIP(String registerIP) {
67         this.registerIP = registerIP;
68     }
69 
70     @Override
71     public String toString() {
72         return "Account [id=" + id + ", username=" + username + ", password=" + password + ", registerDate="
73                 + registerDate + ", registerIP=" + registerIP + "]";
74     }
75 
76     
77 }
复制代码

Handler类TestModelData.java

复制代码
 1 package com.dx.springlearn.hanlders;
 2 
 3 import java.text.SimpleDateFormat;
 4 import java.util.Date;
 5 import java.util.Map;
 6 
 7 import org.springframework.stereotype.Controller;
 8 import org.springframework.web.bind.annotation.ModelAttribute;
 9 import org.springframework.web.bind.annotation.RequestMapping;
10 import org.springframework.web.bind.annotation.RequestParam;
11 import org.springframework.web.servlet.ModelAndView;
12 
13 import com.dx.springlearn.entities.Account;
14 
15 @Controller
16 public class TestModelData {
17     private final String SUCCESS = "success";
18 
19     @ModelAttribute
20     public void getAccount(@RequestParam(name = "id", required = false) Integer id, Map<String, Object> map) {
21         if (id != null) {
22             System.out.println("read account(id=" + id + ") from db");
23             Account account = new Account(1, "tommy", "123456", "2018-01-20 21:56:09", "127.0.0.1");
24             map.put("account", account);
25         } else {
26             System.out.println("the acount id is null");
27         }
28     }
29 
30     @RequestMapping("/testModelAttribute")
31     public ModelAndView testModelAttribute(Account account) {
32         System.out.println("accept account:" + account);
33         String viewName = SUCCESS;
34         ModelAndView modelAndView = new ModelAndView(viewName);
35         modelAndView.addObject("currentTime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
36 
37         return modelAndView;
38     }
39 }
复制代码

测试表单页面:

复制代码
    <form id="form_testModelAttribute" action="testModelAttribute"
        method="POST">
        <input name="id" type="hidden" value="1"/>
        username:<input name="username" type="text" value="tommy" /><br>
        <!-- password:<input name="password" type="password" /><br> -->
        register date:<input name="registerDate" type="text" value="2018-01-20 21:56:09" /><br>
        register ip:<input name="registerIP" type="text" value="127.0.0.1"/><br>
        <input type="submit" value="Submit"/>
    </form>
复制代码

除了handler目标方法参数第一个参数名称与存放到map中的对象名称一致外,也可以使用@ModelAttribute标注handler目标方法参数:

复制代码
package com.dx.springlearn.hanlders;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import com.dx.springlearn.entities.Account;

@Controller
public class TestModelData {
    private final String SUCCESS = "success";

    @ModelAttribute
    public void getAccount(@RequestParam(name = "id", required = false) Integer id, Map<String, Object> map) {
        if (id != null) {
            System.out.println("read account(id=" + id + ") from db");
            Account account = new Account(1, "tommy", "123456", "2018-01-20 21:56:09", "127.0.0.1");
            map.put("testabc", account);
        } else {
            System.out.println("the acount id is null");
        }
    }

    @RequestMapping("/testModelAttribute")
    public ModelAndView testModelAttribute(@ModelAttribute("testabc") Account account) {
        System.out.println("accept account:" + account);
        String viewName = SUCCESS;
        ModelAndView modelAndView = new ModelAndView(viewName);
        modelAndView.addObject("currentTime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));

        return modelAndView;
    }
}
复制代码

运行流程:

1)运行有@ModelAttribute注解标注的方法:从数据库中取出对象,把对象放入到Map中,键值为:user;

2)SpringMVC从Map中取出User对象,并把表单的请求参数赋值给该User对象的对应属性;

3)SpringMVC把上述对象传入目标方法的参数(参数名称必须与Map中的键值一致)。

注意:在@ModelAttribute修饰的方法中,放入Map是的键类型要与目标方法入参类型一直,而且Map是的键名称要与目标方法入参的参数名一致。



猜你喜欢

转载自blog.csdn.net/qq_40587575/article/details/80104348