SpringMVC中用於綁定請求數據的註解以及配置視圖解析器
在上一篇文章中我們簡單介紹了@RequestMapping與@RequestParam註解,知道了如何去配置地址映射,本篇則介紹一些用於處理request數據的註解。
1.@RequestHeader註解,該註解用於處理request中的header部分,也就是http請求頭的部分,它可以把header部分的值綁定到方法的參數上,示例:
package org.zero01.test; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping("/test") public class Test { @RequestMapping("test.do") public void method( @RequestHeader("Host") String host, @RequestHeader("Content-Type") String contentType ){ System.out.println(host); System.out.println(contentType); } }
使用Postman進行訪問,訪問方式如下:
控制臺打印結果:
localhost:8080
application/json
從打印結果可以看到,以上的代碼把http請求頭中的Host以及Content-Type字段的值,都綁定到了註解配置的方法參數上,這就是@RequestHeader註解的作用。
2.@CookieValue註解,該註解用於把http請求頭中關於cookie的值綁定到方法的參數上,示例:
package org.zero01.test; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.CookieValue; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping("/test") public class Test { @RequestMapping("test.do") public void method( @CookieValue("JSEESIONID") String cookie ){ System.out.println(cookie); } }
使用Postman進行訪問,訪問方式如下:
控制臺打印結果:
415A4AC178C59DACE0B2C9CA727CDD84
如上,@CookieValue註解幫我們把Cookie裏JSEESIONID的值綁定到了該方法的參數中。
3.@PathVariable註解, 該註解可以把@RequestMapping註解中配置的URL占位符映射的值,綁定到相應的方法參數上,示例:
package org.zero01.test; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping("/test") public class Test { // 將URL上映射的值綁定到方法參數上,用 {} 來進行綁定 @RequestMapping("test.do/{typeid}/{id}") public void method( @PathVariable String typeid, @PathVariable String id ) { System.out.println(typeid); System.out.println(id); } }
使用Postman進行訪問,訪問方式如下:
控制臺打印結果:
8451
25
4.@RequestBody註解,該註解常用來處理application/json, application/xml等數據,也就是用於處理http請求體的內容。通過這個註解可以很輕松的獲取到請求體的數據,再也不用像使用Servlet時那樣通過流去讀了,示例:
package org.zero01.test;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@Controller
@RequestMapping("/test")
public class Test {
@RequestMapping("/test.do")
public void method(
@RequestBody String json
) {
System.out.println(json);
}
}
使用Postman進行訪問,訪問方式如下:
控制臺打印結果:
{
"name" : "Jon",
"age" : 23,
"address" : "usa"
}
5.@SessionAttributes註解,該註解用來將方法參數中的值綁定到HttpSession的attribute中,這個註解是寫在類上的,示例:
package org.zero01.test;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@Controller
@SessionAttributes("name")
@RequestMapping("/test")
public class Test {
@RequestMapping("/test.do")
public void method(Map<String, Object> map) {
// 由於@SessionAttributes註解的作用,這對鍵值會被存儲一份到HttpSession對象的attribute中
map.put("name", "Jon");
}
}
該註解有value、types兩個屬性,可以通過名字和類型來指定需要存儲到HttpSession中的數據;示例:
package org.zero01.test;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@Controller
@SessionAttributes(value = "name", types = Object.class)
@RequestMapping("/test")
public class Test {
@RequestMapping("/test.do")
public void method(Map<String, Object> map) {
// 由於@SessionAttributes註解的作用,這對鍵值會被存儲一份到HttpSession對象的attribute中
map.put("name", "Jon");
}
}
6.@SessionAttribute註解,該註解用來訪問預先存在的HttpSession中的屬性值,例如HttpSession中存儲了一個name的值,通過@SessionAttribute註解可以取出這個name的值,並且可以綁定到方法的參數上,所以這個註解是寫在方法參數上的,示例:
package org.zero01.test;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@Controller
@RequestMapping("/test")
public class Test {
@RequestMapping("/test.do")
// 拿出HttpSession中鍵為name的值,綁定到方法參數name上
public void method(@SessionAttribute("name") String name) {
}
}
7.@ModelAttribute註解,該註解有兩個用法,一個是用於方法上,一個是用於參數上:
- 用於方法上時: 通常用來在處理@RequestMapping之前,為請求綁定需要從後臺查詢的model;
- 用於參數上時: 用來通過名稱對應,把相應名稱的值綁定到註解的參數bean上;要綁定的值來源於:
- @SessionAttributes 啟用的attribute 對象上;
- @ModelAttribute 用於方法上時指定的model對象;
- 上述兩種情況都沒有時,new一個需要綁定的bean對象,然後把request中按名稱對應的方式把值綁定到bean中。
用在方法上的示例代碼:
package org.zero01.test;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@Controller
@RequestMapping("/test")
public class Test {
@ModelAttribute
@RequestMapping("/test.do")
public Account method(@RequestParam String number) {
return accountManager.findAccount(number);
}
}
用在參數上的示例代碼:
package org.zero01.test;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@Controller
@RequestMapping("/test")
public class Test {
@RequestMapping("/test.do")
public void method(@ModelAttribute String name) {
}
}
獲得HttpRequest以及HTTPResponse對象
在控制器中要想獲得HttpRequest以及HTTPResponse對象很簡單,直接在方法上聲明這兩個對象的參數即可,示例:
package org.zero01.test;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Controller
@RequestMapping("/test")
public class Test {
@RequestMapping("/test.do")
public void method(HttpServletRequest request, HttpServletResponse response) {
System.out.println(request.getRequestURI());
System.out.println(response.getStatus());
}
}
使用Postman進行訪問,訪問方式如下:
控制臺打印結果:
/test/test.do
200
把url參數封裝到對象的屬性裏
通常url上會帶有好幾個參數,我們希望把這些參數都封裝到某個對象的屬性裏,這樣就不需要在方法上聲明多個參數了,只需要聲明一個對象即可。而SpringMVC可以自動幫我們完成這個事情,我們只需要創建一個封裝類即可。例如我這裏創建一個Student類,裏面封裝了與URL參數對應的屬性:
Student類代碼如下:
package org.zero01.test;
public class Student {
private String sname;
private int age;
private String address;
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
控制器代碼如下:
package org.zero01.test;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@Controller
@RequestMapping("/test")
public class Test {
@RequestMapping("/test.do")
// 只需要在方法上聲明一個對象參數即可
public void method(Student student) {
System.out.println(student.getSname());
System.out.println(student.getAge());
System.out.println(student.getAddress());
}
}
使用Postman進行訪問,訪問方式如下:
控制臺打印結果:
Jon
22
15
註:URL參數的名稱要與對象屬性的名稱對應得上,不然是無法進行綁定的。如:
控制臺打印結果:
Jon
0
null
數組參數綁定
SpringMVC除了可以自動幫我們綁定參數到pojo對象之外,還可以自動綁定參數到數組對象裏,這裏的數組指的是Integer、Stirng、Long等基本數據類型的包裝類數組,以及int、long、byte等基本數據類型的數組,示例:
package org.zero01.test;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@Controller
public class Test {
@RequestMapping(value = "/test.do")
public void method(String[] names) {
for (String name : names) {
System.out.println(name);
}
}
}
使用Postman進行訪問,訪問方式如下:
控制臺打印結果:
Jon
Mack
Alin
Steven
Eson
基本數據類型的數組也是一樣的:
package org.zero01.test;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@Controller
public class Test {
@RequestMapping(value = "/test.do")
public void method(int[] numbers) {
for (int number : numbers) {
System.out.println(number);
}
}
}
使用Postman進行訪問,訪問方式如下:
控制臺打印結果:
1
2
3
4
5
集合類型參數綁定
對於List、Set、Map等集合類型的參數綁定,如果我們嘗試直接綁定,是會失敗的,必須將其作為一個具體類對象的成員屬性,這個時候我們也可稱這個具體類對象為一個包裝類。
POJO類代碼如下:
package org.zero01.test;
import java.util.*;
public class Student {
private Map<String, Integer> map;
private List<String> list;
private Set<String> set;
public Map<String, Integer> getMap() {
return map;
}
public void setMap(Map<String, Integer> map) {
this.map = map;
}
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
public Set<String> getSet() {
return set;
}
public void setSet(Set<String> set) {
this.set = set;
}
}
控制器代碼如下:
package org.zero01.test;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@Controller
public class Test {
@RequestMapping(value = "/test.do")
public void method(Student student) {
System.out.println(student.getMap());
System.out.println(student.getList());
System.out.println(student.getSet());
}
}
使用Postman進行訪問,訪問方式如下:
控制臺打印結果:
{one=1, three=3, tow=2}
[4, 5, 6]
[7, 8, 9]
通過方法返回值轉發到視圖上
在SpringMVC中控制器只需要通過方法的返回值就可以轉發到某個指定的視圖上,示例:
package org.zero01.test;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@Controller
public class Test {
@RequestMapping(value = "/test.do", method = RequestMethod.GET)
public String method() {
return "index.jsp";
}
}
index.jsp內容如下:
<html>
<body>
<h2>Hello World!</h2>
</body>
</html>
使用Postman進行訪問,訪問結果如下:
默認情況下不加任何關鍵字是使用轉發機制(forward),如果在視圖名稱前面加上redirect關鍵字則是使用重定向機制(redirect)示例:
package org.zero01.test;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@Controller
public class Test {
@RequestMapping(value = "/test.do", method = RequestMethod.GET)
public String method() {
return "redirect:index.jsp";
}
}
但是大多數情況下為了安全性,我們一般會把jsp文件都放在WEB-INF目錄下,而放在該目錄下的jsp文件是無法通過重定向來進行訪問的,只能通過轉發機制進行訪問。因為WEB-INF目錄下的文件是不允許外部訪問的,重定向屬於外部訪問,外部訪問的話會報404錯誤,如下:
只能通過內部轉發進行訪問:
package org.zero01.test;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@Controller
public class Test {
@RequestMapping(value = "/test.do")
public String method() {
return "WEB-INF/index.jsp";
}
}
訪問結果:
配置視圖解析器
在以上的實驗中,我們只把jsp文件放在了WEB-INF目錄下,但是如果這個jsp文件是在很多級目錄下,那麽我們通過返回值來轉發到jsp上時,需要寫的路徑就很長了。例如我在WEB-INF目錄下創建一個pages目錄,在pages目錄裏再創建一個index目錄,然後把index.jsp文件放在這個index目錄下,那麽我們需要寫的路徑就是這樣子的:
package org.zero01.test;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@Controller
public class Test {
@RequestMapping(value = "/test.do")
public String method() {
return "WEB-INF/pages/index/index.jsp";
}
}
如果不想寫這麽長的路徑,就需要用到SpringMVC中的視圖解析器了,在Spring配置文件中,添加如下內容:
<!-- 配置視圖解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 視圖名稱的前綴 -->
<property name="prefix" value="/WEB-INF/pages/index/"/>
<!-- 視圖名稱的後綴 -->
<property name="suffix" value=".jsp"/>
</bean>
控制器代碼:
package org.zero01.test;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@Controller
public class Test {
@RequestMapping(value = "/test.do")
public String method() {
return "index";
}
}
從控制器代碼中可以看到,配置了視圖解析器之後,我們只需要寫個視圖的名稱就可以了,不需要去寫全路徑。
訪問結果:
SpringMVC中用於綁定請求數據的註解以及配置視圖解析器