SpringMVC參數綁定-入門用法總結

開篇引言

前面已經寫過 SSM 三大框架的一些入門文章,在 SpringMVC 部分,關於參數的綁定提的不是太多,從新整理了一下,就當作一個補充,時間匆匆,可能會有一些錯誤,你們能夠共同交流,一塊兒探討!javascript

注:下面的文章,重點仍是參數綁定的使用,關於導包或者一些註解的講解,我沒有多說,以前的文章一些經常使用的也都還介紹過,若是有必要,我再整理一篇關於註解的總結也能夠哈 ~php

【萬字長文】Spring MVC 層層遞進輕鬆入門 !html

juejin.im/post/5e781c…前端

(一) 基本類型、包裝類型參數綁定

咱們假定要請求的參數爲 age ,那麼咱們有兩種選擇 :即 ① 傳入基本類型 int ② 傳入包裝類型 Integer ,咱們這一塊的講解,就用它們兩個來說解java

注:咱們將重心放在參數綁定上,項目名或者Controller上的@RequestMapping註解,我都沒加ajax

(1) 基本類型 int

@RequestMapping("baseType.do")
@ResponseBody
public String baseType(int age) {
    return "age:" + age;
}
複製代碼

http://localhost:8080/baseType.do?age=30spring

當咱們請求時,返回結果:age:30json

  • 這種狀況下,首先 key 值必須傳入,不然會報 500 錯誤,提示當前 age 不能爲空
  • 其次,參數只能爲 int 類型,不然報 400 參數異常錯誤

這裏有一個問題須要提一下,你們應該知道一個註解 @RequestParam ,咱們是否可經過這個註解的 required 屬性,幫助咱們規避這個請求參數爲空的問題呢?後端

答案是否認的,雖然這個註解設置 required = false 後不傳值後臺也不會報錯,可是若是其中指定了基本數據類型,例如咱們代碼中的 int 這個時候若是不傳值是依舊會報一個 500 錯誤數組

由於其不傳值就賦 null,可是 int 類型卻不能爲null

因此想要規避這個參數爲空的問題,咱們就能夠選擇包裝類型 Integer

(2) 包裝類型

@RequestMapping("packingType.do")
@ResponseBody
public String packingType(Integer age) {
    return "age:" + age;
}
複製代碼

http://localhost:8080/packingType.do?age=30

正常返回:age:30

http://localhost:8080/packingType.do

http://localhost:8080/packingType.do?

http://localhost:8080/packingType.do?=

參數爲空不報錯,均返回:age:null

  • 能夠不傳 key,後臺接收到的數據則爲 age=null
  • 因此開發中,對於參數可能爲空的數據,建議使用包裝類型
  • 固然,咱們也可使用 @RequestParam 註解 來設置是否請求中必須包含該參數,此註解默認就是必須傳參,不然報錯

(二) 對象的參數綁定

(1) 多層級對象的綁定

什麼是多層級對象,先別急,先看一個最基礎的例子

咱們首先建立一個用戶類

public class User {
    private String id;
    private String name;
	......補充其 get set toString 方法
}
複製代碼

直接在參數中寫上對應 User 類型就能夠了

@RequestMapping("objectType.do")
@ResponseBody
public String objectType(User user) {
    return user.toString();
}
複製代碼

http://localhost:8080/objectType.do?id=001&name=Steven

返回結果:User{uid='001', name='Steven'}

若是這個時候,我建立一個新的類 UserDetails

public class UserDetails {
    private Integer age;
    private String address;
    ......補充其 get set toString 方法
}
複製代碼

在 User 類中引入這個類,這種狀況又該如何綁定參數呢

public class User {
    private String id;
    private String name;
    
    private UserDetails userDetails;
    
    ......補充其 get set toString 方法
}
複製代碼

http://localhost:8080/objectType.do?id=1&name=Steven&userDetails.age=20&userDetails.address=BeiJing

返回結果:User{uid='1', name='Steven', userDetails=UserDetails{age=20, address='BeiJing'}}

  • 對於引入的對象成員復賦值,格式就例如:userDetails.address=xxxxx
  • 這裏地址我沒用中文,是由於我是直接返回的,沒通過編碼的處理,否則會顯示 ? ?

(2) 同屬性對象參數綁定

若是咱們想要直接接收兩個對象,有時候免不了有相同的成員,例如咱們的 User 和 Student 類中均含有

Integer id 、String name 兩個成員,咱們試着請求一下

@RequestMapping("objectType2.do")
@ResponseBody
public String objectType2(User user, Student student) {
    return user.toString() + " " + student.toString();
}
複製代碼

http://localhost:8080/objectType2.do?id=8&name=Steven

返回結果:User{id='8', name='Steven'} Student{id='8', name='Steven'}

能夠看到,兩個對象的值都被賦上了,可是,大部分狀況下,不一樣的對象的值通常都是不一樣的,爲此,咱們還有解決辦法

@InitBinder 註解能夠幫助咱們分開綁定,下面的代碼也就是說分別給 user、student 指定一個前綴

@InitBinder("user")
public void initUser(WebDataBinder binder) {
    binder.setFieldDefaultPrefix("user.");
}

@InitBinder("student")
public void initStudent(WebDataBinder binder) {
    binder.setFieldDefaultPrefix("stu.");
}
複製代碼

http://localhost:8080/objectType2.do?user.id=1&name=Steven&stu.id=002

當發起這樣一個請求後,咱們分別指定了 user 和 student 的 id 值,而 name 則是一樣的 Steven

返回結果:User{id='1', name='Steven', userDetails=null} Student{id='2', name='Steven'}

(三) 數組類型參數綁定

@RequestMapping("arrayType.do")
@ResponseBody
public String arrayType(String[] nickname) {
    StringBuilder sb = new StringBuilder();
    for (String s : nickname) {
        sb.append(s).append(", ");
    }
    return sb.toString();
}
複製代碼

http://localhost:8080/arrayType.do?nickname=Jack&nickname=Steven&nickname=Tom

返回結果:Jack, Steven, Tom,

(四) 集合類型參數綁定

(1) List 類型

集合是不能直接進行參數綁定的,因此咱們須要建立出一個類,而後在類中進行對 List 的參數綁定

首先建立 UserList 類,其中我爲了演示,只放了 private List<User> users 補充好 get set toString 方法

控制層方法中,參數就是這個建立出來的類

@RequestMapping("listType.do")
@ResponseBody
public String listType(UserList userList) {
    return userList.toString();
}
複製代碼

http://localhost:8080/listType.do?users[0].id=1&users[0].name=Jack&users[1].id=2&users[1].name=Marry

咱們的請求,分別將兩個user信息存入了 List<User> users

特別注意:若是你的 Tomcat 版本是 7.0 左右 那麼上述請求是沒問題的,可是若是版本比較高,例如我自己所用的 Tomcat 8.5 ,若是執行上述請求就會報 400 錯誤

HTTP Status 400 – Bad Request

Message Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986

這是由於Tomcat高的版本地址中不能使用「[」和「]」 ,咱們能夠將其換成對應的16進制,即 「[」 換成 %5B,「]」 換成 %5D

http://localhost:8080/listType.do?users%5B0%5D.id=1&users%5B0%5D.name=Jack&users%5B1%5D.id=2&users%5B1%5D.name=Marry

或者直接用 post 請求也是能夠的哈

(2) Map 類型

map 類型是同樣的套路,咱們先建立一個 UserMap類,而後在其中聲明 private Map<String,User> users 進而綁定參數

@RequestMapping("mapType.do")
@ResponseBody
public String mapType(UserMap userMap) {
    return userMap.toString();
}
複製代碼

http://localhost:8080/mapType.do?users['userA'].id=1&users['userA'].name=Jack&users['userB'].id=2&users['userB'].name=Tom

一樣 「[]」 會遇到上面的錯誤,因此若是想要在地址欄請求訪問,就須要替換字符,或者發起一個 post 請求

http://localhost:8080/mapType.do?users%5B%27userA%27%5D.id=1&users%5B%27userA%27%5D.name=Jack&users%5B%27userB%27%5D.id=2&users%5B%27userB%27%5D.name=Tom

返回結果:UserMap{users={userA=User{id='1', name='Jack'}, userB=User{id='2', name='Tom'}}}

(五) JSON 參數綁定

除了前面表單等提交的方式,咱們還有一種ajax的提交方式,經常用來向後端傳遞以及接受 json 格式的數據,關於 json 字符串和對象之間的轉換會用到下面的 jar包

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.10.0</version>
</dependency>

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-core</artifactId>
  <version>2.10.0</version>
</dependency>

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-annotations</artifactId>
  <version>2.10.0</version>
</dependency>
複製代碼

這一塊的演示,咱們建立一個 Admin 實體類

public class Admin {
    private Integer id;
    private String name;
    ......補充其 get set toString 方法
}
複製代碼

(1) 實體參數綁定

當 ajax 傳遞的參數不少的時候,使用參數名匹配,會很是麻煩,若是請求的參數在後臺中有一個匹配的實體類,咱們就能夠選擇前臺傳一個 json 到後臺,後臺使用匹配的實體類進行接收

提交 JSON: {"id": "37","name": "張三"}

$(function () {
	$("#btn").click(function () {
		//發送ajax請求
        $.ajax({
            url:"ajaxType1.do",
            contentType:"application/json",
            data:'{"id":"37","name":"張三"}',
            dataType:"json",
            type:"post",
            success:function (data) {
            //解析響應數據
            alert(data.id);
            alert(data.name);
            }
     	})
    });
});
複製代碼

Contoller

//用實體接參數
@RequestMapping("ajaxType1.do")
@ResponseBody
public Admin ajaxType1(@RequestBody Admin admin) {
    System.out.println(admin.toString());
    admin.setName("測試管理員");
    return admin;
}
複製代碼

後端參數中的 admin 就會被綁定好參數,供開發者使用

@RequestBody 註解經常使用來處理 content-type不是默認的application/x-www-form-urlcoded編碼的內容,說常處理application/json類型

(2) Map 參數綁定

還有一種狀況,那就是請求的參數仍然挺多,可是後臺也沒有一個合適的實體進行匹配,咱們也能夠考慮使用map來接收

依舊提交 JSON: {"id": "37","name": "張三"}

$(function () {
	$("#btn").click(function () {
		//發送ajax請求
        $.ajax({
            url:"ajaxType1.do",
            contentType:"application/json",
            data:'{"id":"37","name":"張三"}',
            dataType:"json",
            type:"post",
            success:function (data) {
            //解析響應數據
            alert(data.id);
            alert(data.name);
            }
     	})
    });
});
複製代碼

可是 Controller 中咱們使用 map 來進行接收,而後簡單給了一個實例,將map值封裝到 Admin 對象中,而後返回到前端去

@RequestMapping("ajaxType3.do")
@ResponseBody
public Admin ajaxType3(@RequestBody Map<String, String> map) {
    Integer id = null;
    String name = null;

    if (map.containsKey("id")){
        id = Integer.parseInt(map.get("id"));
    }
    if (map.containsKey("name")){
        name = map.get("name");
    }

    Admin admin = new Admin();
    admin.setId(id);
    admin.setName(name);
    return admin;
}
複製代碼

(3) List 參數綁定

一樣的,咱們還可使用 list 方式進行接收,它時以 json 數組的形式傳遞的

var listType=[];
var admin={};
admin.id=1;
admin.name='湯姆';
listType.push(admin);

var admin2={};
admin2.id=2;
admin2.name='傑克';
listType.push(admin2);

$(function () {
	$("#btn").click(function () {
		//發送ajax請求
        $.ajax({
            url:"ajaxType1.do",
            contentType:"application/json",
            data:JSON.stringify(listType),
            dataType:"json",
            type:"post",
            success:function (data) {
            //解析響應數據
            alert(data.id);
            alert(data.name);
            }
     	})
    });
});
複製代碼

去後臺看一下

@RequestMapping("ajaxType5.do")
@ResponseBody
public void ajaxType5(@RequestBody List<Admin> list) {

    System.out.println(list);

    for (Admin admin : list){
        System.out.println(admin.getId() + " " + admin.getName());
    }

}
複製代碼

看一下控制檯的輸出:

[Admin{id='1', name='湯姆'}, Admin{id='2', name='傑克'}]
1 湯姆
2 傑克
複製代碼

(4) 補充

這是用來提交的表單

<form id="ajaxForm" method="post">
    id:<input type="text" name="id">
    name:<input type="text" name="name">
</form>
複製代碼

這是 ajax請求,咱們也經常使用$("#ajaxForm").serialize() 進行一個表單的序列化,而後提交,可是它只是將Form序列化拼接成了簡單的字符串,並非JSON格式,它是例如這樣的:

id=111&name=Steven
複製代碼

因此剛纔所說的json那一套就無論用了

$(function () {
	$("#btn").click(function () {
		//發送ajax請求
        $.ajax({
            url:"ajaxType1.do",
            contentType:"application/json",
            data:$("#ajaxForm").serialize(),
            dataType:"json",
            type:"post",
            success:function (data) {
            //解析響應數據
            alert(data.id);
            alert(data.name);
            }
     	})
    });
});
複製代碼

若是想要使用序列化,同時還想要傳遞 json 格式到後臺,也不是沒辦法

咱們須要添加一個方法

$.fn.serializeObject = function() {
	var o = {};
    var a = this.serializeArray();
    $.each(a, function() {
    	if (o[this.name]) {
         	if (!o[this.name].push) {
            	o[this.name] = [o[this.name]];
             }
         	o[this.name].push(this.value || '');
         } else {
         	o[this.name] = this.value || '';
         }
    });
    return o;
};
複製代碼

同時將下面 ajax 中的 data修改成

data:JSON.stringify($("#ajaxForm").serializeObject()),
複製代碼

後臺就能獲取到 json 格式了

{"id":"111","name":"Steven"}
複製代碼

(六) XML 參數綁定

後臺很是簡單,和前面沒什麼區別,咱們須要在實體中進行一些操做

@RequestMapping("xmlType.do")
@ResponseBody
public String xmlType(@RequestBody Student student) {
    return student.toString();
}
複製代碼

這種狀況下,咱們須要藉助一個jar包 —— spring-oxm,本身能夠導入一下

而後咱們須要在接受的實體那裏,添加 @XmlRootElement 和 @XmlElement 註解,來表明根節點和子節點

package cn.ideal.Object;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "student")
public class Student {
    private Integer id;
    private String name;

    @XmlElement(name = "id")
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    @XmlElement(name = "name")
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                '}';
    }
}

複製代碼

例如咱們xml爲

<?xml version="1.0" encoding="UTF-8" ?>
<student>
	<id>66</id>
	<name>Steven</name>
</student>
複製代碼

而後發起請求,注意將Content-Type 改成 application/xml

返回的結果:Student{id='66', name='Steven'}

(七) 結尾

若是文章中有什麼不足,歡迎你們留言交流,感謝朋友們的支持!

若是能幫到你的話,那就來關注我吧!若是您更喜歡微信文章的閱讀方式,能夠關注個人公衆號

在這裏的咱們素不相識,卻都在爲了本身的夢而努力 ❤

一個堅持推送原創開發技術文章的公衆號:理想二旬不止

相關文章
相關標籤/搜索