Spring2.5引入註解式處理器支援,通過@Controller和@RequestMapping註解定義我們的處理器類。並且提供了一組強大的註解需要通過處理器對映DefaultAnnotationHandlerMapping和處理器介面卡AnnotationMethodHandlerAdapter來開啟支援@Controller和@RequestMapping註解的處理器。


@Controller:用於標識是處理器類;

@RequestMapping:請求到處理器功能方法的對映規則;

@RequestParam:請求引數到處理器功能處理方法的方法引數上的繫結;

@ModelAttribute:請求引數到命令物件的繫結;

@InitBinder:自定義資料繫結註冊支援,用於將請求引數轉換到命令物件屬性的對應型別;

一、檢視返回

1、返回String物件

  1. @RequestMapping(value ="/index")//相對於根目錄的路徑
  2. public String test(ModelMap model) {  
  3.     model.addAttribute("message""呼叫FirstController的test方法");  
  4.     return"index";//指定頁面要跳轉的view檢視路徑
  5. }
	@RequestMapping(value ="/index")//相對於根目錄的路徑
	public String test(ModelMap model) {
		model.addAttribute("message", "呼叫FirstController的test方法");
		return "index";//指定頁面要跳轉的view檢視路徑
	}
直接返回檢視的名稱,結果:


2、返回ModelAndView物件

  1. @RequestMapping("/index1")  
  2. public ModelAndView test2() {  
  3.     ModelAndView modelAndView = new ModelAndView();  
  4.     ///modelAndView.setView(new RedirectView("index1"));
  5.     modelAndView.setViewName("index1");//指定頁面要跳轉的view檢視路徑
  6.     modelAndView.addObject("message""呼叫FirstController的test1方法");//第二個引數:指定了要項前臺傳遞的引數,在前臺可以這樣取值 ${sp_ids }
  7.     return modelAndView;  
  8. }
	@RequestMapping("/index1")
	public ModelAndView test2() {
		ModelAndView modelAndView = new ModelAndView();
		///modelAndView.setView(new RedirectView("index1"));
		modelAndView.setViewName("index1");//指定頁面要跳轉的view檢視路徑
		modelAndView.addObject("message", "呼叫FirstController的test1方法");//第二個引數:指定了要項前臺傳遞的引數,在前臺可以這樣取值 ${sp_ids }
		return modelAndView;
	}
結果:

其中

  1. modelAndView.setViewName("index1");
modelAndView.setViewName("index1");
也可以寫成:
  1. modelAndView.setView(new RedirectView("index1"));
modelAndView.setView(new RedirectView("index1"));

ModelAndView()

這個構造方法構造出來的ModelAndView
不能直接使用,應為它沒有指定view,也沒有繫結對應的model物件。當然,model物件不是必須的,但是view確實必須的。
用這個構造方法構造的例項主要用來在以後往其中加view設定和model物件。
給ModelAndView
例項設定view的方法有兩
個:setViewName(String viewName) 和 setView(View view)。前者是使用view
name,後者是使用預先構造好的View物件。其中前者比較常用。事實上View是一個介面,而不是一個可以構造的具體類,我們只能通過其他途徑來獲取
View的例項。對於view
name,它既可以是jsp的名字,也可以是tiles定義的名字,取決於使用的ViewNameResolver如何理解這個view name。
如何獲取View的例項以後再研究。
而對應如何給ModelAndView
例項設定model則比較複雜。有三個方法可以使用:
  1. addObject(Object modelObject)  
  2. addObject(String modelName, Object modelObject)  
  3. addAllObjects(Map modelMap) 
addObject(Object modelObject)
addObject(String modelName, Object modelObject)
addAllObjects(Map modelMap)

二、@RequestMapping

         對於各種註解而言,排第一的當然是“@Controller”,表明某類是一個controller。“@RequestMapping”請求路徑對映,如果標註在某個controller的類級別上,則表明訪問此類路徑下的方法都要加上其配置的路徑;最常用是標註在方法上,表明哪個具體的方法來接受處理某次請求。 

@RequestMapping 引數說明

  1. value  
  2. 定義處理方法的請求的 URL 地址。  
  3. method  
  4. 定義處理方法的 http method 型別,如 GET、POST 等。  
  5. params  
  6. 定義請求的 URL 中必須包含的引數。  
  7. headers  
  8. 定義請求中 Request Headers 必須包含的引數

2.1 攔截路徑設定

(1) 方法上的攔截

  1. @Controller
  2. publicclass FirstController {  
  3.     @RequestMapping(value ="/index")//相對於根目錄的路徑
  4.     public String test(ModelMap model) {  
  5.         model.addAttribute("message""呼叫FirstController的test方法");  
  6.         return"index";//指定頁面要跳轉的view檢視路徑
  7.     }  
  8. }
@Controller
public class FirstController {
	@RequestMapping(value ="/index")//相對於根目錄的路徑
	public String test(ModelMap model) {
		model.addAttribute("message", "呼叫FirstController的test方法");
		return "index";//指定頁面要跳轉的view檢視路徑
	}
}
表示攔截:http://localhost:8080/SpringMVCLearningChapter2/index1


(2)類上的攔截

  1. @Controller
  2. @RequestMapping("/user")  
  3. publicclass SecondController {  
  4.     @RequestMapping(value ="/index")  
  5.     public String test(ModelMap model) {  
  6.         model.addAttribute("message""呼叫SecondController 的test方法");  
  7.         return"index";//指定頁面要跳轉的view檢視路徑
  8.     }  
  9.     @RequestMapping("/index1")  
  10.     public ModelAndView test2() {  
  11.         ModelAndView modelAndView = new ModelAndView();  
  12.         ///modelAndView.setView(new RedirectView("index1"));
  13.         modelAndView.setViewName("index1");//指定頁面要跳轉的view檢視路徑
  14.         modelAndView.addObject("message""呼叫SecondController 的test1方法");//第二個引數:指定了要項前臺傳遞的引數,在前臺可以這樣取值 ${sp_ids }
  15.         return modelAndView;  
  16.     }     
  17. }
@Controller
@RequestMapping("/user")
public class SecondController {
	@RequestMapping(value ="/index")
	public String test(ModelMap model) {
		model.addAttribute("message", "呼叫SecondController 的test方法");
		return "index";//指定頁面要跳轉的view檢視路徑
	}

	@RequestMapping("/index1")
	public ModelAndView test2() {
		ModelAndView modelAndView = new ModelAndView();
		///modelAndView.setView(new RedirectView("index1"));
		modelAndView.setViewName("index1");//指定頁面要跳轉的view檢視路徑
		modelAndView.addObject("message", "呼叫SecondController 的test1方法");//第二個引數:指定了要項前臺傳遞的引數,在前臺可以這樣取值 ${sp_ids }
		return modelAndView;
	}	
}
表示攔截:http://localhost:8080/SpringMVCLearningChapter2/user/index

和http://localhost:8080/SpringMVCLearningChapter2/user/index1

即攔截:根目錄/user/index根目錄/user/index1

請求對映
  • 普通URL路徑對映

@RequestMapping(value={"/login.do","/user/login.do"}):多個URL路徑可以對映到同一個處理器的功能處理方法。

  • URL模板模式對映

@RequestMapping(value="/users/{userId}"):{xxx}佔位符,請求的URL可以是"/users/123456"或"/users/abcd"。

@RequestMapping(value="/users/{userId}/login.do"):這樣也是可以的,請求的URL可以是"/users/123/login.do"。

@RequestMapping(value="/users/{userId}/channel/{channelId}"):這樣也是可以的,請求的URL可以是"/users/123/channel/456"。

  • Ant風格的URL路徑對映

@RequestMapping(value="/users/**"):可以匹配"/users/abc/abc"。

@RequestMapping(value="/model?"):可匹配"/model1"或"/modela" ,但不匹配"/model"或"/modelaa";

@RequestMapping(value="/model*"):可匹配"/modelabc"或"/model",但不匹配"/modelabc/abc";

@RequestMapping(value="/model/*"):可匹配"/model/abc",但不匹配"/modelabc";

@RequestMapping(value="/model/**/{modelId}"):可匹配"/model/abc/abc/123”或"/model/123",

也就是Ant風格和URI模板變數風格可混用;

  • 正則表示式風格的URL路徑對映

從Spring3.0開始支援正則表示式風格的URL路徑對映,格式為{變數名:正則表示式}

@RequestMapping(value="/login/{userId://d+}.do"):可以匹配

"/login/123.do",但不能匹配"/login/abc.do",這樣可以設計加嚴格的規則。

  • 組合使用是"或"的關係

如@RequestMapping(value={"/login.do","/user/login.do"})組合使用是或的關係,即"/login.do"或

"/user/login.do"請求URL路徑都可以對映到@RequestMapping指定的功能處理方法。


2、param引數

如果想給一個頁面設定傳遞的引數,可以寫成如下:

  1. @Controller
  2. @RequestMapping("/third")  
  3. publicclass ThirdController {  
  4.     @RequestMapping(value ="/index",params="name")//要求傳遞引數name,瀏覽器中輸入name後,控制器會自動把引數傳遞給test中的name
  5.     public String test(ModelMap model,String name) {  
  6.         model.addAttribute("message", name);  
  7.         return"index";  
  8.     }  
  9. }
這時輸入http://localhost:8080/SpringMVCLearningChapter2/third/index是無法訪問的:

因為它要求你一定要傳遞一個name引數,所以得這樣寫:

當然,這裡也可以把需要的引數註解到方法的引數上去

  1. @RequestMapping(value ="/index")//要求傳遞引數name,瀏覽器中輸入name後,控制器會自動把引數傳遞給test中的name
  2. public String test(ModelMap model,@RequestParam("name")String name) {  
  3.     model.addAttribute("message", name);  
  4.     return"index";  
  5. }
	@RequestMapping(value ="/index")//要求傳遞引數name,瀏覽器中輸入name後,控制器會自動把引數傳遞給test中的name
	public String test(ModelMap model,@RequestParam("name")String name) {
		model.addAttribute("message", name);
		return "index";
	}

效果和上面和一樣的。這時如果還是想訪問http://localhost:8080/SpringMVCLearningChapter2/third/index,把required=false加上
  1. @RequestMapping(value ="/index")  
  2. public String test(ModelMap model,@RequestParam(value="name",required=false)String name) {  
  3.     model.addAttribute("message", name);  
  4.     return"index";  
  5. }
3、method
  1. @RequestMapping(value ="/index1",method = RequestMethod.GET,params="name")  
  2. public ModelAndView test2() {  
  3.     ModelAndView modelAndView = new ModelAndView();  
  4.     ///modelAndView.setView(new RedirectView("index1"));
  5.     modelAndView.setViewName("index1");//指定頁面要跳轉的view檢視路徑
  6.     modelAndView.addObject("message""呼叫SecondController 的test1方法");//第二個引數:指定了要項前臺傳遞的引數,在前臺可以這樣取值 ${sp_ids }
  7.     return modelAndView;  
  8. }
	@RequestMapping(value ="/index1",method = RequestMethod.GET,params="name")
	public ModelAndView test2() {
		ModelAndView modelAndView = new ModelAndView();
		///modelAndView.setView(new RedirectView("index1"));
		modelAndView.setViewName("index1");//指定頁面要跳轉的view檢視路徑
		modelAndView.addObject("message", "呼叫SecondController 的test1方法");//第二個引數:指定了要項前臺傳遞的引數,在前臺可以這樣取值 ${sp_ids }
		return modelAndView;
	}	
表明只能通過GET來訪問,或要POST,改成
  1. method = RequestMethod.POST
4、head

@RequestMapping(headers)
headers 的作用也是用於細化對映。只有當請求的 Request Headers 中包含與 heanders 值相匹配的引數,處理方法才會被呼叫。
@RequestMapping(value = "/specify", headers = "accept=text/*")
public String specify(){
return "example_specify_page";
}
請求的 Request Headers 中 Accept 的值必須匹配 text/* ( 如 text/html ),方法才會被呼叫。

三、其它常用註解

handler method 引數繫結常用的註解,我們根據他們處理的Request的不同內容部分分為四類:(主要講解常用型別)

A、處理requet uri 部分(這裡指uri template中variable,不含queryString部分)的註解:   @PathVariable;

B、處理request header部分的註解:   @RequestHeader, @CookieValue;

C、處理request body部分的註解:@RequestParam,  @RequestBody;

D、處理attribute型別是註解: @SessionAttributes, @ModelAttribute;

1、 @PathVariable 

當使用@RequestMapping URI template 樣式對映時, 即 /fourth/{num}, 這時的num可通過 @Pathvariable註解繫結它傳過來的值到方法的引數上。

示例程式碼:

  1. @Controller
  2. @RequestMapping("/fourth/{num}")  
  3. publicclass FourthController {  
  4.     @RequestMapping(value ="/index/{string}")  
  5.     public String test(ModelMap model,@PathVariable("num"int num,@PathVariable("string") String string) {  
  6.         model.addAttribute("message""num="+String.valueOf(num)+"  string="+string);  
  7.         return"index";  
  8.     }  
@Controller
@RequestMapping("/fourth/{num}")
public class FourthController {
	@RequestMapping(value ="/index/{string}")
	public String test(ModelMap model,@PathVariable("num") int num,@PathVariable("string") String string) {
		model.addAttribute("message", "num="+String.valueOf(num)+"  string="+string);
		return "index";
	}
}
瀏覽器輸入:http://localhost:8080/SpringMVCLearningChapter2/fourth/1234/index/linbingwen

上面程式碼把URI template 中變數num的值和string的值,繫結到方法的引數上。若方法引數名稱和需要繫結的uri template中變數名稱不一致,需要在@PathVariable("num")指定uri template中的名稱。

2、 @RequestHeader、@CookieValue

@RequestHeader 註解,可以把Request請求header部分的值繫結到方法的引數上。

  1. @RequestMapping(value = "six/index4")    
  2.    public String  getHello(@RequestHeader ("host") String hostName,    
  3.         @RequestHeader ("Accept") String acceptType,    
  4.         @RequestHeader ("Accept-Language") String acceptLang,    
  5.         @RequestHeader ("Accept-Encoding") String acceptEnc,      
  6.         @RequestHeader ("Cookie") String cookie,    
  7.         @RequestHeader ("User-Agent") String userAgent)    
  8.    {    
  9.     System.out.println("Host : " + hostName);    
  10.     System.out.println("Accept : " + acceptType);    
  11.     System.out.println("Accept Language : " + acceptLang);    
  12.     System.out.println("Accept Encoding : " + acceptEnc);    
  13.     System.out.println("Cookie : " + cookie);    
  14.     System.out.println("User-Agent : " + userAgent);    
  15.        return"index4";    
  16.    }
	@RequestMapping(value = "six/index4")  
	   public String  getHello(@RequestHeader ("host") String hostName,  
	        @RequestHeader ("Accept") String acceptType,  
	        @RequestHeader ("Accept-Language") String acceptLang,  
	        @RequestHeader ("Accept-Encoding") String acceptEnc,    
	        @RequestHeader ("Cookie") String cookie,  
	        @RequestHeader ("User-Agent") String userAgent)  
	   {  
	    System.out.println("Host : " + hostName);  
	    System.out.println("Accept : " + acceptType);  
	    System.out.println("Accept Language : " + acceptLang);  
	    System.out.println("Accept Encoding : " + acceptEnc);  

	    System.out.println("Cookie : " + cookie);  
	    System.out.println("User-Agent : " + userAgent);  
	       return "index4";  
	   }
執行後輸入:http://localhost:8080/SpringMVCLearningChapter2/six/index4

執行結果:


注:@RequestHeader 與@RequestParam 一樣也有3個引數,其含義與的@RequestParam 引數含義相同。

@CookieValue 可以把Request header中關於cookie的值繫結到方法的引數上。

引數繫結的程式碼:

  1. @RequestMapping("six/index3")  
  2. public String test3(Model model,@CookieValue(value="JSESSIONID", defaultValue="") String jsessionId) {    
  3.      model.addAttribute("jsessionId", jsessionId);  
  4.     return"index3";  
  5. }
JSP中獲取:
  1. <%@ page language="java"contentType="text/html; charset=gb2312"
  2.     pageEncoding="gb2312"%>
  3. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
  4. <html>
  5. <head>
  6. <metahttp-equiv="Content-Type"content="text/html; charset=gb2312">
  7. <title>Insert title here</title>
  8. </head>
  9. <body>
  10. 採用String返回檢視jsessionId=:${jsessionId}  
  11. </body>
  12. </html>
<%@ page language="java" contentType="text/html; charset=gb2312"
    pageEncoding="gb2312"%>
<!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=gb2312">
<title>Insert title here</title>
</head>
<body>
採用String返回檢視jsessionId=:${jsessionId}
</body>
</html>
結果:


即把JSESSIONID的值繫結到引數cookie上

注:@CookieValue 與@RequestParam 一樣也有3個引數,其含義與的@RequestParam 引數含義相同

3、@RequestParam, @RequestBody

@RequestParam

A) 常用來處理簡單型別的繫結,通過Request.getParameter() 獲取的String可直接轉換為簡單型別的情況( String--> 簡單型別的轉換操作由ConversionService配置的轉換器來完成);因為使用request.getParameter()方式獲取引數,所以可以處理get 方式中queryString的值,也可以處理post方式中 body data的值;

B)用來處理Content-Type: 為 application/x-www-form-urlencoded編碼的內容,提交方式GET、POST;

C) 該註解有兩個屬性: value、required; value用來指定要傳入值的id名稱,required用來指示引數是否必須繫結;

@RequestBody

該註解常用來處理Content-Type: 不是application/x-www-form-urlencoded編碼的內容,例如application/json, application/xml等;

它是通過使用HandlerAdapter 配置的HttpMessageConverters來解析post data body,然後繫結到相應的bean上的。

因為配置有FormHttpMessageConverter,所以也可以用來處理 application/x-www-form-urlencoded的內容,處理完的結果放在一個MultiValueMap<String, String>裡,這種情況在某些特殊需求下使用,詳情檢視FormHttpMessageConverter api;

示例程式碼:

  1. @RequestMapping(value = "/something", method = RequestMethod.PUT)  
  2. publicvoid handle(@RequestBody String body, Writer writer) throws IOException {  
  3.   writer.write(body);  
  4. }

4、@SessionAttributes, @ModelAttribute

@SessionAttributes:

該註解用來繫結HttpSession中的attribute物件的值,便於在方法中的引數裡使用。

該註解有value、types兩個屬性,可以通過名字和型別指定要使用的attribute 物件;

示例程式碼:

  1. @Controller
  2. @RequestMapping("/editPet.do")  
  3. @SessionAttributes("pet")  
  4. publicclass EditPetForm {  
  5.     // ...
  6. }

@ModelAttribute

該註解有兩個用法,一個是用於方法上,一個是用於引數上;

用於方法上時:  通常用來在處理@RequestMapping之前,為請求繫結需要從後臺查詢的model;

用於引數上時: 用來通過名稱對應,把相應名稱的值繫結到註解的引數bean上;要繫結的值來源於:

A) @SessionAttributes 啟用的attribute 物件上;

B) @ModelAttribute 用於方法上時指定的model物件;

C) 上述兩種情況都沒有時,new一個需要繫結的bean物件,然後把request中按名稱對應的方式把值繫結到bean中。

用到方法上@ModelAttribute的示例程式碼:

  1. @ModelAttribute("string1")  
  2. public String preRun() {  
  3.     System.out.println("Test Pre-Run");  
  4.     String string="linbingwen";  
  5.     return string;  
  6. }
     @ModelAttribute("string1")
	    public String preRun() {
	        System.out.println("Test Pre-Run");
	        String string="linbingwen";
	        return string;
	        
	    }

這種方式實際的效果就是在呼叫@RequestMapping的方法之前,為request物件的model裡put(“string1”, string);

JSP中可以這樣來獲取