@RequestParam,你一定見過;@PathVariable,你肯定也知道;@QueryParam,你怎麼會不曉得?!還有你熟悉的他 (@CookieValue)!她(@ModelAndView)!它(@ModelAttribute)!沒錯,僅註解這塊,spring mvc就為你開啟了五彩斑斕的世界。來來來,不要興(mi)奮(hu),坐下來,我們好好聊聊這麼些個註解兄弟們~~~(wait, 都沒有聽過? 好,來,你坐前排,就你!)
一、spring mvc如何匹配請求路徑——“請求路徑哪家強,RequestMapping名遠揚”
@RequestMapping是用來對映請求的,比如get請求,post請求,或者REST風格與非REST風格的。 該註解可以用在類上或者方法上,如果用於類上,表示該類中所有方法的父路徑。
舉例(這裡用到的測試類如SpringMVCTest以及一些頁面在第一篇《學習SpringMVC——從HelloWorld開始》中已經介紹):
SpringMVCTest.java中加入測試方法:
1
2
3
4
5
|
@RequestMapping ( "/testRequestMapping" )
public String testRequestMapping(){
System.out.println( "testRequestMapping" );
return SUCCESS;
}
|
注意這裡 在方法級別上新增了註解@RequestMapping(“/testRequestMapping”), 表示可以透過“/testRequestMapping”相對路徑來定位到這個方法,同時我們在SpringMVCTest類上也放了一個類級別的 RequestMapping的註解:
1
2
3
|
@RequestMapping ( "/springmvc" )
@Controller
public class SpringMVCTest {
|
注意這裡 還新增了一個@Controller的註解,該註解在SpringMVC 中,負責處理由DispatcherServlet 分發的請求,它把使用者請求 的資料經過業務處理層處理之後封裝成一個Model ,然後再把該Model 返回給對應的View 進行展示。至此有了一個 “springmvc/testRequestMapping”這樣的路徑,我們就能夠定位到testRequestMapping這個方法上,然後執行 方法內的方法體。
再補充一點,RequestMapping可以實現模糊匹配路徑,比如:
?:匹配一個字元
*:匹配任意字元
**:匹配多層路徑
/springmvc/**/lastTest 就可以匹配/springmvc/firstTest/secondTest/lastTest這樣的路徑
二、spring mvc如何獲取請求的引數——“八仙過海,各顯神通”
1. @PathVariable
該註解用來對映請求URL中繫結的佔位符。透過@PathVariable可以將URL中佔位符的引數繫結到controller處理方法的入參中,沒聽懂?看例子:
1
2
3
4
5
|
@RequestMapping ( "/testPathVariable/{id}" )
public String testPathVariable( @PathVariable (value= "id" ) Integer id){
System.out.println( "testPathVariable:" + id);
return SUCCESS;
}
|
在index.jsp中我們新增一條連線,用來觸發一個請求:
< a href="springmvc/testPathVariable/1">testPathVariable</ a >< br />< br />
|
我們可以 看到這裡有一個超連結,點選後會進入到springmvc/testPathVariable/1對應的controller處理的方法中,那我們現在就 是想獲取到這個請求引數中的“1”,所以在testPathVariable方法上加入“/testPathVariable/id”,關於
{id}的具體對應在該方法的引數中,透過@PathVariable(value="id")來宣告要接收的請求引數,並透過Integer id來繫結和接收。透過該種方式,我們就可以得到前臺頁面請求的引數“1”。
2. @RequestParam
該註解也是用來獲取請求引數的。那麼該註解和@PathVariable有何不同呢? 還是看例子:
在SpringMVCTest中新增方法
1
2
3
4
5
|
@RequestMapping (value= "/testRequestParam" )
public String testRequestParam( @RequestParam (value= "username" ) String username, @RequestParam (value= "age" , required= false , defaultValue= "0" ) int age){
System.out.println( "testRequestParam" + " username:" + username + " age:" +age);
return SUCCESS;
}
|
在index.jsp新增超連結標籤
1
|
< a href="springmvc/testRequestParam?username=jackie&age=12">testRequestParam</ a >< br />< br />
|
點選頁面 上的超連結,就會匹配controller中testRequestParam方法上的RequestMapping的路徑。注意在該方法中,我們透過 @RequestParam這個註解宣告瞭兩個變數,用來獲取請求中query所帶的引數值,一個是username後的值,另一個是age後面的值。
看到這 裡,你大概已經明白了@PathVariable和@RequestParam之間的一些區別了吧,對於像 “springmvc/testPathVariable/1”這樣的請求,我們透過@PathVariable來繫結請求的引數;而對於類似 “springmvc/testRequestParam?username=jackie&age=12”這樣的請求引數是以鍵值對出現的,我 們透過@RequestParam來獲取到如username或age後的具體請求值。
與RequestParam有異曲同工用法的還有QueryParam,因其不是spring mvc框架內的註解,這裡不再詳述。
對於不同的請求型別和請求方式,spring mvc都有一套針對的解決方案,下面我們來看看當下比較流行的REST風格的請求是啥樣的——利用REST風格實現增刪改查。
在SpringMVCTest類中自下而上的實現了查(get)增(post)刪(delete)和改(put)的介面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
@RequestMapping (value= "/testRest/{id}" , method=RequestMethod.PUT)
public String testRestPut( @PathVariable (value= "id" ) Integer id){
System.out.println( "test put:" + id);
return SUCCESS;
}
@RequestMapping (value= "/testRest/{id}" , method=RequestMethod.DELETE)
public String testRestDelete( @PathVariable (value= "id" ) Integer id){
System.out.println( "test delete:" + id);
return SUCCESS;
}
@RequestMapping (value= "/testRest" , method=RequestMethod.POST)
public String testRest(){
System.out.println( "test post" );
return SUCCESS;
}
@RequestMapping (value= "/testRest/{id}" , method=RequestMethod.GET)
public String testRest( @PathVariable (value= "id" ) Integer id){
System.out.println( "test get:" + id);
return SUCCESS;
}
|
那麼前臺介面如何實現呢,相對應的順序為
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
< form action="springmvc/testRest/1" method="post">
< input type="hidden" name="_method" value= "PUT"/>
< input type="submit" value="testRestPut"/>
</ form >< br />< br />
< form action="springmvc/testRest/1" method="post">
< input type="hidden" name="_method" value="DELETE"/>
< input type="submit" value="TestRest DELETE"/>
</ form >< br >< br >
< form action="springmvc/testRest" method="post">
< input type="submit" value="testRestPost">
</ form >< br />< br />
< a href="springmvc/testRest/1">testRest</ a >< br />< br />
|
除此之外,我們還需要在配置檔案web.xml中新增支援將post轉化為delete和put請求的宣告
1
2
3
4
5
6
7
8
9
10
|
< 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 >
|
如你所見,這裡的改和刪都是透過post的方式傳送出去的,因為這裡不支援put和delete來直接實現刪改,而是透過藉助post方式,並悄悄的帶上一塊令牌hidden型別的input標籤來告訴後臺我在前臺傳送的實際上是刪和改的請求。
那麼這個過程時如何實現的呢,為什麼加上
1
|
< input type="hidden" name="_method" value="DELETE"/>
|
這塊令牌,人家後臺就要買你的賬呢。那我們就來看看後來是如何買賬的吧。
歸根到底 還是得益於新增在web.xml中的HiddenHttpMethodFilter這個類,在該類中有一個方法doFilterInternal, 透過除錯我們可以發現其中端倪,啟動tomcat(不能是tomcat8),點選delete操作對應的input標籤,進入除錯介面,我們可以看到:
- 透過 request.getParameter(this.methodParam)在request域中得到 this.methodParam(_method)的值,對應於刪除delete的操作,在頁面上,delete中宣告瞭一個hidden的 input,其中name就是“_method”,value就是DELETE,所以這裡得到的paramValue的值為“DELETE”
- 繼續執行,可以看到透過request.getMethod的取值是否與“POST”相等,顯然,這裡是相等,因為我們在前臺頁面中對於delete的操作請求中method宣告為post方式
- 再往後就是將獲取到的請求方法封裝HttpServletRequest中,完成後續的處理。這裡我們應該明白了為什麼前臺要加上那樣一個hidden的input了。
小坑:這裡注意啟動不能是tomcat8,而只能是比8小的版本,如7或6等,下圖展示了用tomcat的報錯資訊和用7的成功響應:
總結下,如何傳送put和delete的請求:
- 在web.xml中配置HiddenHttpMethodFilter
- 傳送post請求
- 請求中是個隱藏域,name為”_mothod”,value為put或delete
最後再來說下@CookieValue這個註解。
3. @CookieValue
該註解也是差不多的套路,也是一種對映,對映的是一個Cookie值。
在我們傳送一個請求時,我們可以看到請求中攜帶了一些cookie值
比如這裡的JSESSIONID或者Path等。現在我們就寫個方法用於獲取Cookie值。
在SpringMVCTest中新增
1
2
3
4
5
|
@RequestMapping (value= "/testCookieValue" )
public String testCookieValue( @CookieValue ( "JSESSIONID" ) String cookieValue){
System.out.println( "testCookieValue: " + cookieValue);
return SUCCESS;
}
|
index.jsp介面上新增連結
1
|
< a href="springmvc/testCookieValue">testCookieValue</ a >< br />< br />
|
這樣我們就可以得到類似“testCookieValue: 1410F05C9ADD84E8659C2AC79E8CC666”這樣的結果。
至此,我們介紹了
- @RequestMapping的用法
- 獲取請求引數的@PathVariable、@RequestParam的用法
- 介紹如何實現REST風格的請求,並分析了post如何轉化為delete和put請求
- 介紹了@CookieValue的用法