Spring MVC (二)——控制器定義與@RequestMapping詳解


一、控制器定義

控制器提供訪問應用程序的行為,通常通過服務接口定義或注解定義兩種方法實現。 控制器解析用戶的請求並將其轉換為一個模型。在Spring MVC中一個控制器可以包含多個Action(動作、方法)。

使用注解@Controller定義控制器

org.springframework.stereotype.Controller注解類型用於聲明Spring類的實例是一個控制器(在講IOC時還提到了另外3個注解);Spring可以使用掃描機制來找到應用程序中所有基於注解的控制器類,為了保證Spring能找到你的控制器,需要在配置文件中聲明組件掃描。

創建一個名了Bar的類,定義為一個控制器,類的具體實現如下:

package com.zhangsan.springmvc01;

import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@org.springframework.stereotype.Controller
public class Controller {
    @RequestMapping("/bar")
    public String hi(Model model){
        model.addAttribute("msg","這是通過注解定義的一個控制器中的Action");
        return "hi";
    }
}

還要需要修改Spring mvc配置文件,啟用自動組件掃描功能,在beans中增加如下配置:

<!-- 自動掃描包,實現支持注解的IOC -->
    <context:component-scan base-package="com.zhangsan.springmvc01" />

運行結果如下:

小結:從代碼與運行結果可以看出BarController與FooController同時都指定了一個視圖hi.jsp,但是頁面結果的結果是不一樣的,從這里可以看出視圖是被復用的,而控制器與視圖之間是弱偶合關系。

二、@RequestMapping詳解

@RequestMapping注釋用於映射url到控制器類或一個特定的處理程序方法。可用於類或方法上。用於類上,表示類中的所有響應請求的方法都是以該地址作為父路徑。該注解共有8個屬性,注解源碼如下:

package org.springframework.web.bind.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.Callable;

import org.springframework.core.annotation.AliasFor;

/**
 * 用於映射url到控制器類或一個特定的處理程序方法.
 */
//該注解只能用於方法或類型上
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {

    /**
     * 指定映射的名稱
     */
    String name() default "";

    /**
     * 指定請求的路徑映射,指定的地址可以是uri模板,別名為path
     */
    @AliasFor("path")
    String[] value() default {};

    /** 別名為value,使用path更加形象
     * 只有用在一個Servlet環境:路徑映射URI(例如“/myPath.do”)。
     * Ant風格的路徑模式,同時也支持(例如,“/myPath/*.do”)。在方法層面,在主要的映射在類型級別表示相對路徑(例如,“edit.do”)
     * 的支持。路徑映射的URI可能包含占位符(例如“/$ {}連接”)
     */
    @AliasFor("value")
    String[] path() default {};

    /**
     * 指定請求謂詞的類型如GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE. 收窄請求范圍 The
     * HTTP request methods to map to, narrowing the primary mapping: GET, POST,
     * HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE.
     */
    RequestMethod[] method() default {};

    /**
     * 映射請求的參數,收窄請求范圍 The parameters of the mapped request, narrowing the
     * primary mapping.
     */
    String[]params() default {};

    /**
     * 映射請求頭部,收窄請求范圍 The headers of the mapped request, narrowing the primary
     * mapping. RequestMapping(value = "/something", headers =
     * "content-type=text/*")
     */
    String[] headers() default {};

    /**
     * 指定處理請求的提交內容類型(Content-Type),例如application/json, text/html,收窄請求范圍 The
     * consumable media types of the mapped request, narrowing the primary
     * mapping.
     */
    String[] consumes() default {};

    /**
     * 指定返回的內容類型,僅當request請求頭中的(Accept)類型中包含該指定類型才返回 The producible media types
     * of the mapped request, narrowing the primary mapping. produces =
     * "text/plain" produces = {"text/plain", "application/*"} produces =
     * "application/json; charset=UTF-8"
     */
    String[] produces() default {};
}

 

 從上面的源碼可以發現除了name基本都是數組類型,在設置時我們可以指定單個值,如@RequestMapping(value="/foo");也可以同時指定多個值如:@RequestMapping(value={"/foo","/bar"})。

2.1、指定具體路徑字符

2.1.1 只注解方法

@Controller
public class Controller {
    @RequestMapping("/h1")
    public String h1(){
        return "h1";
    }
}

 

 訪問路徑:http://localhost:8080/h1

 

2.1.2 同時注解類與方法

@Controller
@RequestMapping("/foo")
public class Controller {
    @RequestMapping("/h1")
    public String h1(){
        return h1";
    }
}

 

訪問路徑:http://localhost:8080/foo/h1

 需要先指定類的路徑再指定方法的路徑

 

2.1.3 @RequestMapping 來處理多個 URI

@Controller
@RequestMapping("/foo")
public class Controller {
    @RequestMapping(value = {"/hi","/a/b/c"})
    public String h2(Model model){
        model.addAttribute("msg","@RequestMapping 來處理多個 URI!");
        return "hi";
    }
}

訪問路徑:1、http://localhost:8080/foo/hi

        2、http://localhost:8080/foo/a/b/c

2.1.4、路徑變量占位,URI模板模式

在Spring MVC可以使用@PathVariable 注釋方法參數的值綁定到一個URI模板變量。

@Controller
@RequestMapping("/foo")
public class Controller {
    @RequestMapping(value = {"/h3/{name}/{id}"})
    public String h3(Model model, @PathVariable String name,@PathVariable int id){
        model.addAttribute("msg","路徑變量占位,URI模板模式!\n名稱:"+name+"\n編號:"+id);
        return "hi";
    }
}

訪問路徑:http://localhost:8080/foo/h3/張三/20

 

2.1.5、正則表達式模式的URI模板

@Controller
@RequestMapping("/foo")
public class Controller {
    @RequestMapping(value = "/h4/{id:\\d{6}}-{name:[a-z]{3}}")
    public String h4(Model model, @PathVariable String name,@PathVariable int id){
        model.addAttribute("msg","正則表達式模式的URI模板!\n名稱:"+name+"\n編號:"+id);
        return "hi";
    }
}

訪問路徑:http://localhost:8080/foo/h4/123456-abc

正則要求id必須為6位的數字,而name必須為3位小寫字母,訪問結果如下:

2.1.6、Ant風格路徑模式
@RequestMapping注解也支持ant風格的路徑模式,如/foo/h5/*.do,示例代碼如下:

@Controller
@RequestMapping("/foo")
public class Controller {
    @RequestMapping(value = "/h5/*.do")
    public String h5(Model model){
        model.addAttribute("msg","Ant風格路徑模式");
        return "hi";
    }
}

訪問路徑:http://localhost:8080/foo/h5/任意符號.do

ANT通配符有三種:

 

 

2.2、method屬性指定謂詞類型

用於約束請求的謂詞類型,可以收窄請求范圍。指定請求謂詞的類型如GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE,如下代碼所示:

@Controller
@RequestMapping("/foo")
public class Controller {
    @RequestMapping(value = "/h6",method = {RequestMethod.POST,RequestMethod.DELETE})
    public String h6(Model model){
        model.addAttribute("msg","請求謂詞只能是POST與DELETE");
        return "hi";
    }
}

 

 要訪問h6請求謂詞類型必須是POST或者為DELETE,當我們從瀏覽器的URL欄中直接請求時為一個GET請求,則結果是405,如下所示:

 

 如果將POST修改為GET則正常了,如下所示:

@Controller
@RequestMapping("/foo")
public class Controller {
    @RequestMapping(value = "/h6",method = {RequestMethod.GET})
    public String h6(Model model){
        model.addAttribute("msg","請求謂詞只能是GET");
        return "hi";
    }
}

 

Spring MVC 的 @RequestMapping 注解能夠處理 HTTP 請求的方法, 比如 GET, PUT, POST, DELETE 以及 PATCH。

所有的請求默認都會是 HTTP GET 類型的。

為了能降一個請求映射到一個特定的 HTTP 方法,你需要在 @RequestMapping 中使用 method 來聲明 HTTP 請求所使用的方法類型,如下所示:

@RestController  
@RequestMapping("/home")  
public class IndexController {  
    @RequestMapping(method = RequestMethod.GET)  
    String get() {  
        return "Hello from get";  
    }  
    @RequestMapping(method = RequestMethod.DELETE)  
    String delete() {  
        return "Hello from delete";  
    }  
    @RequestMapping(method = RequestMethod.POST)  
    String post() {  
        return "Hello from post";  
    }  
    @RequestMapping(method = RequestMethod.PUT)  
    String put() {  
        return "Hello from put";  
    }  
    @RequestMapping(method = RequestMethod.PATCH)  
    String patch() {  
        return "Hello from patch";  
    }  
}

在上述這段代碼中, @RequestMapping 注解中的 method 元素聲明了 HTTP 請求的 HTTP 方法的類型。 
所有的處理處理方法會處理從這同一個 URL( /home)進來的請求, 但要看指定的 HTTP 方法是什么來決定用哪個方法來處理。 
例如,一個 POST 類型的請求 /home 會交給 post() 方法來處理,而一個 DELETE 類型的請求 /home 則會由 delete() 方法來處理。 
你會看到 Spring MVC 將使用這樣相同的邏輯來映射其它的方法。

2.3、consumes屬性指定請求的Content-Type

@RequestMapping 注解的 produces 和 consumes 這兩個元素來縮小請求映射類型的范圍,達到處理生產和消費對象的目的。 

 指定處理請求的提交內容類型(Content-Type),例如application/json, text/html,收窄請求范圍,如果用戶發送的請求內容類型不匹配則方法不會響應請求,具體使用如下代碼所示:

@Controller
@RequestMapping("/foo")
public class Controller {
    @RequestMapping(value = "/h7",consumes = "text/html")
    public String h7(Model model){
        model.addAttribute("msg", "請求的提交內容類型(Content-Type)是text/html");
        return "hi";
    }
}

在h7的注解中約束發送到服務器的Content-Type必須是text/html類型,如果類型不一致則會報錯(415),測試結果如下:

請求的提交內容類型(Content-Type)是text/html 

注意:可以使用!號,如consumes="!text/html"

2.4、produces屬性指定響應的Content-Type,約束Accept類型

指定返回的內容類型,僅當request請求頭中的(Accept)類型中包含該指定類型才返回,方法才處理客戶端的請求否則會報406錯誤,常用設置如下:

produces = "text/plain"  //客戶端只接收純文本

produces = {"text/plain", "application/*"}   //客戶端接收純文本與application/*類型的內容

produces = "application/json; charset=UTF-8"  //客戶端接收json且編碼為utf-8/;

@Controller
@RequestMapping("/foo")
public class Controller {
    @RequestMapping(value = "/h8",produces = "application/json;charset=UTF-8")
    public String h8(Model model){
        model.addAttribute("msg", "客戶端可以接收的類型是application/json; charset=UTF-8");
        return "hi";
    }
}

 

 運行結果:

 注意:可以使用!號,如produces="!text/html"

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM