SpringMVC基礎——參數擷取與Servlet資源擷取問題,springmvcservlet

來源:互聯網
上載者:User

SpringMVC基礎——參數擷取與Servlet資源擷取問題,springmvcservlet

一、SpringMVC 使用 @PathVariable、@RequestParam、@RequestHeader、@CookieValue 等來解決參數擷取問題。

1. @PathVariable:映射 URL 綁定的預留位置,可以藉助於傳入到方法參數列表中的 @PathVariable 註解擷取到 URL 對應中的參數值。如:

<a href="handler01/1">test pathvariable</a>
@RequestMapping("/handler01/{id}")public String testPathVariable(@PathVariable("id") String id) {  System.out.println("id:" + id);  return "success";}

說明:URL 綁定預留位置使 SpringMVC 對 REST 提供了支援。對於具體的 SpringMVC 的 REST 風格的例子會在以後的文章裡介紹。

2.@RequestParam 

官方文檔是這樣描述的:

* Annotation which indicates that a method parameter should be bound to a web
* request parameter. Supported for annotated handler methods in Servlet and
* Portlet environments.
*
* <p>If the method parameter type is {@link Map} and a request parameter name
* is specified, then the request parameter value is converted to a {@link Map}
* assuming an appropriate conversion strategy is available.
*
* <p>If the method parameter is {@link java.util.Map Map&lt;String, String&gt;} or
* {@link org.springframework.util.MultiValueMap MultiValueMap&lt;String, String&gt;}
* and a parameter name is not specified, then the map parameter is populated
* with all request parameter names and values.

 



 

 

 

 

 

 

說明一下:

(1)該註解表明 web 請求參數綁定到目標 handler 方法的入參。

(2)如果方法的入參類型是一個 Map,不包含泛型型別,並且請求參數名稱是被指定的

(如:public String testRequestParam5(@RequestParam("userName") Map map)),請求參數會被轉換為一個 Map,前提是存在轉換策略。

這裡所說的轉換策略,通常是指 請求參數 到 Map 的類型轉換,如請求參數為 userName=a|12,b|34 這樣的資料,需要通過一個轉換策略(類型轉換器)

來完成 a|12,b|34 到 map 的轉換。在我們一般開發的過程中,不包含這種情況。是一種擴充。關於類型轉換會在後面的文章中介紹。

(3)如果方法的入參是一個 Map 且指定了泛型型別 Map<String,String> 或者是 org.springframework.util.MultiValueMap 類型的 MultiValueMap<String, String>

並且沒有指定請求參數,那麼這個 Map 類型的參數會將所有的請求參數名稱和值填充(populate)到其中。

如:

請求:<a href="testRequestParam4?userName=jack&age=23">test request param4</a>

handler 方法:

@RequestMapping("/testRequestParam4")public String testRequestParam4(@RequestParam Map<String, String> map) {  System.out.println("map:" + map);  return "success";}

控制台輸出:

map:{userName=jack, age=23}

上面整體介紹了 @RequestParam,下面詳細看看它的API:

包含三個屬性:

(1)value 屬性,預設為 ""

官方文檔說明:

The name of the request parameter to bind to.

解釋的已經很明白了,不再贅述。

(2)required 屬性,預設為 true

官方文檔說明:Whether the parameter is required.

見名知意,該請求參數是否是必須的。為 true 的請求下,若請求參數中沒有,則會拋出一個異常。為 false 的情況下,如果請求參數中沒有,則方法入參對應值為 null。

另外,提供一個 defaultValue 屬性,則會是此屬性設定為 false。

(3)defaultValue 屬性

當沒有提供對應的請求參數,或者請求參數為空白時,會使用此屬性對應的值。當設定此屬性的時候,會將 required 屬性設定為 false。

下面提供幾個常見請求情況的例子:

(1)請求為:<a href="testRequestParam?userName=abc">test request param</a> 

handler 方法:

@RequestMapping("/testRequestParam")public String testRequstParam01(@RequestParam("userName") String userName) {  System.out.println("userName: " + userName);  return "success";}

(2)請求為:<a href="testRequestParam2?userName=jack&userName=lucy">test request param2</a>

handler 方法:

@RequestMapping("/testRequestParam2")public String testRequestParam02(@RequestParam("userName") List<String> userNames) {  System.out.println("userNames:" + userNames);  return "success";}

控制台輸出:

userNames:[jack, lucy]

(3)請求為:<a href="testRequestParam4?userName=jack&age=23">test request param4</a>

handler 方法:

@RequestMapping("/testRequestParam4")public String testRequestParam4(@RequestParam Map<String, String> map) {  System.out.println("map:" + map);  return "success";}

控制台輸出:

map:{userName=jack, age=23}

主要就分為這三種情況,其中第一種最為常用,第二種和第三種很少能想到,若能想到的話,能為我們開發節省不少時間。

3.@RequestHeader

官方文檔中是這樣描述的:

Annotation which indicates that a method parameter should be bound to a web request header.
Supported for annotated handler methods in Servlet and Portlet environments.

 

 

和 @RequestParam 描述類似,只不過綁定的是 web 要求標頭資訊到方法入參。

定義的三個屬性和 @RequestParam 一樣,預設值和使用的方法也一樣。由於用的比較少,這裡只做一個例子說明:

請求:<a href="testRequestHeader">test request header</a>

handler 方法:

@RequestMapping("/testRequestHeader")public String testRequestHeader(@RequestHeader(value = "Accept", required = false) String accept) {  System.out.println("accept:" + accept);  return "success";}

控制台輸出:

accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8

4.@CookieValue

官方文檔描述:

Annotation which indicates that a method parameter should be bound to an HTTP cookie.
Supported for annotated handler methods in Servlet and Portlet environments.

 

 

綁定一個 http cookie 到方法的入參,其中 value 屬性工作表明要入參的 cookie 的 key。

預設值和使用方式和 @RequestParam 類似。

例子:

請求:<a href="testCookieValue">test cookie value</a>

handler 方法:

@RequestMapping("/testCookieValue")public String testCookieValue(@CookieValue(value = "JSESSIONID", required = false) String sessionId) {  System.out.println("sessionId:"+sessionId);  return "success";}

控制台輸出:

sessionId:9D16BDF7063E1BFD9A0C052F1B109A0D

5.綁定請求參數到方法入參處的 bean 對象。

先看兩個例子:

(1)綁定請求參數到 bean 

請求:包括 get 和 post 請求方式提交的情況。

<a href="testBean?personName=jack&age=23">test bean</a><form action="testBean" method="post">  <label>    personName:<input type="text" name="personName"/>  </label>  <label>    age:<input type="text" name="age"/>  </label>  <input type="submit" value="submit"/></form>

handler 方法:

@RequestMapping("/testBean")public String testBean(Person person) {  System.out.println(person);//Person{personName='jack', age='23'}  return "success";}

發現不論是通過 get 方式,還是post 方式,都可以將對應的請求參數注入到對應的 bean 中。

(2)綁定請求參數到級聯的 bean

bean 的結構:

/** * @author solverpeng * @create 2016-08-04-9:43 */public class Employee { private String empName; private Address address; public String getEmpName() { return empName; } public void setEmpName(String empName) { this.empName = empName; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } @Override public String toString() { return "Employee{" + "empName='" + empName + '\'' + ", address=" + address + '}'; }}Employee /** * @author solverpeng * @create 2016-08-04-9:43 */public class Address { private String addressName; public String getAddressName() { return addressName; } public void setAddressName(String addressName) { this.addressName = addressName; } @Override public String toString() { return "Address{" + "addressName='" + addressName + '\'' + '}'; }}Address

請求:同樣包含 get 請求 和 post 請求

<a href="testBeanCascade?empName=jack&address.addressName=beijing">test bean cascade</a><form action="testBeanCascade" method="post">    <label>        empName:<input type="text" name="empName"/>    </label>    <label>        Address:<input type="text" name="address.addressName"/>    </label>    <input type="submit" value="submit"/></form>    

handler 方法:

@RequestMapping("/testBeanCascade")public String testBeanCascade(Employee employee) {  System.out.println(employee);//Employee{empName='jack', address=Address{addressName='beijing'}}  return "success";}

是如何綁定的呢?翻源碼過程如下:

org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter#invokeHandlerMethod

ExtendedModelMap implicitModel = new BindingAwareModelMap();
Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);

第一步:發現在 result 中已經包含了注入的 bean。所以注入是在methodInvoker.invokeHandlerMethod() 方法中做的。


第二步:org.springframework.web.bind.annotation.support.HandlerMethodInvoker#invokeHandlerMethod
Object[] args = resolveHandlerArguments(handlerMethodToInvoke, handler, webRequest, implicitModel);

第三步:org.springframework.web.bind.annotation.support.HandlerMethodInvoker#resolveHandlerArguments
doBind(binder, webRequest, validate, validationHints, !assignBindingResult);// 這裡進行的綁定

第四步:org.springframework.web.bind.ServletRequestDataBinder#bind
doBind(mpvs);

第五步:org.springframework.validation.DataBinder#doBind
this.applyPropertyValues(mpvs);

最終發現,是在 DataBinder 這個類的 doBind() 方法中進行的綁定。在翻源碼的過程中,發現 resolveHandlerArguments() 方法值得大家看一看,不論水平高低,

其實真正解決 SpringMVC 參數問題就是在這個方法中解決的。

總結一下:Spring MVC 會按請求參數名和 POJO 屬性名稱進行自動匹配,自動為該對象填充屬性值。支援級聯屬性。

二、SpringMVC 解決 Servlet 資源擷取問題

1. SpringMVC 使用 Servlet 資源作為方法的入參來解決 Servlet 資源擷取問題。

2.可以作為入參的 Servlet 資源有:HttpServletRequest、HttpServletResponse、HttpSession、Locale、InputStream、OutputStream、Reader、Writer

3.例子:

使用 HttpServletRequest 作為入參

請求:<a href="testServletAPI">test servlet api</a>

handler 方法:

@RequestMapping("/testServletAPI")public String testServletAPI(HttpServletRequest request) {  String id = request.getSession().getId();  System.out.println("sessionId:" + id);  return "success";}

控制台輸出:

sessionId:E369037AF3DC276BA78539F0AF5C044B

其他的 Servlet 資源這裡就不在贅述。

三、總結

SpringMVC 使用 @PathVariable 來擷取 @RequestMapping 中預留位置的值,為 REST 風格的程式的編寫提供了支援。使用 @RequestParam 能接收絕大部分請求參數,同時提供了類型

轉換這種擴充。使用 @RequestHeader 來映射要求標頭資訊。使用 @CookieValue 來映射 http cookie 資訊。同時還支援模型的注入。也可以擷取到原生的 servlet 資源。即在目標的方法處,

我們可以擷取到任何我們想要的資源,SpringMVC 對這個過程進行了簡化,使開發更加便捷,靈活。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.