在 SpringMVC 中,提交請求的數據是通過方法形參來接收的。從客戶端請求的 key/value 數據,經過參數綁定,將 key/value 數據綁定到 Controller 的形參上,然后在 Controller 就可以直接使用該形參。
一、類型支持
1、默認支持類型
SpringMVC 有支持的默認參數類型,我們直接在形參上給出這些默認類型的聲明,就能直接使用了。
HttpServletRequest 對象
HttpServletResponse 對象
HttpSession 對象
Model/ModelMap 對象
@RequestMapping("/defaultParameter") public ModelAndView defaultParameter(HttpServletRequest request,HttpServletResponse response, HttpSession session,Model model,ModelMap modelMap) throws Exception{return null; }
2、基本數據類型
1、byte,占用一個字節,取值范圍為 -128-127,默認是“\u0000”,表示空 2、short,占用兩個字節,取值范圍為 -32768-32767 3、int,占用四個字節,-2147483648-2147483647 4、long,占用八個字節,對 long 型變量賦值時必須加上"L"或“l”,否則不認為是 long 型 5、float,占用四個字節,對 float 型進行賦值的時候必須加上“F”或“f”,如果不加,會產生編譯錯誤,因為系統自動將其定義為 double 型變量。double轉換為float類型數據會損失精度。
float a = 12.23產生編譯錯誤的,float a = 12是正確的 6、double,占用八個字節,對 double 型變量賦值的時候最好加上“D”或“d”,但加不加不是硬性規定 7、char,占用兩個字節,在定義字符型變量時,要用單引號括起來 8、boolean,只有兩個值“true”和“false”,默認值為false,不能用0或非0來代替,這點和C語言不同
@RequestMapping(value = {"/card"}, method = RequestMethod.GET) public TravelCard getTravelCard(@RequestParam("amount") long amount) { return null; }
3、包裝數據類型的綁定
包裝類型如Integer、Long、Byte、Double、Float、Short,(String 類型在這也是適用的)。
建議所有的參數都用包裝類型,別用原始類型,因為無法將null轉換為原始類型,入參不傳遞此參數時則會報錯。
@RequestMapping(value = {"/card"}, method = RequestMethod.GET) public TravelCard getTravelCard(@RequestParam("amount") Integer amount) { return null; }
4、POJO(實體類)類型的綁定
@RequestMapping(value = {"/passenger"}, method = RequestMethod.POST) public long insertOne(@RequestBody Passenger passenger) { LOGGER.info("Get a request for insertPassenger(POST)."); return this.passengerService.insertOne(passenger); }
二、@RequestMapping注解屬性
RequestMapping是一個用來處理請求地址映射的注解,可用於類或方法上。用於類上,表示類中的所有響應請求的方法都是以該地址作為父路徑。RequestMapping注解有六個屬性,下面我們把她分成三類進行說明。
1、value, method;
value:指定請求的實際地址,指定的地址可以是URI Template 模式(后面將會說明);當只設置value一個屬性時,value可以省略不寫,當有其他屬性時則需要加上進行區分。
method:指定請求的method類型, GET、POST、PUT、DELETE等;
@RequestMapping("/v1/metro") public class PassengerController { } @RequestMapping(value = {"/travel"}, method = RequestMethod.POST) public Map travel(@RequestParam long passengerId, @RequestParam long startStation, @RequestParam long endStation, @RequestParam int cardType) {return null; }
value的uri值為以下三類:
A) 可以指定為普通的具體值;
B) 可以指定為含有某變量的一類值(URI Template Patterns with Path Variables);
C) 可以指定為含正則表達式的一類值( URI Template Patterns with Regular Expressions);
example B)
@RequestMapping(value = {"/travel/{passengerId}"}, method = RequestMethod.GET) public List<TravelRecord> queryTravelRecords(@PathVariable("passengerId") long passengerId) {return null; }
example C)
@RequestMapping("/spring-web/{symbolicName:[a-z-]+}-{version:\d\.\d\.\d}.{extension:\.[a-z]}") public void handle(@PathVariable String version, @PathVariable String extension) { // ... }
2、consumes,produces;
consumes:指定處理請求的提交內容類型(Content-Type),例如application/json, text/html;
@Controller @RequestMapping(value = "/pets", method = RequestMethod.POST, consumes="application/json") public void addPet(@RequestBody Pet pet, Model model) { // implementation omitted }
方法僅處理request的Content-Type為“application/json”類型的請求。
produces:指定返回的內容類型,僅當request請求頭中的(Accept)類型中包含該指定類型才返回;
@Controller @RequestMapping(value = "/pets/{petId}", method = RequestMethod.GET, produces="application/json") @ResponseBody public Pet getPet(@PathVariable String petId, Model model) { // implementation omitted }
方法僅處理request請求中Accept頭中包含了"application/json"的請求,同時暗示了返回的內容類型為application/json;
3、params,headers;
params:指定request中必須包含某些參數值是,才讓該方法處理。
@Controller @RequestMapping("/owners/{ownerId}") public class RelativePathUriTemplateController { @RequestMapping(value = "/pets/{petId}", method = RequestMethod.GET, params="myParam=myValue") public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) { // implementation omitted } }
僅處理請求中包含了名為“myParam”,值為“myValue”的請求;
headers:指定request中必須包含某些指定的header值,才能讓該方法處理請求。
@Controller @RequestMapping("/owners/{ownerId}") public class RelativePathUriTemplateController { @RequestMapping(value = "/pets", method = RequestMethod.GET, headers="Referer=http://www.ifeng.com/") public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) { // implementation omitted } }
僅處理request的header中包含了指定“Refer”請求頭和對應值為“http://www.ifeng.com/”的請求;
三、參數綁定
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 樣式映射時, 即 someUrl/{paramId}, 這時的paramId可通過 @Pathvariable注解綁定它傳過來的值到方法的參數上。
@RequestMapping(value = {"/travel/{passengerId}"}, method = RequestMethod.GET) public List<TravelRecord> queryTravelRecords(@PathVariable("passengerId") long passengerId) { return null; }
若方法參數名稱和需要綁定的uri template中變量名稱不一致,需要在@PathVariable("name")指定uri template中的名稱。
2、 @RequestHeader、@CookieValue
@RequestHeader 注解,可以把Request請求header部分的值綁定到方法的參數上。
一個Request 的header部分:
Host localhost:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9 Accept-Language fr,en-gb;q=0.7,en;q=0.3 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive 300
@RequestMapping("/displayHeaderInfo.do") public void displayHeaderInfo(@RequestHeader("Accept-Encoding") String encoding, @RequestHeader("Keep-Alive") long keepAlive) { //... }
@CookieValue 可以把Request header中關於cookie的值綁定到方法的參數上。
有如下Cookie值:
@RequestMapping("/displayHeaderInfo.do") public void displayHeaderInfo(@CookieValue("JSESSIONID") String cookie) { //... }
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) 該注解有3個屬性: value、required、defaultValue; value用來指定要傳入值的id名稱(改變參數名字),required用來指示參數是否必須綁定,defaultValue用於對參數設置默認值,required為true時,如果參數為空,會報錯,但是當required=true,和defaultValue= 同時出現時,required失效,可傳可不傳;
@RequestMapping(value = {"/travel"}, method = RequestMethod.POST) public Map travel(@RequestParam(defaultValue = 1) long passengerId, @RequestParam long startStation, @RequestParam long endStation, @RequestParam(value="card") int cardType) { return null; }
@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;
@RequestMapping(value = "/something", method = RequestMethod.PUT) public void handle(@RequestBody String body, Writer writer) throws IOException { writer.write(body); }
因為@RequestBody是將post請求中content值轉為一個整體對象。@RequestBody的解析有兩個條件:
1. POST請求中content的值必須為json格式(存儲形式可以是字符串,也可以是byte數組);
2. @RequestBody注解的參數類型必須是完全可以接收參數值的類型,比如:Map,JSONObject,或者對應的JavaBean;所以Integer等類型不能作為@RequestBody注解的參數類型。
4、@SessionAttributes, @ModelAttribute
@SessionAttributes:
該注解用來綁定HttpSession中的attribute對象的值,便於在方法中的參數里使用。
該注解有value、types兩個屬性,可以通過名字和類型指定要使用的attribute 對象;
@Controller @RequestMapping("/editPet.do") @SessionAttributes("pet") public class EditPetForm { // ... }
@ModelAttribute
該注解有兩個用法,一個是用於方法上,一個是用於參數上;
用於方法上時: 通常用來在處理@RequestMapping之前,為請求綁定需要從后台查詢的model;
用於參數上時: 用來通過名稱對應,把相應名稱的值綁定到注解的參數bean上;要綁定的值來源於:
A) @SessionAttributes 啟用的attribute 對象上;
B) @ModelAttribute 用於方法上時指定的model對象;
C) 上述兩種情況都沒有時,new一個需要綁定的bean對象,然后把request中按名稱對應的方式把值綁定到bean中。
用到方法上@ModelAttribute的示例代碼:
// Add one attribute // The return value of the method is added to the model under the name "account" // You can customize the name via @ModelAttribute("myAccount") @ModelAttribute public Account addAccount(@RequestParam String number) { return accountManager.findAccount(number); }
這種方式實際的效果就是在調用@RequestMapping的方法之前,為request對象的model里put(“account”, Account);
用在參數上的@ModelAttribute示例代碼:
@RequestMapping(value="/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST)
public String processSubmit(@ModelAttribute Pet pet) {
}
首先查詢 @SessionAttributes有無綁定的Pet對象,若沒有則查詢@ModelAttribute方法層面上是否綁定了Pet對象,若沒有則將URI template中的值按對應的名稱綁定到Pet對象的各屬性上。
四、RequestBody、ResponseBody比較
@RequestBody
作用:
i) 該注解用於讀取Request請求的body部分數據,使用系統默認配置的HttpMessageConverter進行解析,然后把相應的數據綁定到要返回的對象上;
ii) 再把HttpMessageConverter返回的對象數據綁定到 controller中方法的參數上。
使用時機:
A) GET、POST方式提時, 根據request header Content-Type的值來判斷:
application/x-www-form-urlencoded, 可選(即非必須,因為這種情況的數據@RequestParam, @ModelAttribute也可以處理,當然@RequestBody也能處理);
multipart/form-data, 不能處理(即使用@RequestBody不能處理這種格式的數據);
其他格式, 必須(其他格式包括application/json, application/xml等。這些格式的數據,必須使用@RequestBody來處理);
B) PUT方式提交時, 根據request header Content-Type的值來判斷:
application/x-www-form-urlencoded, 必須;
multipart/form-data, 不能處理;
其他格式, 必須;
說明:request的body部分的數據編碼格式由header部分的Content-Type指定;
@ResponseBody
作用:
該注解用於將Controller的方法返回的對象,通過適當的HttpMessageConverter轉換為指定格式后,寫入到Response對象的body數據區。
使用時機:
返回的數據不是html標簽的頁面,而是其他某種格式的數據時(如json、xml等)使用;