SpringMVC數據綁定全面示例(復雜對象,數組等)


點擊鏈接查詢原文  

http://www.xdemo.org/springmvc-data-bind/

已經使用SpringMVC開發了幾個項目,平時也有不少朋友問我數據怎么傳輸,怎么綁定之類的話題,今天做一個總結。在此之前,大家可以看一下我之前的一篇關於Spring restful的文章http://www.xdemo.org/spring-restful/

項目下載http://pan.baidu.com/share/link?shareid=955245807&uk=1896630845

首先貼出Controller的全部內容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/**
  * @author <a href="http://www.xdemo.org">xdemo.org</a>
  */
@Controller
@RequestMapping (value= "/request" )
public  class  RequestParamController {
                
                /**
                 * 最簡的配置,不是用@RequestParam,效果和get2一樣,默認required=false
                 * 請求方式不限
                 * @param p1
                 * @param map
                 */
                @RequestMapping (value= "get0" )
                public  void  get0(String p1,ModelMap map){
                                map.addAttribute( "p1" , p1); //往頁面傳遞
                }
                
                /**
                 * value="p1"表示參數名稱<br>
                 * required=true表示如果沒有傳遞參數"p1",則會報400參數異常<br>
                 * 使用void表示約定的路徑,即request/get1.jsp
                 * @param p1
                 * @param map
                 */
                @RequestMapping (value= "get1" ,method=RequestMethod.GET)
                public  void  get1( @RequestParam (value= "p1" ,required= true )String p1,ModelMap map){
                                map.addAttribute( "p1" , p1); //往頁面傳遞
                }
                
                /**
                 * 和get1不同的是,p1這個參數不一定非得需要,即使不給這個參數,也可以正常運行<br>
                 * 返回String是視圖的名稱,只要將map賦值,給的值也會帶到前抬
                 * @param p1
                 * @param map
                 * @return
                 */
                @RequestMapping (value= "get2" ,method=RequestMethod.GET)
                public  String get2( @RequestParam (value= "p1" ,required= false )String p1,ModelMap map){
                                map.addAttribute( "p1" , p1); //往頁面傳遞
                                return  "request/get2" ;
                }
                
                /**
                 * 和get2不同的是,返回的對象是ModelAndView
                 * 表示綁定了視圖和數據的對象,數據就是ModelMap中的Key-Value
                 * @param p1
                 * @param map
                 * @return
                 */
                @RequestMapping (value= "get3" ,method=RequestMethod.GET)
                public  ModelAndView get3( @RequestParam (value= "p1" ,required= false )String p1,ModelMap map){
                                map.addAttribute( "p1" , p1);
                                return  new  ModelAndView( "request/get2" ,map);
                }
                
                /**
                 * 跳轉到頁面
                 * @throws NoSuchAlgorithmException 
                 */
                @RequestMapping ( "userForm" )
                public  String userForm(HttpServletResponse response)  throws  NoSuchAlgorithmException{
                                CookieUtils.writeCookie(response, - 1 "x" "dddddddddddddd" );
                                return  "request/userForm" ;
                }
                
                /**
                 * 綁定數據到User對象,支持Map,Set,List,Array等,但是需要使用下標,不是很靈活
                 * 請查看user2的寫法
                 * @param user
                 * @param map
                 */
                @RequestMapping (value= "user" )
                public  void  user(User user,ModelMap map){
                                map.addAttribute( "user" , user);
                }
                
                /**
                 * 這里可以接受List,Array,Set等,寫法是一樣的,注意前端寫法<br>
                 * 另外這個必須要使用MappingJacksonHttpMessageConverter這個消息轉換器
                 * 請看我上面的配置
                 * @param user
                 * @return
                 */
                @ResponseBody
                @RequestMapping ( "user2" )
                public  String user2( @RequestBody  List<User> user){
                                System.out.println(user.size());
                                return  "" ;
                }
                
                /**
                 * 這個方法只支持POST
                 * @param s
                 * @return
                 */
                @ResponseBody
                @RequestMapping ( "array" )
                public  String array( @RequestBody  String[] s){
                                System.out.println(s.length);
                                return  "" ;
                }
                
                /**
                 * 這個比較奇葩,來自一位朋友的寫法,即.xxx/5,4這樣的請求,SpringMVC竟然也是支持的
                 * @param id
                 * @return
                 */
                @ResponseBody
                @RequestMapping (value= "array/{id}" ,method=RequestMethod.GET)
                public  String array2( @PathVariable ( "id" )Long[] id){
                                System.out.println(id.length);
                                return  "array length:" +id.length+ "" ;
                }
                
                /**
                 * 一個表單對應多個Bean對象,這些Bean中有相同的屬性,那么需要在分裝他們的一個整體的對象
                 * 使之支持object.property的表達式
                 * @param c
                 */
                @ResponseBody
                @RequestMapping ( "complex" )
                public  void  complexObject(C c){
                                System.out.println(c.getA().getX());
                                System.out.println(c.getB().getX());
                                
                }
                
                /**
                 * 讀取Cookie的值
                 * @param x
                 * @return
                 */
                @ResponseBody
                @RequestMapping ( "cookie" )
                public  String cookie( @CookieValue ( "x" )String x){
                                return  x;
                }
                
}

這種方式支持get和post,參數可選

1
2
3
4
5
6
7
8
9
10
/**
* 最簡的配置,不是用@RequestParam,效果和get2一樣,默認required=false
* 請求方式不限
* @param p1
* @param map
*/
@RequestMapping (value= "get0" )
public  void  get0(String p1,ModelMap map){
        map.addAttribute( "p1" , p1); //往頁面傳遞
}

訪問方式簡單的比如http://localhost:8080/springmvc-param/request/get0?p1=xxx。


 這種方式支持get,參數必須

1
2
3
4
5
6
7
8
9
10
11
/**
* value="p1"表示參數名稱<br>
* required=true表示如果沒有傳遞參數"p1",則會報400參數異常<br>
* 使用void表示約定的路徑,即request/get1.jsp
* @param p1
* @param map
*/
@RequestMapping (value= "get1" ,method=RequestMethod.GET)
public  void  get1( @RequestParam (value= "p1" ,required= true )String p1,ModelMap map){
        map.addAttribute( "p1" , p1); //往頁面傳遞
}

這種方式和第一種不同的是,指定了訪問訪問必須為GET,而且參數是必須的,可以通過如下方式訪問這個地址:http://localhost:8080/springmvc-param/request/get1?p1=xxxx。


這種方式僅支持GET,參數可選

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 和get1不同的是,p1這個參數不一定非得需要,即使不給這個參數,也可以正常運行<br>
* 返回String是視圖的名稱,只要將map賦值,給的值也會帶到前抬
* @param p1
* @param map
* @return
*/
@RequestMapping (value= "get2" ,method=RequestMethod.GET)
public  String get2( @RequestParam (value= "p1" ,required= false )String p1,ModelMap map){
        map.addAttribute( "p1" , p1); //往頁面傳遞
        return  "request/get2" ;
}

這個方法和第二種唯一不同的就是參數是可選的,其他沒有不同。


 這種方式僅支持GET,參數可選

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 和get2不同的是,返回的對象是ModelAndView
* 表示綁定了視圖和數據的對象,數據就是ModelMap中的Key-Value
* @param p1
* @param map
* @return
*/
@RequestMapping (value= "get3" ,method=RequestMethod.GET)
public  ModelAndView get3( @RequestParam (value= "p1" ,required= false )String p1,ModelMap map){
        map.addAttribute( "p1" , p1); //往頁面傳遞
        return  new  ModelAndView( "request/get2" ,map);
}

ModelAndView表示綁定了數據的視圖,可以通過EL表達式去取值。


 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
  * 跳轉到頁面
  * @throws NoSuchAlgorithmException 
  */
@RequestMapping ( "userForm" )
public  String userForm(HttpServletResponse response)  throws  NoSuchAlgorithmException{
        CookieUtils.writeCookie(response, - 1 "x" "dddddddddddddd" );
        return  "request/userForm" ;
}
/**
* 讀取Cookie的值
* @param x
* @return
*/
@ResponseBody
@RequestMapping ( "cookie" )
public  String cookie( @CookieValue ( "x" )String x){
        return  x;
}

先訪問http://localhost:8080/springmvc-param/request/userForm這個方法,跳轉到一個頁面,並向瀏覽器寫入Cookie,第二個方法訪問的時候即可通過@CookieValue方式來取到Cookie中的值。


綁定數據到一個對象上,支持get和post

一個User,一個Phone,一個User擁有多個Phone,為了演示,User中有一個List和Array的Phone的集合

1
2
3
4
5
6
7
8
public  class  User {
                
        private  String userName;
        private  String address;
        private  List<Phone> phones;
        private  Phone[] phones2;
        //省略GET和SET...
}
1
2
3
public  class  Phone {
                private  String brand; //手機品牌
}

Controller方法如下

1
2
3
4
5
6
7
8
9
10
/**
* 綁定數據到User對象,支持Map,Set,List,Array等,但是需要使用下標,不是很靈活
* 請查看user2的寫法
* @param user
* @param map
*/
@RequestMapping (value= "user" )
public  void  user(User user,ModelMap map){
        map.addAttribute( "user" , user);
}

HTML表單如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
< form  action = "request/user"  method = "get"  style = "border:1px solid red;" >
      < table >
            < tr >< td  colspan = "2" >這個表單演示了對象數據綁定的方法,以及對象中的Set,List,Array數據綁定(三者類似)</ td ></ tr >
             < tr >
                 < td >用戶名:</ td >
                 < td >< input  type = "text"  name = "userName"  value = "張三" ></ td >
             </ tr >
             < tr >
                 < td >用戶地址:</ td >
                 < td >< input  type = "text"  name = "address"  value = "江蘇省無錫市新區菱湖大道200號" >< br ></ td >
             </ tr >
             < tr >
                 < td >手機品牌:</ td >
                 < td >
                     < input  type = "text"  name = "phones[0].brand"  value = "SONY" >< br >
                     < input  type = "text"  name = "phones[1].brand"  value = "MOTO" >< br >
                     < input  type = "text"  name = "phones[2].brand"  value = "LG" >< br >
                  </ td >
              </ tr >
              < tr >
                  < td >手機品牌2:</ td >
                  < td >
                      < input  type = "text"  name = "phones2[0].brand"  value = "Apple" >< br >
                      < input  type = "text"  name = "phones2[1].brand"  value = "Samsung" >< br >
                      < input  type = "text"  name = "phones2[2].brand"  value = "HTC" >< br >
                  </ td >
               </ tr >
               < tr >
                   < td  colspan = "2"  style = "text-align: right;" >
                   < input  type = "submit"  value = "提交" >
                   </ td >
                </ tr >
        </ table >
</ form >

一對多的時候,使用多一方的在一一方的對象中的屬性名,加上數組下標,即phones[0].brand,phones[1].brand即可綁定到User的phones屬性上,這種方法的局限性就是要求下標是正確的,否則會無法綁定,不是很方便,但是也有其適用場景。


下面這種方法就是比較方便了,僅支持post,但是必須要在消息轉換器中配置JSON解析器

1
<bean  class = "org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" ></bean>

並注冊到RequestMappingHandlerAdaptermessageConverters中。

Controller如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
  * 這里可以接受List,Array,Set等,寫法是一樣的,注意前端寫法<br>
  * 另外這個必須要使用MappingJacksonHttpMessageConverter這個消息轉換器
  * 請看我上面的配置
  * @param user
  * @return
  */
  @ResponseBody
  @RequestMapping ( "user2" )
  public  String user2( @RequestBody  List<User> user){
          System.out.println(user.size());
          return  "" ;
  }

Javascript如下

1
2
3
4
5
6
7
8
9
10
11
12
13
var  userList=  new  Array();
userList.push({userName: "xx" ,address: "fff" });
userList.push({userName: "zzzz" ,address: "ggggg" });
$.ajax({
   url: "request/user2" ,
   type: "post" ,
   data:JSON.stringify(userList),
   dataType: "json" ,
   contentType: "application/json" ,
   success: function (data){
    },error: function (data){
   }
});

該方法僅支持POST的方式,會使用到json2.js這個類庫,注意設置contentType:"application/json"這個屬性,否則會報415未知的類型異常。


傳遞簡單的字符串數組,僅支持POST方式

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 傳遞簡單的字符串數組
* 這個方法只支持POST
* @param s
* @return
*/
@ResponseBody
@RequestMapping ( "array" )
public  String array( @RequestBody  String[] s){
     System.out.println(s.length);
     return  "" ;
  }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var  array= new  Array();
array.push(1);
array.push(2);
array.push(3);
array.push(4);
array.push(5);
$.ajax({
     url: "request/array" ,
     type: "post" ,
     dataType: "json" ,
     data:JSON.stringify(array),
     dataType: "json" ,
     contentType: "application/json" ,
     success: function (data){
     },error: function (data){
     }
});

和上面的方法類似,注意contentType:"application/json",否則同樣的415錯誤。


下面的方法是restful中的路徑變量,支持get,post,delete等,如:xxx/1,xxx/2這種方式,經測試,這個方法的奇葩之處在於"xxx/5,4"以及"xxx/[5,4]"的效果是一樣的,看代碼:

1
2
3
4
5
6
7
8
9
10
11
/**
* 這個比較奇葩,來自一位朋友的寫法,即.xxx/5,4這樣的請求,SpringMVC竟然也是支持的
* @param id
* @return
*/
@ResponseBody
@RequestMapping (value= "array/{id}" ,method=RequestMethod.GET)
public  String array2( @PathVariable ( "id" )Long[] id){
        System.out.println(id.length);
        return  "array length:" +id.length+ "" ;
}

可以直接將后面的路徑變量,轉換成相應的數組。可以在瀏覽器輸入:http://localhost:8080/springmvc-param/request/array/5,4,3,2,1或者http://localhost:8080/springmvc-param/request/array/[5,4,3,2,1],都可以轉換成數組。


如果一個表單對應多個實體類,恰好這些類中具有相同的屬性,這時候SpringMVC就犯難了,我們要做的是讓SpringMVC明白我們在給誰賦值。

支持post,get,put

如下,A,B,C,其中C中包含了A和B兩個成員變量

1
2
3
public  class  A {
        private  String x;
}
1
2
3
public  class  B {
        private  String x;
}
1
2
3
4
public  class  C {
        private  A a;
        private  B b;
}

Controller如下

1
2
3
4
5
6
7
8
9
10
11
/**
* 一個表單對應多個Bean對象,這些Bean中有相同的屬性,那么需要在分裝他們的一個整體的對象
* 使之支持object.property的表達式
* @param c
*/
@ResponseBody
@RequestMapping ( "complex" )
public  void  complexObject(C c){
        System.out.println(c.getA().getX());
        System.out.println(c.getB().getX());
}

HTML如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
< form  action = "request/complex"  method = "POST"  style = "border:1px solid red;" >
       < table >
              < tr >
                  < td >A對象:</ td >
                  < td >< input  type = "text"  name = "a.x"  value = "xxx" ></ td >
               </ tr >
               < tr >
                   < td >B對象:</ td >
                   < td >< input  type = "text"  name = "b.x"  value = "yyy" >< br ></ td >
               </ tr >
               < tr >
                   < td  colspan = "2"  style = "text-align: right;" >
                      < input  type = "submit"  value = "提交" >
                   </ td >
               </ tr >
         </ table >
</ form >

通過object.property即可指定給誰賦值。


 

另外一個是關於Session取值的

代碼如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Controller
@SessionAttributes (value= "user" )
@RequestMapping ( "/session" )
public  class  SessionController {
     @RequestMapping (method=RequestMethod.GET)     
     public  String setUser(ModelMap map){ 
         User user= new  User(); 
         user.setAddress( "xxx" ); 
         user.setUserName( "yyy" );
         map.put( "user" , user);
         return  "request/userForm" ;
     }
                
     @ResponseBody
     @RequestMapping (value= "getUser" ,method=RequestMethod.GET)
     public  String getUser( @ModelAttribute ( "user" )User user){
            System.out.println(user.getUserName());
            return  user.getUserName();
     }
}

在Controller上加上注解@SessionAttributes(value="user"),再使用ModelMap的put方法(非addAttribute方法),然后在getUser方法中,使用@ModelAttribute("user")即可取得session中的user對象

 


Maven依賴:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
< properties >
             < springframework >4.0.5.RELEASE</ springframework >
             < servlet >3.1.0</ servlet >
             < jstl >1.2</ jstl >
             < xstream >1.4.7</ xstream >
             < commons-fileupload >1.3.1</ commons-fileupload >
             < jackson >1.9.13</ jackson >
</ properties >
< dependencies >
             <!-- jackson json解析支持 -->
             < dependency >
                         < groupId >org.codehaus.jackson</ groupId >
                         < artifactId >jackson-mapper-asl</ artifactId >
                         < version >${jackson}</ version >
             </ dependency >
             <!-- Spring web mvc -->
             < dependency >
                         < groupId >org.springframework</ groupId >
                         < artifactId >spring-webmvc</ artifactId >
                         < version >${springframework}</ version >
             </ dependency >
             <!-- servlet -->
             < dependency >
                         < groupId >javax.servlet</ groupId >
                         < artifactId >javax.servlet-api</ artifactId >
                         < version >${servlet}</ version >
             </ dependency >
             <!-- JSTL -->
             < dependency >
                         < groupId >jstl</ groupId >
                         < artifactId >jstl</ artifactId >
                         < version >${jstl}</ version >
             </ dependency >
             <!--xml解析支持 -->
             < dependency >
                         < groupId >com.thoughtworks.xstream</ groupId >
                         < artifactId >xstream</ artifactId >
                         < version >${xstream}</ version >
             </ dependency >
</ dependencies >

Spring配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
@EnableWebMvc // 啟用SpringMVC
@ComponentScan (basePackages =  "org.xdemo.example.springmvc" ) // 配置包掃描路徑
@Configuration // 啟用注解式配置
//繼承WebMvcConfigurerAdapter可以是我們可以重寫一些資源或者一些處理器
public  class  AppConfig  extends  WebMvcConfigurerAdapter {
                /**
                 * 設置資源路徑
                 */
                @Override
                public  void  addResourceHandlers(ResourceHandlerRegistry registry) {
                       registry.addResourceHandler( "/resources/**" ).addResourceLocations( "/resources/" ).setCachePeriod( 31556926 );
                }
                /**
                 * 設置默認的Servlet請求處理器
                 */
                @Override
                public  void  configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
                       configurer.enable();
                }
                /**
                 * 設置視圖解析器,以及頁面路徑
                
                 * @return
                 */
                @Bean
                public  InternalResourceViewResolver getInternalResourceViewResolver() {
                                InternalResourceViewResolver resolver =  new  InternalResourceViewResolver();
                                resolver.setPrefix( "/WEB-INF/views/" );
                                resolver.setSuffix( ".jsp" );
                                return  resolver;
                }
                
                /**
                 * 配置消息轉換器
                 */
                @Override
                public  void  configureMessageConverters(
                       List<HttpMessageConverter<?>> converters) {converters.add(converter());
                                
                }
                
                /**
                 * JSON格式的支持,這個很重要,只有加上這個JSON的消息轉換器,才能夠支持JSON格式數據的綁定
                 * @return
                 */
                @Bean
                public  MappingJacksonHttpMessageConverter converter() {
                               MappingJacksonHttpMessageConverter converter =  new  MappingJacksonHttpMessageConverter();
                                return  converter;
                }
}

轉載請注明來源:http://www.xdemo.org/springmvc-data-bind/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM