Spring MVC 入門指南(二):@RequestMapping用法詳解

1、@RequestMapping 簡介html

在Spring MVC 中使用 @RequestMapping 來映射請求,也就是經過它來指定控制器能夠處理哪些URL請求,至關於Servlet中在web.xml中配置java

<servlet>
    <servlet-name>servletName</servlet-name>
    <servlet-class>ServletClass</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>servletName</servlet-name>
    <url-pattern>url</url-pattern>
</servlet-mapping>

的映射做用一致。讓咱們先看一下RequestMapping註解類的源碼:web

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
	String name() default "";
	String[] value() default {};
	String[] path() default {};
	RequestMethod[] method() default {};
	String[] params() default {};
	String[] headers() default {};
	String[] consumes() default {};
	String[] produces() default {};
}

1)在@Target中有兩個屬性,分別爲 ElementType.METHOD 和 ElementType.TYPE ,也就是說 @RequestMapping 能夠在方法的聲明中使用spring

2)能夠看到註解中的屬性除了 name() 返回的字符串,其它的方法均返回數組,也就是能夠定義多個屬性值,例如 value() 和 path() 均可以同時定義多個字符串值來接收多個URL請求數組


2、準備工做:(注:後面的示例都將基於準備工做)瀏覽器

1)新建一個 Web 工程,取名爲 SpringMVC spring-mvc

服務器

2)新建一個的控制器類:UserController網絡

package cn.kolbe.spring.mvc.controller;

import org.springframework.stereotype.Controller;

@Controller
public class UserController {

	public String login() {
		return "success";
	}
}

3)新建和配置 web.xml 以及 spring-mvc.xml 文件架構

略(具體參見 前一章:Spring MVC 學習筆記(一):HelloWorld

4)新建一個測試的 JSP 頁面 index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Spring MVC</title>
</head>
<body>
	<p> <a href="#">User Login</a>
</body>
</html>

5)新建一個成功跳轉的頁面 JSP 頁面 welcome.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Spring MVC</title>
</head>
<body>

	<h1>Welcome</h1>

</body>
</html>


3、測試 @RequestMapping 中的 value 和 path 屬性(這兩個屬性做用相同,能夠互換,若是僅有這一個屬性,則能夠省略,下面兩個例子均採用省略的方式)

1)將 @RequestMapping 註解在 login 方法上,而UserController上不添加 @RequestMapping 註解,這時的請求 URL 是相對於 Web 根目錄

@Controller
public class UserController {

	@RequestMapping("/login")
	public String login() {
		return "success";
	}
}

這時的方法 login() 能處理的 URL 請求路徑是基於 Web 應用的,也就是 http://localhost/SpringMVC/login,也就是 index.jsp 頁面中的 User Login 連接地址應該是:

<a href="login">User Login</a>


2)將 @RequestMapping 註解在 UserController 類上,這時類的註解是相對於 Web 根目錄,而方法上的是相對於類上的路徑

@Controller
@RequestMapping("/user")
public class UserController {

	@RequestMapping("/login")
	public String login() {
		return "success";
	}
}

這時的方法login()能處理的 URL 請求路徑則是 http://localhost/SpringMVC/user/login,也就是 index.jsp 頁面中的 User Login 連接地址應該是:

<a href="user/login">User Login</a>


4、測試 @RequestMapping 的 method 屬性

1)簡介:@RequestMapping 中的 method 主要用來定義接收瀏覽器發來的何種請求。在Spring中,使用枚舉類

org.springframework.web.bind.annotation.RequestMethod來定義瀏覽器請求的方式。

Http規範定義了多種請求資源的方式,最基本的有四種,分別爲:GET(查)、POST(增)、PUT(改)、DELETE(刪),而URL則用於定位網絡上的資源至關於地址的做用,配合四種請求方式,能夠實現對URL對應的資源的增刪改查操做。

在實際應用中,不少人並無按照這個規範作,由於使用GET/POST一樣能夠完成PUT和DELETE操做,甚至GET也能夠完成POST操做,由於GET不須要用到表單,而POST卻須要經過表單來發送。

2)經過 @RequestMapping(value="/login",method=RequestMethod.GET) 來指定 login()方法 僅處理經過 GET 方式發來的請求

@Controller
@RequestMapping(path = "/user")
public class UserController {

	@RequestMapping(path = "/login", method=RequestMethod.GET)
	public String login() {
		return "success";
	}
}

這時,若是瀏覽器發來的請求不是GET的話,將收到瀏覽器返回的錯誤提示,也就是得經過連接的方式而不是表單的方式:

<a href="user/login>User Login</a>

3)經過 @RequestMapping(value="/login",method=RequestMethod.POST) 來指定 login()方法 僅處理經過 POST 方式發來的請求

@Controller
@RequestMapping(path = "/user")
public class UserController {

	@RequestMapping(path = "/login", method=RequestMethod.POST)
	public String login() {
		return "success";
	}
}

這時,必須經過表單的方式發送請求,不然將收到瀏覽器返回的錯誤提示

<form action="user/login" method="post">
    <input type="submit" value="使用Post發送請求"/>
</form>

4)因爲在 RequestMapping 註解類中 method() 方法返回的是 RequestMethod 數組,因此能夠給 method 同時指定多個請求方式,例如:

@Controller
@RequestMapping(path = "/user")
public class UserController {
        // 該方法將同時接收經過GET和POST方式發來的請求
	@RequestMapping(path = "/login", method={RequestMethod.POST,RequestMethod.GET})
	public String login() {
		return "success";
	}
}


5、測試 @RequestMapping 的 params 屬性,該屬性表示請求參數,也就是追加在URL上的鍵值對,多個請求參數以&隔開,例如:

http://localhost/SpringMVC/user/login?username=kolbe&password=123456

則這個請求的參數爲username=kolbe以及password=123456,@RequestMapping 中可使用 params 來限制請求參數,來實現進一步的過濾請求,舉個例子:

@Controller
@RequestMapping(path = "/user")
public class UserController {
        
        // 該方法將接收 /user/login 發來的請求,且請求參數必須爲 username=kolbe&password=123456
	@RequestMapping(path = "/login", params={"username=kolbe","password=123456"})
	public String login() {
		return "success";
	}
}

該例中則表示 UserController 中的 login() 方法僅處理 /user/login 發來的請求,且必須帶有 username=kolbe&password=123456 的請求參數,不然瀏覽器將返回HTTP 404的錯誤, 對應 index.jsp 中的鍵接地址爲:

<a href="user/login?username=kolbe&password=123456">User Login</a>


6、測試 @RequestMapping 的 headers 屬性,該屬性表示請求頭

用於HTTP協義交互的信息被稱爲HTTP報文,客戶端發送的HTTP報文被稱爲請求報文,服務器發回給客戶端的HTTP報文稱爲響應報文,報文由報文頭部和報文體組成。

請求頭部(Request Headers):請求頭包含許多有關客戶端環境和請求正文的信息,例如瀏覽器支持的語言、請求的服務器地址、客戶端的操做系統等。

響應頭部(Rsponse Headers):響應頭也包含許多有用的信息,包括服務器類型、日期、響應內容的類型及編碼,響應內容的長度等等。

若是你安裝的是Chrome瀏覽器,能夠經過在網頁中  右擊鼠標---->審查元素---->Network---->Name中點擊網頁---->右側查看Headers便可,若是Name中沒有出現網頁,能夠刷新一下便可,下邊是我電腦中的一個請求頭部示例:

Request Headers
    Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
    Accept-Encoding:gzip, deflate, sdch
    Accept-Language:zh-CN,zh;q=0.8
    Cache-Control:max-age=0
    Connection:keep-alive
    Cookie:JSESSIONID=210075B5E521CWE3CDE938076295A57A
    Host:localhost:8080
    Upgrade-Insecure-Requests:1
    User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.93

回規正題,經過 @RequestMapping 中的 headers 屬性,能夠限制客戶端發來的請求

@Controller
@RequestMapping(path = "/user")
public class UserController {
        // 表示只接收本機發來的請求
	@RequestMapping(path = "/login", headers="Host=localhost:8080")
	public String login() {
		return "success";
	}
}


7、帶佔位符的URL

(一)帶佔位符的URL是Spring 3.0 新增的功能,能夠經過 @PathVariable 將 URL 中的佔位符綁定到控制器的處理方法的參數中,佔位符使用{}括起來

(二)使用方法:

1)帶佔位符的URL示例:

@Controller
@RequestMapping(path = "/user")
public class UserController {
        
	@RequestMapping(value="/{id}", method=RequestMethod.GET)
	public String show(@PathVariable("id") Integer id) {
		return "success";
	}
}

在這個控制器中 show() 方法將能夠接收 user/一、user/二、user/3等等的路徑請求,請求的方法必須爲GET,使用 @PathVariable 爲應用實現 REST 規範提供了具大的便利條件。


8、採用 REST 風格的 URL 請求

1)簡介:REST(Representational State Transfer):(資源)表現層狀態轉化,它是目前最流行的一種軟件架構,其結構清晰、易於理解、擴展方便且符合標準,正在愈來愈多的被實踐到應用中。

2)REST 風格的 URL 請求

 請求路徑        請求方法           做用
-/user/1        HTTP GET        獲得id爲1的user
-/user/1        HTTP DELETE     刪除id爲1的user
-/user/1        HTTP PUT        更新id爲1的user
-/user          HTTP POST       新增user

3)因爲瀏覽器表單只支持 GET 和 POST 請求,爲了實現 DELETE 和 PUT 請求,Spring 爲咱們提供了一個過濾器org.springframework.web.filter.HiddenHttpMethodFilter,能夠爲咱們將 GET 和 POST 請求經過過濾器轉化成 DELETE 和 PUT 請求。

4)在 web.xml 中配置過濾器

<!-- 配置 org.springframework.web.filter.HiddenHttpMethodFilter 過濾器 -->
<filter>
    <filter-name>hiddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>    
<filter-mapping>
    <filter-name>hiddenHttpMethodFilter</filter-name>
    <!-- 攔截全部請求 -->
    <url-pattern>/*</url-pattern>
</filter-mapping>

5)因爲瀏覽器表單沒法發送 DELETE 和 PUT 請求,因此爲了讓 HiddenHttpMethodFilter 識別請求的方法,須要在表單中添加一個隱藏域,名字爲 _method 值爲 DELETE 或 POST 或PUT,修改後 index.jsp 頁面代碼以下:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Spring MVC</title>
</head>
<body>
<p>
 	<!-- 獲得id爲1的user -->
	<a href="user/1">Test Rest GET</a>

	<!-- 新建id爲1的user -->
	<form action="user" method="post">
	        <input type="hidden" name="_method" value="POST"/>
		<input type="submit" value="Test Rest POST"/>
	</form>
	
	<!-- 刪除id爲1的user -->
	<form action="user/1" method="post">
		<input type="hidden" name="_method" value="DELETE"/>
		<input type="submit" value="Test Rest DELETE"/>
	</form>
	
	<!-- 更新id爲1的user -->
	<form action="user/1" method="post">
		<input type="hidden" name="_method" value="PUT"/>
		<input type="submit" value="Test Rest PUT"/>
	</form>

</body>
</html>

6)修改後的UserController代碼

package cn.kolbe.spring.mvc.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping(path = "/user")
public class UserController {

	@RequestMapping(value="/{id}", method=RequestMethod.GET)
	public String show(@PathVariable("id") Integer id) {
		System.out.println("查看id爲:" + id + "的user");
		return "success";
	}
	
	
	@RequestMapping(value="/{id}", method=RequestMethod.PUT)
	public String update(@PathVariable("id") Integer id) {
		System.out.println("更新id爲:" + id + "的user");
		return "success";
	}
	
	@RequestMapping(value="/{id}", method=RequestMethod.DELETE)
	public String destroy(@PathVariable("id") Integer id) {
		System.out.println("刪除id爲:" + id + "的user");
		return "success";
	}
	
	@RequestMapping(value="", method=RequestMethod.POST)
	public String create() {
		System.out.println("新建user");
		return "success";
	}
}


注:若是你的web項目是運行在Tomcat 8下,你會發現被過濾成DELETE和PUT請求,到達控制器後,返回時(forward)會報HTTP 405的錯誤提示

HTTP Status 405 - Request method 'DELETE' not supported
或
HTTP Status 405 - JSPs only permit GET POST or HEAD

有三種解決方案:

(一)將 Tomcat 8 改成 Tomcat 7,在Tomcat 7 下運行是正常的

(二)將請求轉發(forward)改成請求重定向(redirect)

(三)本身手動寫一個Filter來包裝HttpRequest中的getMethod()方法

下面介紹一下第(三)種作法,也就是本身寫一個Filter來包裝從服務器發回來的HttpRequest請求:




大體說一下流程,

1. 在第1步中,客戶端發送請求至服務器,這時若是發送的是POST請求且帶有以_method爲名的參數會被Spring的HiddenHttpMethodFilter給攔截。

2. HiddenHttpMethodFilter內有一個靜態內部類經過繼承HttpServletRequestWrapper類並重寫getMethod()方法,將該方法返回值設爲_method隱藏域的值。

3. HiddenHttpMethodFilter在包裝好Request後,將請求發往服務器的控制器中對應的方法處理器,這時的請求變成了圖中的 三、WrapperRequest by SpringFilter

4. 服務器處理完請求後,產生了一個forward請求,產生相應的請求處理信息發往客戶端,注意這時的request的getMethod()方法仍然是HiddenHttpMethodFilter包裝過的

5. 咱們須要在服務器的響應請求到達客戶端前進行攔截,這也是最關鍵的一步,經過自定義過濾器MyHttpMethodFilter進一步包裝請求,將getMethod()方法返回值改爲POST或GET便可

6. 在web.xml中配置該filter,注意dispatcher結點值必須爲FORWARD。因爲字數超限,暫時說到這。。。

<filter-mapping>
	<filter-name>myFilter</filter-name>
	<url-pattern>/*</url-pattern>
	<dispatcher>FORWARD</dispatcher>
</filter-mapping>
相關文章
相關標籤/搜索