spring mvc @RequestMapping value 匹配規則和匹配優先順序
在一些場景中,請求的url可能是符合一定模式的多個值,這時候需要使用Ant 風格萬用字元來進行限定。
Ant 風格資源地址支援 3 種匹配符:
說明一下: _?萬用字元前面都多加了下劃線
- 1
- 2
–?:匹配檔名中的一個字元
– *:匹配檔名中的任意字元
– 兩個星花: ** 匹配多層路徑
@RequestMapping 還支援 Ant 風格的 URL:
– /user/*/createUser: 匹配
/user/aaa/createUser、 /user/bbb/createUser 等 URL
– /user/**/createUser: 匹配
/user/createUser、 /user/aaa/bbb/createUser 等 URL
– /user/createUser??: 匹配
/user/createUseraa、 /user/createUserbb 等 URL
這個似乎沒什麼難的,現在我們來看看一些例子。這些例子分成幾組,分別說明當萬用字元的url請求滿足多個控制器方法的RequestMapping條件時,會對映到哪一個方法上?
請求頁面如下:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Insert title here</title> </head> <body> 1 rq3/**/ or rq3/**/hhh<br/> <a href="c3/rq3/aaa/bbb/hhh">c3/rq3/aaa/bbb/hhh</a><br/> <br/> 2 rq4/*/bbb or rq4/**/bbb rq5/**/bbb<br/> <a href="c3/rq4/aaa/bbb">c3/rq4/aaa/bbb</a><br/> <a href="c3/rq4/aaa/ccc/bbb">c3/rq4/aaa/ccc/bbb</a><br/> <a href="c3/rq5/aaa/bbb">c3/rq5/aaa/bbb</a><br/> <br/> 3 rq6/qqq* or rq6/qqq? rq7/qqq*<br/> <a href="c3/rq6/qqqw">c3/rq6/qqqw</a><br/> <a href="c3/rq6/qqqww">c3/rq6/qqqww</a><br/> <a href="c3/rq7/qqqw">c3/rq7/qqqw</a><br/> <br/> 4<br/> rq8/**/kkk or rq8/aaa/**<br/> <a href="c3/rq8/aaa/kkk">c3/rq8/aaa/kkk</a><br/> rq8_bm/bbb/** rq8_bm/**/mmm<br/> <a href="c3/rq8_bm/bbb/mmm">c3/rq8_bm/bbb/mmm</a><br/> <br/> 5<br/> rq9/*/kkk/nnn or rq9/aaa/*/*<br/> <a href="c3/rq9/aaa/kkk/nnn">c3/rq9/aaa/kkk/nnn</a><br/> rq10/aaa/*/* or rq10/*/kkk/nnn<br/> <a href="c3/rq10/aaa/kkk/nnn">c3/rq10/aaa/kkk/nnn</a><br/> </body> </html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
顯示出來:
我們將上面五組請求對應的萬用字元標記了出來,並寫出相應的控制器方法。
package com.happyBKs.springmvc.handlers; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @RequestMapping("/c3") @Controller public class RMHandler { //1 //handle4和handle5測試當請求的url符合兩個對映方法的value萬用字元時,如何springmvc選擇 @RequestMapping(value="rq3/**/") public String handle4() { return "successrm"; } @RequestMapping(value="rq3/**/hhh") public String handle5() { return "robot_baymax1"; } //2 //handle6-8測試當請求的url符合兩個對映方法的value萬用字元時,如何springmvc選擇 @RequestMapping(value="rq4/*/bbb") public String handle6() { return "robot_baymax1"; } @RequestMapping(value="rq4/**/bbb") public String handle7() { return "robot_baymax2"; } @RequestMapping(value="rq5/**/bbb") public String handle8() { return "robot_baymax2"; } //3 //handle9-11測試當請求的url符合兩個對映方法的value萬用字元時,如何springmvc選擇 @RequestMapping(value="rq6/qqq*") public String handle9() { return "robot_baymax1"; } @RequestMapping(value="rq6/qqq?") public String handle10() { return "robot_baymax3"; } @RequestMapping(value="rq7/qqq*") public String handle11() { return "robot_baymax1"; } //4 //handle12-13測試當請求的url符合兩個對映方法的value萬用字元時,如何springmvc選擇 @RequestMapping(value="rq8/**/kkk") public String handle12() { System.out.print("handle12"); return "robot_baymax1"; } @RequestMapping(value="rq8/aaa/**") public String handle13() { System.out.print("handle13"); return "robot_baymax2"; } @RequestMapping(value="rq8_bm/bbb/**") public String handle12_bm() { System.out.print("handle12_bm"); return "robot_baymax1"; } @RequestMapping(value="rq8_bm/**/mmm") public String handle13_bm() { System.out.print("handle13_bm"); return "robot_baymax2"; } //5 //handle14-15測試當請求的url符合兩個對映方法的value萬用字元時,如何springmvc選擇 @RequestMapping(value="rq9/*/kkk/nnn") public String handle14() { System.out.print("handle14"); return "robot_baymax1"; } @RequestMapping(value="rq9/aaa/*/*") public String handle15() { System.out.print("handle15"); return "robot_baymax2"; } //handle16-17測試當請求的url符合兩個對映方法的value萬用字元時,如何springmvc選擇 @RequestMapping(value="rq10/aaa/*/*") public String handle16() { System.out.print("handle16"); return "robot_baymax1"; } @RequestMapping(value="rq10/*/kkk/nnn") public String handle17() { System.out.print("handle17"); return "robot_baymax2"; } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
那麼,我們來看看結果和結論吧:
第1組實驗:
一個請求:c3/rq3/aaa/bbb/hhh
對於兩個萬用字元請求url: rq3// 和 rq3//hhh
結果是rq3/**/hhh顯示的頁面robot_baymax1.jsp。
結論: 當springmvcDispatchServlet會選擇對映範圍更小、更具體的url來進行對映。
第2組實驗:
(A)請求:c3/rq4/aaa/bbb
萬用字元請求url:rq4/*/bbb
(B)請求:c3/rq5/aaa/bbb
萬用字元請求url:rq5/**/bbb
連個請求是類似的,但對映到的物理檢視的情況截然不同。
(A)結果:
(B)結果:
這是因為符合(A)請求c3/rq4/aaa/bbb 的由兩個方法的RequestMapping萬用字元,rq4//bbb和 rq4/*/bbb
這時候,的優先順序會高於*的萬用字元。
第3組實驗:
(A)請求:c3/rq6/qqqw
萬用字元請求url:rq6/qqq*
(B)請求:c3/rq7/qqqw
萬用字元請求url:rq7/qqq*
連個請求是類似的,但對映到的物理檢視的情況截然不同。
(A)結果:
(B)結果:
結論:當請求url兩個都符合時,含有?的對映優先順序高於含有*的。
大結論:至此,我們可以得到,相同位置相同個數的含有一個萬用字元,優先順序由高到低:? * **
第4組實驗:
(A)請求:c3/rq8/aaa/kkk
萬用字元請求url:rq8//kkk or rq8/aaa/
(B)請求:c3/rq8_bm/bbb/mmm
萬用字元請求url:rq8_bm/bbb/* rq8_bm/*/mmm
目的:看看相同的萬用字元在不同位置的請求url的對映情況。
結果:
(A)
(B)
結論:對映優先順序與萬用字元位置無關,當兩個RequestMapping萬用字元url差別僅僅是位置差別時,對映結果是隨機的。
(這裡的實驗也出現過兩個baymax2)
第5組實驗:
(A)請求:c3/rq9/aaa/kkk/nnn
萬用字元請求url:rq9//kkk/nnn or rq9/aaa//*
(B)請求:c3/rq10/aaa/kkk/nnn
萬用字元請求url:rq10/aaa// or rq10/*/kkk/nnn
目的:看看相同的萬用字元在個數不同請求url的對映情況。
結果:
(A)
(B)
結論:萬用字元個數少的RequestMapping的value更高優先順序。