1. 程式人生 > >springMVC中關於引數傳遞的問題

springMVC中關於引數傳遞的問題

有這麼一個jsp頁面

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="java.util.*" isELIgnored="false"%>
 
<form action="addProduct">
 
    產品名稱 :<input type="text" name="name" value=""><br />
    產品價格: <input type="text" name="price" value=""><br />
 
    <input type="submit" value="增加商品">
</form>
有這一個pojo類
package pojo;
 
public class Product {
 
    private int id;
    private String name;
    private float price;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public float getPrice() {
        return price;
    }
    public void setPrice(float price) {
        this.price = price;
    }
     
}
對應的控制器為
package controller;
 
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 pojo.Product;
 
@Controller
public class ProductController {
 
    @RequestMapping("/addProduct")
    public ModelAndView add(Product product) throws Exception {
        ModelAndView mav = new ModelAndView("showProduct");
        return mav;
    }
}
最後是展示用的jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" isELIgnored="false"%>
 
產品名稱: ${product.name}<br>
產品價格: ${product.price}

問題1

為什麼第一個jsp頁面中傳遞引數只是pojo類Product的的屬性即可,而不用寫成product.name這種形式?

分析:

這應該是springMVC的一個特點,name和price屬性會賦值給add方法的product引數物件,稍後也會討論當有多個物件具有相同的屬性時該怎麼處理。

問題2
第二個jsp頁面${product} 這個 product 到底是哪兒來的?
分析:
 引數product會預設被當做值加入到ModelAndView 中,相當於:

mav.addObject("product",product);

絕大部分疑問都是圍繞 ${product} 這個 product 到底是哪兒來的,看了站長的回答,其實是有些問題的。
我自己一開始也是一臉懵逼的,經過多次實驗以及google,給大家講一下吧:
大家應該都知道,EL 表示式中的引數應該是來自於 addObject("abc",xxx) 中的第一個引數 abc
站長說的半對半錯,他告訴你們引數 product 會預設被當做值加入到 ModelAndView 中
但是沒有說,這只是 addObject() 第二個引數的來歷,有疑問的其實更關心第一個引數,也就是我們 EL 表示式中要用到的這個 "product" 從何而來:)
一句話,大家就能明白:
add()方法的【引數型別】會自動轉小駝峰並加入到 ModelAndView 中作為 addObject() 的【第一個引數】,相當於 addObject("theFirstParam", product);
綜上:addObject 裡第一個引數是根據 add() 的引數型別自動轉成小駝峰命名,第二個引數是 add() 的引數名。
區分命名,舉個極端的栗子就明白了,這裡程式碼看的不爽點上面【程式碼】到那裡看
bean:
public class MyFuckingProduct {...};


controller:
public ModelAndView add(MyFuckingProduct 隨便寫我寫中文應該沒人發現吧) {...}

jsp:
${myFuckingProduct.xxx}

跑一下,bingo!

大家注意 add() 方法的引數,引數名是什麼根本不用管,瞎寫一通 fhdhdfai2u3y,沒有關係,因為預設的 addObject()方法第一個引數只跟你的引數型別有關係,第二個引數就是你瞎寫的引數名。
相當於:addObject("myFuckingProduct", 隨便寫我寫中文應該沒人發現吧);
然後 EL 表示式寫什麼就很明瞭了。

4種方法讓SpringMVC接收多個物件(以下內容來自百度)

問題背景: 
我要在一個表單裡同時一次性提交多名乘客的個人資訊到SpringMVC,前端HTML和SpringMVC Controller裡該如何處理?

  • 第1種方法:表單提交,以欄位陣列接收;
  • 第2種方法:表單提交,以BeanListModel接收;
  • 第3種方法:將Json物件序列化成Json字串提交,以List接收;
  • 第4種方法:將表單物件序列化成Json字串提交,以List接收; 
    第4種方法其實是第3種方法的升級,就是將表單轉成Json物件,再轉成Json字串提交; 
    然而,第4種方法還不支援含有多選控制元件表單的提交,故應該還有第5種加強版的方法。

以上4種方法都共用同一個User實體類,程式碼如下:

public class User {

    private Integer id;
    private String name;
    private String pwd;

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
    // .......後面還有getter、setter方法,省略了
 }

第1種方法:表單提交,以欄位陣列接收 
HTML程式碼如下:

    <form action="/user/submitUserList_1" method="post">
        ID:<input type="text" name="id"><br/>
        Username:<input type="text" name="name"><br/>
        Password:<input type="text" name="pwd"><br/><br/>

        ID:<input type="text" name="id"><br/>
        Username:<input type="text" name="name"><br/>
        Password:<input type="text" name="pwd"><br/><br/>
        <input type="submit" value="submit">
    </form>

Java程式碼如下:

    @RequestMapping(value = "/submitUserList_1", method ={RequestMethod.POST})
    @ResponseBody
    public String submitUserList_1(HttpServletResponse response,Integer[] id, String[] name, String[] pwd)
                            throws Exception{
        String result = "";
        if(id == null || id.length <= 0){ return "No any ID.中文"; }
        List<User> userList = new ArrayList<User>();
        for (int i = 0; i < id.length; i++ ) {
            User user = new User();
            user.setId(id[i]);
            user.setName(name[i]);
            user.setPwd(pwd[i]);
            userList.add(user);
        }
        result = this.showUserList(userList);
        return result;
    }

第2種方法:表單提交,以BeanListModel接收 
HTML程式碼如下:

    <form action="/user/submitUserList_2" method="post">
        ID:<input type="text" name="users[0].id"><br/>
        Username:<input type="text" name="users[0].name"><br/>
        Password:<input type="text" name="users[0].pwd"><br/><br/>

        ID:<input type="text" name="users[2].id"><br/>
        Username:<input type="text" name="users[2].name"><br/>
        Password:<input type="text" name="users[2].pwd"><br/><br/>
        <input type="submit" value="Submit">
    </form>

Java程式碼: 
除了剛才公用的User類,還要封裝一個User的容器類UserModel:

public class UserModel {
    private List<User> users;

    public List<User> getUsers() {
        return users;
    }

    public void setUsers(List<User> users) {
        this.users = users;
    }

    public UserModel(List<User> users) {
        super();
        this.users = users;
    }

    public UserModel() {
        super();
    }

}

SpringMVC Controller方法:

    @RequestMapping(value = "/submitUserList_2", method ={RequestMethod.POST})
    @ResponseBody
    public String submitUserList_2(UserModel users)
            throws Exception{
        String result = "";
        List<User> userList = users.getUsers();
        if(userList == null || userList.size() <= 0){ return "No any ID.中文"; }
        result = this.showUserList(userList);
        return result;
    }

第3種方法:將Json物件序列化成Json字串提交,以List接收 
HTML程式碼:

<head>
    <title>submitUserList_3</title>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    <script language="JavaScript" src="/js/jquery.min.js" ></script>
    <script language="JavaScript" src="/js/jquery.json.min.js" ></script>
    <script type="text/javascript" language="JavaScript">
        function submitUserList_3() {alert("ok");
            var customerArray = new Array();
            customerArray.push({id: "1", name: "李四", pwd: "123"});
            customerArray.push({id: "2", name: "張三", pwd: "332"});
            $.ajax({
                url: "/user/submitUserList_3",
                type: "POST",
                contentType : 'application/json;charset=utf-8', //設定請求頭資訊
                dataType:"json",
                //data: JSON.stringify(customerArray),    //將Json物件序列化成Json字串,JSON.stringify()原生態方法
                data: $.toJSON(customerArray),            //將Json物件序列化成Json字串,toJSON()需要引用jquery.json.min.js
                success: function(data){
                    alert(data);
                },
                error: function(res){
                    alert(res.responseText);
                }
            });
        }
    </script>
</head>

<body>
    <h1>submitUserList_3</h1>
    <input id="submit" type="button" value="Submit" onclick="submitUserList_3();">
</body>

Java程式碼:

    @RequestMapping(value = "/submitUserList_3", method ={RequestMethod.POST})
    @ResponseBody
    public String submitUserList_3(@RequestBody List<User> users)
            throws Exception{
        String result = "";
        if(users == null || users.size() <= 0){ return "No any ID.中文"; }
        result = this.showUserList(users);
        return result;
    }

第4種方法:將表單物件序列化成Json字串提交,以List接收 
HTML程式碼:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
        "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <title>submitUserList_4</title>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    <script language="JavaScript" src="/js/jquery.min.js" ></script>
    <script type="text/javascript" language="JavaScript">
        //將表單序列化成json格式的資料(但不適用於含有控制元件的表單,例如複選框、多選的select)
        (function($){
            $.fn.serializeJson = function(){
                var jsonData1 = {};
                var serializeArray = this.serializeArray();
                // 先轉換成{"id": ["12","14"], "name": ["aaa","bbb"], "pwd":["pwd1","pwd2"]}這種形式
                $(serializeArray).each(function () {
                    if (jsonData1[this.name]) {
                        if ($.isArray(jsonData1[this.name])) {
                            jsonData1[this.name].push(this.value);
                        } else {
                            jsonData1[this.name] = [jsonData1[this.name], this.value];
                        }
                    } else {
                        jsonData1[this.name] = this.value;
                    }
                });
                // 再轉成[{"id": "12", "name": "aaa", "pwd":"pwd1"},{"id": "14", "name": "bb", "pwd":"pwd2"}]的形式
                var vCount = 0;
                // 計算json內部的陣列最大長度
                for(var item in jsonData1){
                    var tmp = $.isArray(jsonData1[item]) ? jsonData1[item].length : 1;
                    vCount = (tmp > vCount) ? tmp : vCount;
                }

                if(vCount > 1) {
                    var jsonData2 = new Array();
                    for(var i = 0; i < vCount; i++){
                        var jsonObj = {};
                        for(var item in jsonData1) {
                            jsonObj[item] = jsonData1[item][i];
                        }
                        jsonData2.push(jsonObj);
                    }
                    return JSON.stringify(jsonData2);
                }else{
                    return "[" + JSON.stringify(jsonData1) + "]";
                }
            };
        })(jQuery);

        function submitUserList_4() {alert("ok");
            var jsonStr = $("#form1").serializeJson();
            //console.log("jsonStr:\r\n" + jsonStr);
            //alert(jsonStr);
            $.ajax({
                url: "/user/submitUserList_4",
                type: "POST",
                contentType : 'application/json;charset=utf-8', //設定請求頭資訊
                dataType:"json",
                data: jsonStr,
                success: function(data){
                    alert(data);
                },
                error: function(res){
                    alert(res.responseText);
                }
            });
        }
    </script>
</head>

<body>
    <h1>submitUserList_4</h1>
    <form id="form1">
        ID:<input type="text" name="id"><br/>
        Username:<input type="text" name="name"><br/>
        Password:<input type="text" name="pwd"><br/><br/>

        ID:<input type="text" name="id"><br/>
        Username:<input type="text" name="name"><br/>
        Password:<input type="text" name="pwd"><br/><br/>
        <input type="button" value="submit" onclick="submitUserList_4();">
    </form>
</body>
</html>

Java程式碼:

    @RequestMapping(value = "/submitUserList_4", method ={RequestMethod.POST})
    @ResponseBody
    public String submitUserList_4(@RequestBody List<User> users)
            throws Exception{
        String result = "";
        if(users == null || users.size() <= 0){ return "No any ID.中文"; }
        result = this.showUserList(users);
        return result;
    }

總結: 
第1、2種方法其實都有一個共同的BUG:假如提交三條記錄時,前面兩條記錄的某些欄位不填值的話,在SpringMVC裡接收不準確了。而且,每2種方法在HMTL中需要給name屬性新增[下標],如果下標有跨度的話(比如第一組控制元件下標是0,第二組下標是2),那麼SpringMVC裡其實的是0到2三個物件的,預設下標是1的那個物件全為null值。 
第3、4種方法最實用。