1. 程式人生 > >SpringMVC中用於綁定請求數據的註解以及配置視圖解析器

SpringMVC中用於綁定請求數據的註解以及配置視圖解析器

SpringMVC 視圖解析器 @RequestHeader 綁定集合參數 @CookieValue

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中用於綁定請求數據的註解以及配置視圖解析器