springMVC請求映射全面分析
大小:0.6 MB 人氣: 2017-10-11 需要積分:1
一般的,我們類定義上的路徑注解起到命名空間的作用,防止不同方法的路徑映射產生沖突,比如我在UserController和ArticleController下都定義了如下的方法:
@RequestMapping(“list”) publicvoidlist(){ 。..。 }
一個list映射路徑,這時候springMVC就不知道該將請求交給到哪個方法處理。當然,我們也能在方法上進行二級路徑配置區分:
/*************UserController***********/@RequestMapping(“user/list”) publicvoidlist(){ 。..。 } /*************ArticleController***********/@RequestMapping(“article/list”) publicvoidlist(){ 。..。 }
這樣就能有效防止沖突了,但如果我有很多個方法存在這樣的沖突,是否都要在每個方法加上前綴呢?這時候我們可以選擇在類路徑上注解@RequestMapping來對全體方法進行區分。
通過url進行映射
1. Ant風格字符匹配
除了標準的url外,@RequestMapping還支持Ant風格字符,即”?”、”*”、”**”,其中
1. “?”:匹配一個任意字符,如/user/a?,匹配user/aa,user/ab等路徑
2. “*”:匹配任意字符串,如/user/a*,匹配/user下任意以a開頭的路徑如/user/abc,/user/aqw等
3. “**“:匹配多級路徑字符串,如/user/**/list,匹配/user/user1/list,/user/1resu/list等
在這里,需要注意的是當*的 位置與 個數不同時,*可以代表的 字符數有區別,看下面示例:
@RequestMapping(“u1/*”)//只能匹配u1/a,u1/b,不能匹配u1/————即此時*表示一個或多個字符publicvoidtest(HttpServletResponse response) throwsIOException{ response.getWriter().print(“u1/*”); } @RequestMapping(“u1/**”)//能夠匹配u1/,u1/qq,u1/qq/ww,這里要特別注意的是,“**“能匹配零個而“*”不能publicvoidtest(HttpServletResponse response) throwsIOException{ response.getWriter().print(“u1/*”); } @RequestMapping(“u2/a*”)//能夠匹配u2/a,u2/ab,u2/aqqqq等————即此時*表示零個或零個以上字符publicvoidtest1(HttpServletResponse response) throwsIOException{ response.getWriter().print(“u2/a*”); }
2. restful占位符匹配
除了使用上面風格,@RequestMapping還支持restful風格占位符的形式,假如我們需要針對特定用戶查看其特定文章,restful風格路徑匹配如下所示:
@Controller//注解為控制器,通過spring容器掃描,會注冊為一個Bean@RequestMapping(“/user/{uid}”)//一級訪問路徑,對類中所有方法生效publicclassUserController{@RequestMapping(“article/{aid}”) publicString detail(@PathVariable(“uid”)Integer uid,@PathVariable(“aid”)Integer aid){ System.out.println( “查看id為”+ uid + “的用戶文章,且文章id為”+aid); return“someplace”; } }
這里,如果我們想訪問用戶id為1,文章id為2的用戶文章,就可以訪問如下路徑:[項目根路徑]/user/1/article/2來完成。
我們使用@PathVariable(“val”)來完成對應路徑中{val}的資源請求,這里的兩個val名稱需一致,緊接著的方法入參名字任意,我們剛剛示例了一個多路徑參數綁定,假設只有一個,如下也是合法的:
@RequestMapping(“user/{uid}”) publicString detail(@PathVariable(“uid”)Integer notUid){//notUid名字也能成功綁定return“someplace”; }
此外,如果我們入參名字和url路徑資源名稱一致,則可以省略配置@PathVariable中的value值,如下實例也能正確綁定路徑資源到入參
@RequestMapping(“user/{uid}”) publicString detail(@PathVariable Integer uid){//notUid名字也能成功綁定return“someplace”; }
3. 優先匹配規則
url還有如下兩個常見匹配準則: 最長最精確優先匹配和 占位符優先匹配
1. 最長最精確優先匹配
下面我們來看前一個匹配實例:
@RequestMapping(“test/**”) publicvoidtest2(HttpServletResponse response) throwsIOException{ response.getWriter().print(“test/**”); } @RequestMapping(“test/*”) publicvoidtest3(HttpServletResponse response) throwsIOException{ response.getWriter().print(“test/*”); } @RequestMapping(“test/*/**”) publicvoidtest4(HttpServletResponse response) throwsIOException{ response.getWriter().print(“test/*/**”); } @RequestMapping(“test/*/*”) publicvoidtest5(HttpServletResponse response) throwsIOException{ response.getWriter().print(“test/*/*”); } @RequestMapping(“test/1/*”) publicvoidtest6(HttpServletResponse response) throwsIOException{ response.getWriter().print(“test/1/*”); } @RequestMapping(“test/1/2”) publicvoidtest7(HttpServletResponse response) throwsIOException{ response.getWriter().print(“test/1/2”); }
直接看上面匹配會覺得很亂,我們直接看下面的測試:
測試
匹配結果
test/a 匹配test/*而不匹配test/**(更精確優先匹配)
test/a/a/aa/a 匹配test/**而不匹配test/*/**,(在多層匹配中,**比***更精確)
test/a/a 匹配test/*/*,因為/*/*比**精確
test/1/a 匹配test/1/*,因為/1/*比/*/*精確
test/1/2 匹配test/1/2,這是完全匹配
2. 占位符優先匹配原則
占位符是指@PathVariable等路徑資源占位符,下面我們在看一個實例
@RequestMapping(“test/1/2”) publicvoidtest7(HttpServletResponse response) throwsIOException{ response.getWriter().print(“test/1/2”); } @RequestMapping(“test/1/{id}”) publicvoidtest8(HttpServletResponse response,@PathVariable Integer id ) throwsIOException{ response.getWriter().print(“test/1/(myId=)”+ id ); } @RequestMapping(“test/1/a”) publicvoidtest7(HttpServletResponse response) throwsIOException{ response.getWriter().print(“test/1/a”); }
從上一個實例的所有路徑映射中,我們測試出test/1/2是最精確的。但我們根據添加了占位符映射,在游覽器輸入 test/1/2,此時游覽器返回 test/1/(myId=)2,即 占位符的優先級比普通字符串的優先級更高!但如果我們此時輸入 test/1/a。程序不會因為我們的 在方法入參中id映射為Integer類型而放棄匹配,占位符的優先級依然比字符(串)a的優先級高,但由于 “a”不能轉化為Integer類型,所以服務器會返回 400錯誤
通過HTTP其它請求資源映射
除了使用url外,我們還能通過請求參數、請求方法、或請求頭進行映射
我們先看看@RequestMapping的完整屬性列表:
屬性
說明
value 指定請求的實際地址, 比如 /action/info之類。
method 指定請求的method類型, GET、POST、PUT、DELETE等
consumes 指定處理請求的提交內容類型(Content-Type),例如application/json, text/html;
produces 指定返回的內容類型,僅當request請求頭中的(Accept)類型中包含該指定類型才返回
params 指定request中必須包含某些參數值是,才讓該方法處理
headers 指定request中必須包含某些指定的header值,才能讓該方法處理請求
其中,consumes, produces使用content-type信息進行過濾信息;headers中可以使用content-type進行過濾和判斷。
在前面的使用中,我們發現并沒有指定value屬性,直接在括號里輸入字符串也能向value屬性賦值,這是因為在java注解中不加其他屬性,直接賦值必定是針對注解的value成員,如果該注解沒有名為value的成員,則會報錯
下面我們先看幾個示例:
示例1:vmethod,headers
@RequestMapping(value = “testa”,method = RequestMethod.POST,headers = “content-type=text/*”)
表示映射路徑為testa,請求方法必須為POST方法(如果我們用post發出請求,會返回錯誤信息HTTP Status 405 - Request method ‘GET’ not supported),headers部分表示請求頭信息中必須包含等號后相應部分內容,*匹配任意字符串
示例2:consumes
@RequestMapping(value = “testb”, consumes=“application/json”)
表示方法僅匹配request Content-Type為“application/json”類型的請求。
示例3:produces
@RequestMapping(value = “/testc”, produces=“application/json”)
表示方法匹配的請求需要請求頭中Accept部分包含”application/json“,同時在響應時,會將返回內容同時設置為”application/json‘’
示例4:params
@RequestMapping(value = “testd”,method = RequestMethod.GET,params = {“id1”,“id2”}) publicvoidtest12(HttpServletResponse response,Integer id1,Integer id2) throwsIOException{ response.getWriter().print(id1 + “——”+ id2); }
示例表示入參需包含參數名為id1,id2的兩個參數,這里如果我輸入:
1. http://localhost:8080/springMVC/user/testd—-
2. http://localhost:8080/springMVC/user/testd?id1=1—報404錯誤
3. ttp://localhost:8080/springMVC/user/testd?id1=1&id2=2—-返回1——2
4. ttp://localhost:8080/springMVC/user/testd?id1=1&id2=2&id3=3—-返回1——2
從以上我們可以看出,只有具有相應參數的才能完成映射,且可以有除了params中要求以外的參數,如id3。
在params的常見映射規則如下:
示例規則
說明
”param1” 請求必須包含名為param1的參數
“!param1” 請求中不能包含名為param1的參數
“param1!=value1 請求中必須包含param1參數,但其值不能為value1
{“param1=value1”,”param2”} 請求中需要包含param1參數和param2參數,且param1的值必須為value1
?
非常好我支持^.^
(0) 0%
不好我反對
(0) 0%