Spring MVC 使用@RequestMapping注解映射請求路徑

2018-07-26 15:29 更新

你可以使用@RequestMapping注解來將請求URL,如/appointments等,映射到整個類上或某個特定的處理器方法上。一般來說,類級別的注解負責將一個特定(或符合某種模式)的請求路徑映射到一個控制器上,同時通過方法級別的注解來細化映射,即根據(jù)特定的HTTP請求方法(“GET”“POST”方法等)、HTTP請求中是否攜帶特定參數(shù)等條件,將請求映射到匹配的方法上。

下面這段代碼示例來自Petcare,它展示了在Spring MVC中如何在控制器上使用@RequestMapping注解:

@Controller
@RequestMapping("/appointments")
public class AppointmentsController {

    private final AppointmentBook appointmentBook;

    @Autowired
    public AppointmentsController(AppointmentBook appointmentBook) {
        this.appointmentBook = appointmentBook;
    }

    @RequestMapping(method = RequestMethod.GET)
    public Map<String, Appointment> get() {
        return appointmentBook.getAppointmentsForToday();
    }

    @RequestMapping(path = "/{day}", method = RequestMethod.GET)
    public Map<String, Appointment> getForDay(@PathVariable @DateTimeFormat(iso=ISO.DATE) Date day, Model model) {
        return appointmentBook.getAppointmentsForDay(day);
    }

    @RequestMapping(path = "/new", method = RequestMethod.GET)
    public AppointmentForm getNewForm() {
        return new AppointmentForm();
    }

    @RequestMapping(method = RequestMethod.POST)
    public String add(@Valid AppointmentForm appointment, BindingResult result) {
        if (result.hasErrors()) {
            return "appointments/new";
        }
        appointmentBook.addAppointment(appointment);
        return "redirect:/appointments";
    }
}

在上面的示例中,許多地方都使用到了@RequestMapping注解。第一次使用點是作用于類級別的,它指示了所有/appointments開頭的路徑都會被映射到控制器下。get()方法上的@RequestMapping注解對請求路徑進行了進一步細化:它僅接受GET方法的請求。這樣,一個請求路徑為/appointments、HTTP方法為GET的請求,將會最終進入到這個方法被處理。add()方法也做了類似的細化,而getNewForm()方法則同時注解了能夠接受的請求的HTTP方法和路徑。這種情況下,一個路徑為appointments/new、HTTP方法為GET的請求將會被這個方法所處理。

getForDay()方法則展示了使用@RequestMapping注解的另一個技巧:URI模板。(關于URI模板,請見下小節(jié))

類級別的@RequestMapping注解并不是必須的。不配置的話則所有的路徑都是絕對路徑,而非相對路徑。以下的代碼示例來自PetClinic,它展示了一個具有多個處理器方法的控制器:

@Controller
public class ClinicController {

    private final Clinic clinic;

    @Autowired
    public ClinicController(Clinic clinic) {
        this.clinic = clinic;
    }

    @RequestMapping("/")
    public void welcomeHandler() {
    }

    @RequestMapping("/vets")
    public ModelMap vetsHandler() {
        return new ModelMap(this.clinic.getVets());
    }
}

以上代碼沒有指定請求必須是GET方法還是PUT/POST或其他方法,@RequestMapping注解默認會映射所有的HTTP請求方法。如果僅想接收某種請求方法,請在注解中指定之@RequestMapping(method=GET)以縮小范圍。

@Controller和面向切面(AOP)代理

有時,我們希望在運行時使用AOP代理來裝飾控制器,比如當你直接在控制器上使用@Transactional注解時。這種情況下,我們推薦使用類級別(在控制器上使用)的代理方式。這一般是代理控制器的默認做法。如果控制器必須實現(xiàn)一些接口,而該接口又不支持Spring Context的回調(diào)(比如InitializingBean*Aware等接口),那要配置類級別的代理就必須手動配置了。比如,原來的配置文件<tx:annotation-driven/>需要顯式配置為<tx:annotation-driven proxy-target-class="true"/>

Spring MVC 3.1中新增支持@RequestMapping的一些類

They are recommended for use and even required to take advantage of new features in Spring MVC 3.1 and going forward.

Spring 3.1中新增了一組類用以增強@RequestMapping,分別是RequestMappingHandlerMappingRequestMappingHandlerAdapter。我們推薦你用一用。有部分Spring MVC 3.1之后新增的特性,這兩個注解甚至是必須的。在MVC命名空間和MVC Java編程配置方式下,這組類及其新特性默認是開啟的。但若你使用其他配置方式,則該特性必須手動配置才能使用。本小節(jié)將簡要介紹一下,新類相比之前的一些重要變化。

在Spring 3.1之前,框架會在兩個不同的階段分別檢查類級別和方法級別的請求映射——首先,DefaultAnnotationHanlderMapping會先在類級別上選中一個控制器,然后再通過AnnotationMethodHandlerAdapter定位到具體要調(diào)用的方法。

[Original] With the new support classes in Spring 3.1, the RequestMappingHandlerMapping is the only place where a decision is made about which method should process the request. Think of controller methods as a collection of unique endpoints with mappings for each method derived from type and method-level @RequestMapping information.

現(xiàn)在有了Spring 3.1后引入的這組新類,RequestMappingHandlerMapping成為了這兩個決策實際發(fā)生的唯一一個地方。你可以把控制器中的一系列處理方法當成是一系列獨立的服務節(jié)點,每個從類級別和方法級別的@RequestMapping注解中獲取到足夠請求1路徑映射信息。

[Original] This enables some new possibilities. For once a HandlerInterceptor or a HandlerExceptionResolver can now expect the Object-based handler to be a HandlerMethod, which allows them to examine the exact method, its parameters and associated annotations. The processing for a URL no longer needs to be split across different controllers.

這種新的處理方式帶來了新的可能性。之前的HandlerInterceptorHandlerExceptionResolver現(xiàn)在可以確定拿到的這個處理器肯定是一個HandlerMethod類型,因此它能夠精確地了解這個方法的所有信息,包括它的參數(shù)、應用于其上的注解等。這樣,內(nèi)部對于一個URL的處理流程再也不需要分隔到不同的控制器里面去執(zhí)行了。

[Original] There are also several things no longer possible: [Original] Select a controller first with a SimpleUrlHandlerMapping or BeanNameUrlHandlerMapping and then narrow the method based on @RequestMapping annotations. [Original] Rely on method names as a fall-back mechanism to disambiguate between two @RequestMapping methods that don’t have an explicit path mapping URL path but otherwise match equally, e.g. by HTTP method. In the new support classes @RequestMapping methods have to be mapped uniquely. [Original] * Have a single default method (without an explicit path mapping) with which requests are processed if no other controller method matches more concretely. In the new support classes if a matching method is not found a 404 error is raised.

同時,也有其他的一些變化,比如有些事情就沒法這么玩兒了:

  • 先通過SimpleUrlHandlerMappingBeanNameUrlHandlerMapping來拿到負責處理請求的控制器,然后通過@RequestMapping注解配置的信息來定位到具體的處理方法;
  • 依靠方法名稱來作為選擇處理方法的標準。比如說,兩個注解了@RequestMapping的方法除了方法名稱擁有完全相同的URL映射和HTTP請求方法。在新版本下,@RequestMapping注解的方法必須具有唯一的請求映射;
  • 定義一個默認方法(即沒有聲明路徑映射),在請求路徑無法被映射到控制器下更精確的方法上去時,為該請求提供默認處理。在新版本中,如果無法為一個請求找到合適的處理方法,那么一個404錯誤將被拋出;

[Original] The above features are still supported with the existing support classes. However to take advantage of new Spring MVC 3.1 features you’ll need to use the new support classes.

如果使用原來的類,以上的功能還是可以做到。但是,如果要享受Spring MVC 3.1版本帶來的方便特性,你就需要去使用新的類。

[Original] ## URI Template Patterns

URI模板

[Original] URI templates can be used for convenient access to selected parts of a URL in a @RequestMapping method.

URI模板可以為快速訪問@RequestMapping中指定的URL的一個特定的部分提供很大的便利。

[Original] A URI Template is a URI-like string, containing one or more variable names. When you substitute values for these variables, the template becomes a URI. The proposed RFC for URI Templates defines how a URI is parameterized. For example, the URI Template http://www.example.com/users/{userId} contains the variable userId. Assigning the value fred to the variable yields http://www.example.com/users/fred.

URI模板是一個類似于URI的字符串,只不過其中包含了一個或多個的變量名。當你使用實際的值去填充這些變量名的時候,模板就退化成了一個URI。在URI模板的RFC提議中定義了一個URI是如何進行參數(shù)化的。比如說,一個這個URI模板http://www.example.com/users/{userId}就包含了一個變量名userId。將值fred賦給這個變量名后,它就變成了一個URI:http://www.example.com/users/fred。

[Original] In Spring MVC you can use the @PathVariable annotation on a method argument to bind it to the value of a URI template variable:

在Spring MVC中你可以在方法參數(shù)上使用@PathVariable注解,將其與URI模板中的參數(shù)綁定起來:

@RequestMapping(path="/owners/{ownerId}", method=RequestMethod.GET)
public String findOwner(@PathVariable String ownerId, Model model) {
    Owner owner = ownerService.findOwner(ownerId);
    model.addAttribute("owner", owner);
    return "displayOwner";
}

[Original] The URI Template "/owners/{ownerId}" specifies the variable name ownerId. When the controller handles this request, the value of ownerId is set to the value found in the appropriate part of the URI. For example, when a request comes in for /owners/fred, the value of ownerId is fred.

URI模板"/owners/{ownerId}"指定了一個變量,名為ownerId。當控制器處理這個請求的時候,ownerId的值就會被URI模板中對應部分的值所填充。比如說,如果請求的URI是/owners/fred,此時變量ownerId的值就是fred. `

為了處理@PathVariables注解,Spring MVC必須通過變量名來找到URI模板中相對應的變量。你可以在注解中直接聲明:

@RequestMapping(path="/owners/{ownerId}}", method=RequestMethod.GET)
public String findOwner(@PathVariable("ownerId") String theOwner, Model model) {
    // 具體的方法代碼…
}

或者,如果URI模板中的變量名與方法的參數(shù)名是相同的,則你可以不必再指定一次。只要你在編譯的時候留下debug信息,Spring MVC就可以自動匹配URL模板中與方法參數(shù)名相同的變量名。

@RequestMapping(path="/owners/{ownerId}", method=RequestMethod.GET)
public String findOwner(@PathVariable String ownerId, Model model) {
    // 具體的方法代碼…
}

[Original] A method can have any number of @PathVariable annotations:

一個方法可以擁有任意數(shù)量的@PathVariable注解:

@RequestMapping(path="/owners/{ownerId}/pets/{petId}", method=RequestMethod.GET)
public String findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
    Owner owner = ownerService.findOwner(ownerId);
    Pet pet = owner.getPet(petId);
    model.addAttribute("pet", pet);
    return "displayPet";
}

[Original] When a @PathVariable annotation is used on a Map<String, String> argument, the map is populated with all URI template variables.

@PathVariable注解被應用于Map<String, String>類型的參數(shù)上時,框架會使用所有URI模板變量來填充這個map。

[Original] A URI template can be assembled from type and path level @RequestMapping annotations. As a result the findPet() method can be invoked with a URL such as /owners/42/pets/21.

URI模板可以從類級別和方法級別的 @RequestMapping 注解獲取數(shù)據(jù)。因此,像這樣的findPet()方法可以被類似于/owners/42/pets/21這樣的URL路由并調(diào)用到:

_@Controller_
@RequestMapping("/owners/{ownerId}")
public class RelativePathUriTemplateController {

    @RequestMapping("/pets/{petId}")
    public void findPet(_@PathVariable_ String ownerId, _@PathVariable_ String petId, Model model) {
        // 方法實現(xiàn)體這里忽略
    }

}

[Original] A @PathVariable argument can be of any simple type such as int, long, Date, etc. Spring automatically converts to the appropriate type or throws a TypeMismatchException if it fails to do so. You can also register support for parsing additional data types. See the section called "Method Parameters And Type Conversion" and the section called "Customizing WebDataBinder initialization".

@PathVariable可以被應用于所有 簡單類型 的參數(shù)上,比如int、long、Date等類型。Spring會自動地幫你把參數(shù)轉(zhuǎn)化成合適的類型,如果轉(zhuǎn)換失敗,就拋出一個TypeMismatchException。如果你需要處理其他數(shù)據(jù)類型的轉(zhuǎn)換,也可以注冊自己的類。若需要更詳細的信息可以參考“方法參數(shù)與類型轉(zhuǎn)換”一節(jié)“定制WebDataBinder初始化過程”一節(jié)

帶正則表達式的URI模板

[Original] Sometimes you need more precision in defining URI template variables. Consider the URL "/spring-web/spring-web-3.0.5.jar". How do you break it down into multiple parts?

有時候你可能需要更準確地描述一個URI模板的變量,比如說這個URL:"/spring-web/spring-web-3.0.5.jar。你要怎么把它分解成幾個有意義的部分呢?

[Original] The @RequestMapping annotation supports the use of regular expressions in URI template variables. The syntax is {varName:regex} where the first part defines the variable name and the second - the regular expression.For example:

@RequestMapping注解支持你在URI模板變量中使用正則表達式。語法是{varName:regex},其中第一部分定義了變量名,第二部分就是你所要應用的正則表達式。比如下面的代碼樣例:

@RequestMapping("/spring-web/{symbolicName:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{extension:\\.[a-z]+}")
    public void handle(@PathVariable String version, @PathVariable String extension) {
        // 代碼部分省略...
    }
}

Path Patterns(不好翻,容易掉韻味)

[Original] In addition to URI templates, the @RequestMapping annotation also supports Ant-style path patterns (for example, /myPath/*.do). A combination of URI template variables and Ant-style globs is also supported (e.g. /owners/*/pets/{petId}).

除了URI模板外,@RequestMapping注解還支持Ant風格的路徑模式(如/myPath/*.do等)。不僅如此,還可以把URI模板變量和Ant風格的glob組合起來使用(比如/owners/*/pets/{petId}這樣的用法等)。

路徑樣式的匹配(Path Pattern Comparison)

[Original] When a URL matches multiple patterns, a sort is used to find the most specific match.

當一個URL同時匹配多個模板(pattern)時,我們將需要一個算法來決定其中最匹配的一個。

[Original] A pattern with a lower count of URI variables and wild cards is considered more specific. For example /hotels/{hotel}/* has 1 URI variable and 1 wild card and is considered more specific than /hotels/{hotel}/** which as 1 URI variable and 2 wild cards.

URI模板變量的數(shù)目和通配符數(shù)量的總和最少的那個路徑模板更準確。舉個例子,/hotels/{hotel}/*這個路徑擁有一個URI變量和一個通配符,而/hotels/{hotel}/**這個路徑則擁有一個URI變量和兩個通配符,因此,我們認為前者是更準確的路徑模板。

[Original] If two patterns have the same count, the one that is longer is considered more specific. For example /foo/bar* is longer and considered more specific than /foo/*.

如果兩個模板的URI模板數(shù)量和通配符數(shù)量總和一致,則路徑更長的那個模板更準確。舉個例子,/foo/bar*就被認為比/foo/*更準確,因為前者的路徑更長。

[Original] When two patterns have the same count and length, the pattern with fewer wild cards is considered more specific. For example /hotels/{hotel} is more specific than /hotels/*.

如果兩個模板的數(shù)量和長度均一致,則那個具有更少通配符的模板是更加準確的。比如,/hotels/{hotel}就比/hotels/*更精確。

[Original] There are also some additional special rules:

除此之外,還有一些其他的規(guī)則:

[Original] The default mapping pattern `/*is less specific than any other pattern. For example/api/{a}//{c}` is more specific.

[Original] prefix pattern such as `/public/*is less specific than any other pattern that doesn't contain double wildcards. For example/public/path3/{a}//{c}` is more specific.

  • 默認的通配模式/**比其他所有的模式都更“不準確”。比方說,/api/{a}//{c}就比默認的通配模式/**要更準確
  • 前綴通配(比如/public/**)被認為比其他任何不包括雙通配符的模式更不準確。比如說,/public/path3/{a}//{c}就比/public/**更準確

[Original] For the full details see AntPatternComparator in AntPathMatcher. Note that the PathMatcher can be customized (see Section 21.16.11, "Path Matching" in the section on configuring Spring MVC).

更多的細節(jié)請參考這兩個類:AntPatternComparatorAntPathMatcher。值得一提的是,PathMatcher類是可以配置的(見“配置Spring MVC”一節(jié)中的路徑的匹配一節(jié))。

帶占位符的路徑模式(path patterns)

[Original] Patterns in @RequestMapping annotations support ${…} placeholders against local properties and/or system properties and environment variables. This may be useful in cases where the path a controller is mapped to may need to be customized through configuration. For more information on placeholders, see the javadocs of the PropertyPlaceholderConfigurer class.

@RequestMapping注解支持在路徑中使用占位符,以取得一些本地配置、系統(tǒng)配置、環(huán)境變量等。這個特性有時很有用,比如說控制器的映射路徑需要通過配置來定制的場景。如果想了解更多關于占位符的信息,可以參考PropertyPlaceholderConfigurer這個類的文檔。

Suffix Pattern Matching

后綴模式匹配

[Original] By default Spring MVC performs ".*" suffix pattern matching so that a controller mapped to /person is also implicitly mapped to /person.*. This makes it easy to request different representations of a resource through the URL path (e.g. /person.pdf/person.xml).

Spring MVC默認采用".*"的后綴模式匹配來進行路徑匹配,因此,一個映射到/person路徑的控制器也會隱式地被映射到/person.*。這使得通過URL來請求同一資源文件的不同格式變得更簡單(比如/person.pdf,/person.xml)。

[Original] Suffix pattern matching can be turned off or restricted to a set of path extensions explicitly registered for content negotiation purposes. This is generally recommended to minimize ambiguity with common request mappings such as /person/{id} where a dot might not represent a file extension, e.g. /person/joe@email.com vs /person/joe@email.com.json). Furthermore as explained in the note below suffix pattern matching as well as content negotiation may be used in some circumstances to attempt malicious attacks and there are good reasons to restrict them meaningfully.

你可以關閉默認的后綴模式匹配,或者顯式地將路徑后綴限定到一些特定格式上for content negotiation purpose。我們推薦這樣做,這樣可以減少映射請求時可以帶來的一些二義性,比如請求以下路徑/person/{id}時,路徑中的點號后面帶的可能不是描述內(nèi)容格式,比如/person/joe@email.com vs /person/joe@email.com.json。而且正如下面馬上要提到的,后綴模式通配以及內(nèi)容協(xié)商有時可能會被黑客用來進行攻擊,因此,對后綴通配進行有意義的限定是有好處的。

[Original] See Section 21.16.11, "Path Matching" for suffix pattern matching configuration and also Section 21.16.6, "Content Negotiation" for content negotiation configuration.

關于后綴模式匹配的配置問題,可以參考Spring MVC路徑匹配配置;關于內(nèi)容協(xié)商的配置問題,可以參考Spring MVC 內(nèi)容協(xié)商"的內(nèi)容。

后綴模式匹配與RFD

[Original] Reflected file download (RFD) attack was first described in a paper by Trustwave in 2014. The attack is similar to XSS in that it relies on input (e.g. query parameter, URI variable) being reflected in the response. However instead of inserting JavaScript into HTML, an RFD attack relies on the browser switching to perform a download and treating the response as an executable script if double-clicked based on the file extension (e.g. .bat, .cmd).

RFD(Reflected file download)攻擊最先是2014年在Trustwave的一篇論文中被提出的。它與XSS攻擊有些相似,因為這種攻擊方式也依賴于某些特征,即需要你的輸入(比如查詢參數(shù),URI變量等)等也在輸出(response)中以某種形式出現(xiàn)。不同的是,RFD攻擊并不是通過在HTML中寫入JavaScript代碼進行,而是依賴于瀏覽器來跳轉(zhuǎn)到下載頁面,并把特定格式(比如.bat,.cmd等)的response當成是可執(zhí)行腳本,雙擊它就會執(zhí)行。

[Original] In Spring MVC @ResponseBody and ResponseEntity methods are at risk because they can render different content types which clients can request including via URL path extensions. Note however that neither disabling suffix pattern matching nor disabling the use of path extensions for content negotiation purposes alone are effective at preventing RFD attacks.

Spring MVC的@ResponseBodyResponseEntity方法是有風險的,因為它們會根據(jù)客戶的請求——包括URL的路徑后綴,來渲染不同的內(nèi)容類型。因此,禁用后綴模式匹配或者禁用僅為內(nèi)容協(xié)商開啟的路徑文件后綴名攜帶,都是防范RFD攻擊的有效方式。

[Original] For comprehensive protection against RFD, prior to rendering the response body Spring MVC adds a Content-Disposition:inline;filename=f.txt header to suggest a fixed and safe download file filename. This is done only if the URL path contains a file extension that is neither whitelisted nor explicitly registered for content negotiation purposes. However it may potentially have side effects when URLs are typed directly into a browser.

若要開啟對RFD更高級的保護模式,可以在Spring MVC渲染開始請求正文之前,在請求頭中增加一行配置Content-Disposition:inline;filename=f.txt,指定固定的下載文件的文件名。這僅在URL路徑中包含了一個文件符合以下特征的拓展名時適用:該擴展名既不在信任列表(白名單)中,也沒有被顯式地被注冊于內(nèi)容協(xié)商時使用。并且這種做法還可以有一些副作用,比如,當URL是通過瀏覽器手動輸入的時候。

[Original] Many common path extensions are whitelisted by default. Furthermore REST API calls are typically not meant to be used as URLs directly in browsers. Nevertheless applications that use custom HttpMessageConverter implementations can explicitly register file extensions for content negotiation and the Content-Disposition header will not be added for such extensions. See Section 21.16.6, "Content Negotiation".

很多常用的路徑文件后綴默認是被信任的。另外,REST的API一般是不應該直接用做URL的。不過,你可以自己定制HttpMessageConverter的實現(xiàn),然后顯式地注冊用于內(nèi)容協(xié)商的文件類型,這種情形下Content-Disposition頭將不會被加入到請求頭中。詳見Spring MVC 內(nèi)容協(xié)商。

[Original] This was originally introduced as part of work for CVE-2015-5211. Below are additional recommendations from the report:

  • Encode rather than escape JSON responses. This is also an OWASP XSS recommendation. For an example of how to do that with Spring see spring-jackson-owasp.
  • Configure suffix pattern matching to be turned off or restricted to explicitly registered suffixes only.
  • Configure content negotiation with the properties "useJaf" and "ignoreUnknownPathExtensions" set to false which would result in a 406 response for URLs with unknown extensions. Note however that this may not be an option if URLs are naturally expected to have a dot towards the end.
  • Add X-Content-Type-Options: nosniff header to responses. Spring Security 4 does this by default.

感覺這節(jié)的翻譯質(zhì)量還有限,需要繼續(xù)了解XSS攻擊和RFD攻擊的細節(jié)再翻。

矩陣變量

[Original] The URI specification RFC 3986 defines the possibility of including name-value pairs within path segments. There is no specific term used in the spec. The general "URI path parameters" could be applied although the more unique "Matrix URIs", originating from an old post by Tim Berners-Lee, is also frequently used and fairly well known. Within Spring MVC these are referred to as matrix variables.

原來的URI規(guī)范RFC 3986中允許在路徑段落中攜帶鍵值對,但規(guī)范沒有明確給這樣的鍵值對定義術語。有人叫“URI路徑參數(shù)”,也有叫“矩陣URI”的。后者是Tim Berners-Lee首先在其博客中提到的術語,被使用得要更加頻繁一些,知名度也更高些。而在Spring MVC中,我們稱這樣的鍵值對為矩陣變量。

[Original] Matrix variables can appear in any path segment, each matrix variable separated with a ";" (semicolon). For example: "/cars;color=red;year=2012". Multiple values may be either "," (comma) separated "color=red,green,blue" or the variable name may be repeated "color=red;color=green;color=blue".

矩陣變量可以在任何路徑段落中出現(xiàn),每對矩陣變量之間使用一個分號“;”隔開。比如這樣的URI:"/cars;color=red;year=2012"。多個值可以用逗號隔開"color=red,green,blue",或者重復變量名多次"color=red;color=green;color=blue"。

[Original] If a URL is expected to contain matrix variables, the request mapping pattern must represent them with a URI template. This ensures the request can be matched correctly regardless of whether matrix variables are present or not and in what order they are provided.

如果一個URL有可能需要包含矩陣變量,那么在請求路徑的映射配置上就需要使用URI模板來體現(xiàn)這一點。這樣才能確保請求可以被正確地映射,而不管矩陣變量在URI中是否出現(xiàn)、出現(xiàn)的次序是怎樣等。

[Original] Below is an example of extracting the matrix variable "q":

下面是一個例子,展示了我們?nèi)绾螐木仃囎兞恐蝎@取到變量“q”的值:

// GET /pets/42;q=11;r=22

@RequestMapping(path = "/pets/{petId}", method = RequestMethod.GET)
public void findPet(@PathVariable String petId, @MatrixVariable int q) {

    // petId == 42
    // q == 11

}

[Original] Since all path segments may contain matrix variables, in some cases you need to be more specific to identify where the variable is expected to be:

由于任意路徑段落中都可以含有矩陣變量,在某些場景下,你需要用更精確的信息來指定一個矩陣變量的位置:

// GET /owners/42;q=11/pets/21;q=22

@RequestMapping(path = "/owners/{ownerId}/pets/{petId}", method = RequestMethod.GET)
public void findPet(
    @MatrixVariable(name="q", pathVar="ownerId") int q1,
    @MatrixVariable(name="q", pathVar="petId") int q2) {

    // q1 == 11
    // q2 == 22

}

[Original] A matrix variable may be defined as optional and a default value specified:

你也可以聲明一個矩陣變量不是必須出現(xiàn)的,并給它賦一個默認值:

// GET /pets/42

@RequestMapping(path = "/pets/{petId}", method = RequestMethod.GET)
public void findPet(@MatrixVariable(required=false, defaultValue="1") int q) {

    // q == 1

}

[Original] All matrix variables may be obtained in a Map:

也可以通過一個Map來存儲所有的矩陣變量:

// GET /owners/42;q=11;r=12/pets/21;q=22;s=23

@RequestMapping(path = "/owners/{ownerId}/pets/{petId}", method = RequestMethod.GET)
public void findPet(
    @MatrixVariable Map<String, String> matrixVars,
    @MatrixVariable(pathVar="petId") Map<String, String> petMatrixVars) {

    // matrixVars: ["q" : [11,22], "r" : 12, "s" : 23]
    // petMatrixVars: ["q" : 11, "s" : 23]

}

[Original] Note that to enable the use of matrix variables, you must set the removeSemicolonContentproperty of RequestMappingHandlerMapping to false. By default it is set to true.

如果要允許矩陣變量的使用,你必須把RequestMappingHandlerMapping類的removeSemicolonContent屬性設置為false。該值默認是true的。

[Original] The MVC Java config and the MVC namespace both provide options for enabling the use of matrix variables.

MVC的Java編程配置和命名空間配置都提供了啟用矩陣變量的方式。

[Original] If you are using Java config, The Advanced Customizations with MVC Java Config section describes how the RequestMappingHandlerMapping can be customized.

如果你是使用Java編程的方式,“MVC Java高級定制化配置”一節(jié)描述了如何對RequestMappingHandlerMapping進行定制。

[Original] In the MVC namespace, the <mvc:annotation-driven> element has an enable-matrix-variables attribute that should be set to true. By default it is set to false.

而使用MVC的命名空間配置時,你可以把<mvc:annotation-driven>元素下的enable-matrix-variables屬性設置為true。該值默認情況下是配置為false的。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <mvc:annotation-driven enable-matrix-variables="true"/>

</beans>

可消費的媒體類型

[Original] You can narrow the primary mapping by specifying a list of consumable media types. The request will be matched only if the Content-Type request header matches the specified media type. For example:

你可以指定一組可消費的媒體類型,縮小映射的范圍。這樣只有當請求頭中 Content-Type 的值與指定可消費的媒體類型中有相同的時候,請求才會被匹配。比如下面這個例子:

@Controller
@RequestMapping(path = "/pets", method = RequestMethod.POST, consumes="application/json")
public void addPet(@RequestBody Pet pet, Model model) {
    // 方法實現(xiàn)省略
}

[Original] Consumable media type expressions can also be negated as in !text/plain to match to all requests other than those with Content-Type of text/plain. Also consider using constants provided in MediaType such as APPLICATION_JSON_VALUE and APPLICATION_JSON_UTF8_VALUE.

指定可消費媒體類型的表達式中還可以使用否定,比如,可以使用 !text/plain 來匹配所有請求頭 Content-Type 中不含 text/plain 的請求。同時,在MediaType類中還定義了一些常量,比如APPLICATION_JSON_VALUE、APPLICATION_JSON_UTF8_VALUE等,推薦更多地使用它們。

[Original] The consumes condition is supported on the type and on the method level. Unlike most other conditions, when used at the type level, method-level consumable types override rather than extend type-level consumable types.

consumes 屬性提供的是方法級的類型支持。與其他屬性不同,當在類型級使用時,方法級的消費類型將覆蓋類型級的配置,而非繼承關系。

可生產(chǎn)的媒體類型

[Original] You can narrow the primary mapping by specifying a list of producible media types. The request will be matched only if the Accept request header matches one of these values. Furthermore, use of the produces condition ensures the actual content type used to generate the response respects the media types specified in the produces condition. For example:

你可以指定一組可生產(chǎn)的媒體類型,縮小映射的范圍。這樣只有當請求頭中 Accept 的值與指定可生產(chǎn)的媒體類型中有相同的時候,請求才會被匹配。而且,使用 produces 條件可以確保用于生成響應(response)的內(nèi)容與指定的可生產(chǎn)的媒體類型是相同的。舉個例子:

@Controller
@RequestMapping(path = "/pets/{petId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
public Pet getPet(@PathVariable String petId, Model model) {
    // 方法實現(xiàn)省略
}

[Original] Be aware that the media type specified in the produces condition can also optionally specify a character set. For example, in the code snippet above we specify the same media type than the default one configured in MappingJackson2HttpMessageConverter, including the UTF-8charset.

要注意的是,通過 condition 條件指定的媒體類型也可以指定字符集。比如在上面的小段代碼中,我們還是覆寫了MappingJackson2HttpMessageConverter類中默認配置的媒體類型,同時,還指定了使用UTF-8的字符集。

[Original] Just like with consumes, producible media type expressions can be negated as in !text/plain to match to all requests other than those with an Accept header value of text/plain. Also consider using constants provided in MediaType such as APPLICATION_JSON_VALUE and APPLICATION_JSON_UTF8_VALUE.

與 consumes 條件類似,可生產(chǎn)的媒體類型表達式也可以使用否定。比如,可以使用 !text/plain 來匹配所有請求頭 Accept 中不含 text/plain 的請求。同時,在MediaType類中還定義了一些常量,比如APPLICATION_JSON_VALUEAPPLICATION_JSON_UTF8_VALUE等,推薦更多地使用它們。

[Original] The produces condition is supported on the type and on the method level. Unlike most other conditions, when used at the type level, method-level producible types override rather than extend type-level producible types.

produces 屬性提供的是方法級的類型支持。與其他屬性不同,當在類型級使用時,方法級的消費類型將覆蓋類型級的配置,而非繼承關系。

請求參數(shù)與請求頭的值

[Original] You can narrow request matching through request parameter conditions such as "myParam""!myParam", or "myParam=myValue". The first two test for request parameter presence/absence and the third for a specific parameter value. Here is an example with a request parameter value condition:

你可以篩選請求參數(shù)的條件來縮小請求匹配范圍,比如"myParam"、"!myParam""myParam=myValue"等。前兩個條件用于篩選存在/不存在某些請求參數(shù)的請求,第三個條件篩選具有特定參數(shù)值的請求。下面有個例子,展示了如何使用請求參數(shù)值的篩選條件:

@Controller
@RequestMapping("/owners/{ownerId}")
public class RelativePathUriTemplateController {

    @RequestMapping(path = "/pets/{petId}", method = RequestMethod.GET, params="myParam=myValue")
    public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
        // 實際實現(xiàn)省略
    }

}

[Original] The same can be done to test for request header presence/absence or to match based on a specific request header value:

同樣,你可以用相同的條件來篩選請求頭的出現(xiàn)與否,或者篩選出一個具有特定值的請求頭:

@Controller
@RequestMapping("/owners/{ownerId}")
public class RelativePathUriTemplateController {

    @RequestMapping(path = "/pets", method = RequestMethod.GET, headers="myHeader=myValue")
    public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
        // 方法體實現(xiàn)省略
    }

}

[Original] Although you can match to Content-Type and Accept header values using media type wild cards (for example "content-type=text/*" will match to "text/plain" and "text/html"), it is recommended to use the consumes and produces conditions respectively instead. They are intended specifically for that purpose.

盡管,你可以使用媒體類型的通配符(比如 "content-type=text/*")來匹配請求頭 Content-Type和 Accept的值,但我們更推薦獨立使用 consumes和 produces條件來篩選各自的請求。因為它們就是專門為區(qū)分這兩種不同的場景而生的。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號