Spring中Controller和RequestMapping的詳解
先看一個簡單的例項:
@Controller
@RequestMapping("/hello")
public class anyTypeController{
@RequestMapping(method={RequestMethod.GET,RequestMethod.POST})
public String processWebRequest(){
return "hello";
}
}
上述例子中簡單了闡明瞭Controller以及RequestMapping的用法。含義是
將這個class申明為一個bean,當web請求為/hello時,跳轉到這個class進行處理。
既然上文說了,此處的不需要再配置檔案中配置例如<bean id="xxx" class="com.xxx">的語句,但是我們的Spring如何知道哪些class是bean檔案,哪些class檔案不是bean檔案呢?按照Spring教材上所講,此處所有配置了@Controller 的class檔案回通過java的反射機制進行讀取,因此在這裡Spring2.5官方的org.springframework.web.servlet.mvc.annotation.defaultAnnotationHandlerMapping這個類進行處理。Ps:這裡想進一步學習的同學可以檢視原始碼進行分析。這個類的作用是:首先掃描Classpath獲取註解了@Controller的物件(掃面通過語句:<context:component-sacn/>進行掃描)。 之後通過反射機制進行繫結。
自定義用於基於註解的HandlerAdapter:
上面我們已經通過註解的方式配置好了bean,但是我們bean中方法不只是一個,我們怎麼知道每次訪問的是Controller的哪一個具體的方法呢?具體方法是使用@RequestMapping()註解,然後利用org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter的反射機制,將Controller中的具體方法和請求方法名繫結起來。Ps:想了解更深的同學請看Spring的原始碼。
@RequestMapping
由於在網上搜集到的@RequestMapping的資料很不齊全,看完雲裡霧裡,於是找了本書總結了一下。
@RequestMapping可以被標註型別申明和方法申明這兩種方式上。
申明在型別定義上,那麼@RequestMapping() 括號裡面的東西通常為請求的地址
申明在方法定義上,那麼它用來表明當面方法定義是一個Web請求處理方法。(Ps:這是書上講的,個人理解的是加上具體的對映條件,使對映不會出錯)
下來看個例子,詳細說明:
@Controller
@RequestMapping("/hello")
public class MyController{
@RequestMapping(method=RequestMethod.GET)
public String function1(..){..}
@RequestMapping(method=RequestMethod.POST)
public String function2(..){..}
}
型別定義上標註的@RequestMapping("/hello")的意思是,所有提交到/hello的web請求都有MyController處理。但是問題來了,假設這個bean裡面有很多個函式,到底決定由哪一個來處理呢?接下來會使用在方法定義上的@RequestMapping()進行進一步的縮小範圍。如次所以,所有GET方法請求都會被function1處理,POST請求被function2處理。除了method可以區分,我們還有param可以區分(因為一個bean裡面也不僅僅只有兩個函式。GET和POST並不能使用於所有的地方)。
params屬性的兩種表示式形式:
1.“引數名=引數值”,通常引數名相同,後面的引數值用來區分並且界定請求的處理範圍。例項:
@Controller
@RequestMapping("/hello")
public class MyController{
@RequestMapping(params="locale=en",{method=RequestMethod.POST})
public String function1(..){..}
@RequestMapping(params="locale=ch",method={RequestMethod.POST})
public String function2(..){..}
}
這裡,當請求為http://xxx/xxx/hello?locale=en 時,呼叫function1(..)函式
當請求是http://xxx/xxx/hello?locale=ch時,呼叫function2()函式
2.“paramter” 形式的表示式。 這裡判斷請求中時候存在某一個引數來決定當前請求交個哪個方法處理。
@Controller
@RequestMapping("/hello")
public class MyController{
@RequestMapping(params="delete",{method=RequestMethod.POST})
public String function1(..){..}
@RequestMapping(params="update",method={RequestMethod.POST})
public String function2(..){..}
}
這裡請求可以是http://xxxxxxx/hell?delete 就會訪問function1
@RequestMapping還有一一種全部用於方法級別的繫結方式.例:注意,這裡用的是value
@Controller
public class MyController{
@RequestMapping("/hello1")
public String function1(..){...}
@RequestMapping(value="/hello2",{method=RequestMethod.POST})
public String function2(..){..}
@RequestMapping(value="/hello3",method={RequestMethod.POST})
public String function3(..){..}
}
上述僅僅講了對映的相關知識。下來看如果帶有引數的請求應該如何處理。
請求引數到方法引數的繫結
1.預設繫結行為
假設有如下請求:<a href="/hello?age=10?name=jack">
@Controller
public class MyController{
@RequestMapping("/hello")
pulbic String function1(int age ,String name){
System.out.println(age + name);
return "success";
}
}
在這裡會發現,age 和name自動賦給了函式引數中的age和name。 這是以為預設繫結行為是根據名稱匹配原則進行的函式繫結。當請求中的引數名與方法中的引數名一致,相應的引數值將被繫結到對應的方法引數上(這裡框架類保證了請求引數完成了型別轉換)。
2.使用@RequestParam明確的指定繫結關係.同樣是上面的例子.
@Controller
public class MyController{
@RequestMapping("/hello")
pulbic String function1(@RequestParam("ageOfJack") int age ,String name){
System.out.println(age + name);
return "success";
}
}
這時候同樣是剛才的web請求,已經可以將age的值賦給了ageOfJack引數。預設情況下,如果@RequestParam請求的資料不存在,會丟擲異常。這是因為他的required屬性決定的。他的預設值是true.假設將他設定為false,即該引數不存在時不會報錯,對應方法將獲取到該型別的預設值。
pulbic String function1(@RequestParam("ageOfJack",required=false) int age ,String name)
3.新增自定義資料繫結規則。
Spring框架提供的資料繫結才用JavaBean規範的PropertyEditor機制進行資料轉換。在基於註解的Controller中,可以用下面兩種方式達到這一目的.
1.使用@InitBinder(針對一個Controller)
2.指定自定義的WebBindingInitialize。(這個是針對多個Controller)