胖哥學SpringMVC:RequestMapping註解之對映路徑 上卷

胖先森發表於2019-03-03

@RequestMapping

個人建議重新練習一遍搭建的過程,如果感覺麻煩你可以直接複製上一個工程,但是需要修改pom.xml中的一點資訊

<groupId>com.hanpang.springmvc</groupId>
<artifactId>springmvc-demo02</artifactId>
<version>0.0.1-SNAPSHOT</version>
複製程式碼

1.基本用法

我們可以使用@RequestMapping標註來將請求URL(類似於@WebServlet),如/hanpang等,對映到整個類上某個特定的處理器方法上。

一般來說,類級別的標註負責將一個特定(或符合某種模式)的請求路徑對映到一個控制器上,同時通過方法級別的標註來細化對映,即根據特定的HTTP請求方法(“GET”和“POST”方法等)、HTTP請求中是否攜帶特定引數等條件,將請求對映到匹配的方法上。

package com.hanpang.web;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller//告知其是一個控制器
@RequestMapping("/sys")
public class Demo01Controller {
	//對映預設的路徑
	public ModelAndView test01() {
		System.out.println("該方法是訪問sys執行");
		return null;
	}
	//----------------細化--------------------//

	//對映一個路徑
	@RequestMapping(value="/user01")
	public ModelAndView test02() {
		System.out.println("/user01 path和value屬性一樣");
		return null;
	}
	//對映一個路徑
	@RequestMapping(path="/user02")
	public ModelAndView test03() {
		System.out.println("/user02 path和value屬性一樣");
		return null;
	}

	//簡寫方式
	@RequestMapping("/user03")
	public ModelAndView test04() {
		System.out.println("/user03 當只有path或者value屬性的時候,可以使用簡寫方式");
		return null;
	}

	//多個對映路徑執行一個方法
	@RequestMapping(value= {"/user04","/user05"})
	public ModelAndView test05() {
		System.out.println("設定多個對映路徑");
		return null;
	}
	//簡寫方式
	@RequestMapping({"/user06","/user07"})
	public ModelAndView test06() {
		System.out.println("設定多個對映路徑");
		return null;
	}

}
複製程式碼

2.路徑模式的匹配規則

閱讀一下,我們簡單瞭解一下規則就行,主要介紹一下萬用字元”*”的演示,實際開發中個人基本上沒有使用過.

package com.hanpang.web;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller//告知其是一個控制器
@RequestMapping("/web")
public class Demo02Controller {

	@RequestMapping("/*")
	public ModelAndView test01() {
		System.out.println("* 代表一層");
		return null;
	}

	@RequestMapping("/**")
	public ModelAndView test02() {
		System.out.println("** 代表任意層次");
		return null;
	}

}
複製程式碼

NOTE: 誰描述的更加準確,就執行誰

測試路徑如下:

http://127.0.0.1:8001/mvc/web/user01 執行tes01方法
http://127.0.0.1:8001/mvc/web/user02 執行tes01方法
http://127.0.0.1:8001/mvc/web/user01/user02  執行tes02方法
http://127.0.0.1:8001/mvc/web/a/b/c/d  執行tes02方法
複製程式碼

package com.hanpang.web;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller//告知其是一個控制器
@RequestMapping("/web")
public class Demo02Controller {

	@RequestMapping("/*")
	public ModelAndView test01() {
		System.out.println("* 代表一層");
		return null;
	}

	@RequestMapping("/role*")
	public ModelAndView test02() {
		System.out.println("role* 的描述更準確");
		return null;
	}

	@RequestMapping("/role")
	public ModelAndView test03() {
		System.out.println("role 我更準確");
		return null;
	}
}
複製程式碼

修改之前上面的程式碼,我們繼續測試路徑

http://127.0.0.1:8001/mvc/web/user01 執行test01方法
http://127.0.0.1:8001/mvc/web/roleuser01 執行test02方法
http://127.0.0.1:8001/mvc/web/role 執行test03方法
複製程式碼

使用萬用字元的方式真的很少,但是實際開發中我們經常使用URI模式,路徑傳遞資料的方式(佔位符),我們再次修改原來程式碼

package com.hanpang.web;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller//告知其是一個控制器
@RequestMapping("/web")
public class Demo02Controller {

	@RequestMapping("/*")
	public ModelAndView test01() {
		System.out.println("* 代表一層");
		return null;
	}

	@RequestMapping("/**")
	public ModelAndView test02() {
		System.out.println("** 代表一層");
		return null;
	}

	@RequestMapping("/{a}")
	public ModelAndView test03() {
		System.out.println("{a} 一個佔位符");
		return null;
	}
	@RequestMapping("/{a}/{b}")
	public ModelAndView test04() {
		System.out.println("/{a}/{b} 多個佔位符");
		return null;
	}

}
複製程式碼

測試路徑:

http://127.0.0.1:8001/mvc/web/user01 執行test03方法
http://127.0.0.1:8001/mvc/web/user01/user02 執行test04方法
http://127.0.0.1:8001/mvc/web/user01/user02//user03 執行test02方法
複製程式碼

NOTE: 發現佔位符的描述性比萬用字元的描述更加準確


當一個URL同時匹配多個模式時,只會選擇最匹配的一個:

  • URI模式變數的數目和萬用字元數量的總和最少的那個路徑模式更準確。比如,/hotels/{hotel}/*這個路徑擁有一個URI變數和一個萬用字元,而/hotels/{hotel}/**這個路徑則擁有一個URI變數和兩個萬用字元,因此前者是更準確的路徑模式。
  • 如果兩個模式的URI模式數量和萬用字元數量總和一致,則路徑更長的那個模式更準確。舉個例子,/foo/bar*就被認為比/foo/*更準確,因為前者的路徑更長。
  • 如果兩個模式的數量和長度均一致,則那個具有更少萬用字元的模式是更加準確的。比如,/hotels/{hotel}就比/hotels/*更精確。
  • 預設的通配模式/**比其他所有的模式都更”不準確“。比方說,/api/{a}/{b}/{c}就比預設的通配模式/**要更準確
  • 字首通配(比如/public/**)被認為比其他任何不包括雙萬用字元的模式更不準確。例如,/public/path3/{a}/{b}/{c}就比/public/**更準確

3.URI模式

請重視這種模式,URI模式為獲取**@RequestMapping**中指定的URL的眸一個特定部分提供很大的方便。

URI模式是一個類似於URI的字串,只不過其中包含了一個或多個的變數名。當使用實際的值去填充這些變數名的時候,模式就成為一個URI。比如說,一個這個URI模式http://127.0.0.1/mvc/shxt/{userId}就包含了一個變數名userId。將值1001賦給這個變數名後,它就變成了一個URI:http://127.0.0.1/mvc/shxt/1001

在Spring MVC中可以在方法引數上使用@PathVariable標註,將其與URI模式中的引數繫結起來:

瀏覽器訪問路徑如下: http://127.0.0.1:8001/mvc/shxt/1001

package com.hanpang.web;

@Controller//告知其是一個控制器
@RequestMapping("/shxt")
public class Demo03Controller {
	@RequestMapping("/{userId}")
	public ModelAndView test01(@PathVariable String userId) {
		System.out.println("獲取佔位符的值:"+userId);
		return null;
	}
}
複製程式碼

會在控制檯輸出: 獲取佔位符的值:1001

URI模式”/shxt/{userId}“定義了一個變數,名為userId。當控制器處理這個請求的時候,userId的值就會被URI模式中對應部分的值所填充。比如說,如果請求的URI是/userId/1001,此時變數userId的值就是1001

如果形參id跟佔位符{userId}不一致

為了處理@PathVariables標註,Spring MVC必須通過變數名來找到URI模式中相對應的變數。可以在標註中直接宣告:

package com.hanpang.web;

@Controller//告知其是一個控制器
@RequestMapping("/shxt")
public class Demo03Controller {
	@RequestMapping("/{userId}")
	public ModelAndView test01(@PathVariable(name="userId") String id) {
		System.out.println("獲取佔位符的值:"+id);
		return null;
	}
}
複製程式碼

一個方法可以擁有任意數量的@PathVariable標註:

package com.hanpang.web;

@Controller//告知其是一個控制器
@RequestMapping("/shxt")
public class Demo03Controller {

	@RequestMapping("/{userId}/role/{roleKey}")
	public ModelAndView test01(@PathVariable(name="userId") String id,@PathVariable String roleKey) {
		System.out.println("userId:"+id);
		System.out.println("roleKey:"+roleKey);
		return null;
	}
}
複製程式碼

@PathVariable標註被應用於Map<String, String>型別的引數上時,框架會使用所有URI模式變數來填充map。

package com.hanpang.web;

@Controller//告知其是一個控制器
@RequestMapping("/shxt")
public class Demo03Controller {

	@RequestMapping("/{userId}/role/{roleKey}")
	public ModelAndView test01(@PathVariable Map<String,String> map) {
		System.out.println(map);
		return null;
	}
}
複製程式碼

@PathVariable可以被應用於所有簡單型別的引數上,比如int、long、Date等型別。Spring會自動地幫你把引數轉化成合適的型別,如果轉換失敗,就丟擲一個TypeMismatchException。如果需要處理其他資料型別的轉換,也可以註冊自定義的類。


帶正規表示式的URI模式[來自官網]

有時候可能需要更準確地描述一個URI模式的變數,比如:/spring-web/spring-web-3.0.5.jar。要怎麼把它分解成幾個有意義的部分呢?

@RequestMapping標註支援在URI模式變數中使用正規表示式。語法是{varName:regex},其中第一部分定義了變數名,第二部分就是所要應用的正規表示式。比如下面的程式碼樣例:

@RequestMapping("/spring-web/{symbolicName:[a-z-]+}-{version:\d\.\d\.\d}{extension:\.[a-z]+}")
    public void handle(@PathVariable String version, @PathVariable String extension) {
        // ......
    }
}
複製程式碼

除了URI模式外,@RequestMapping標註還支援Ant風格的路徑模式(如/myPath/*.do等)。不僅如此,還可以把URI模式變數和Ant風格的glob組合起來使用(比如/owners/*/pets/{petId}這樣的用法等)。

相關文章