[spring注解]Spring相關(guān)注解(一)

概述

??由于以前學(xué)習(xí)Spring的時(shí)候?qū)W習(xí)的不太系統(tǒng)进栽,所以通過(guò)本篇及以下幾篇文章來(lái)重新梳理下Spring中常用注解的使用德挣,從而加深對(duì)Spring注解的理解,本篇文章來(lái)看下Spring-web中常用的一些注解快毛。

  1. 本系列學(xué)習(xí)的Spring版本是:4.3.14格嗅,工程基于全注解的實(shí)現(xiàn)。
  2. 強(qiáng)烈建議學(xué)習(xí)的時(shí)候先看官網(wǎng)文檔:https://docs.spring.io/spring/docs/4.3.14.RELEASE/spring-framework-reference/html/mvc.html
  3. 本篇注解包括:RequestParam唠帝,PathVariable屯掖,RequestBodyResponseBody襟衰,RestController贴铜,InitBinderRequestMappingGetMapping绍坝,ControllerAdvice徘意,RestControllerAdviceExceptionHandler轩褐,ModelAttribute椎咧。
1. RequestParam注解

通常在Spring-MVC后臺(tái)我們進(jìn)行獲取參數(shù)的時(shí)候,一種是通過(guò)request.getParameter()的方式來(lái)獲取方式把介,不過(guò)這種方式太古老了邑退;另一種方式就是通過(guò)注解的方式將參數(shù)匹配到對(duì)應(yīng)的對(duì)象上,而RequestParam注解則是其中的一種劳澄。我們來(lái)簡(jiǎn)單看下:

@GetMapping("/test.html")
@ResponseBody
public User test(@RequestParam(value = "user") String user) {
    return user;
}

然后我們?cè)谡?qǐng)求的時(shí)候可以通過(guò)表單傳值的形式傳遞參數(shù):localhost:8080/test.html?user=test地技;該注解一共有4個(gè)參數(shù):

  1. value,前端傳入的參數(shù)名稱秒拔,通過(guò)該名稱來(lái)綁定參數(shù)到相應(yīng)的對(duì)象上莫矗;
  2. name,和value參數(shù)功能一樣砂缩,是Spring4.2之后添加的作谚,目的么,應(yīng)該是為了代替原先value這個(gè)屬性不太直白的描述方式庵芭;
  3. required妹懒,該參數(shù)是否必須,默認(rèn)是true双吆,也就是必須要傳入眨唬,如果不傳入?yún)?shù)的話,會(huì)直接提示異常400好乐;
  4. defaultValue匾竿,如果沒(méi)有傳遞參數(shù),參數(shù)的默認(rèn)值蔚万。當(dāng)然岭妖,如果required=true的話,那該屬性就沒(méi)有意義了反璃。

該注解的一些注意事項(xiàng):

    1. 當(dāng)設(shè)置required=false昵慌,也就是可以不傳參數(shù)的時(shí)候,會(huì)給參數(shù)賦值為null淮蜈,這時(shí)候如果參數(shù)的類型是基本類型 int 等斋攀,則會(huì)直接報(bào)錯(cuò),所以定義參數(shù)的時(shí)候能優(yōu)先使用包裝類型就使用包裝類型礁芦;
    1. 一般情況下蜻韭,基于約定,如果方法的參數(shù)中沒(méi)有使用該注解柿扣,那么前端的參數(shù)將綁定到同名的查詢參數(shù)上肖方。因?yàn)锧RequestParam參數(shù)并不是必須的,這種情況下不傳遞參數(shù)也不會(huì)提示異常未状,和required=false的情況類似俯画。
    1. 該注解一般用于表單提交的方式,也就是用于Content-Typeapplication/x-www-form-urlencoded編碼的提交司草。

這里再多說(shuō)一句艰垂,在綁定參數(shù)的時(shí)候,如果要綁定的參數(shù)不是基礎(chǔ)類型而是對(duì)象的話埋虹,那么RequestParam是不支持的猜憎,這時(shí)候可以直接不使用該注解,采用默認(rèn)的匹配方式即可搔课。

(@RequestParam(value = "user", required = false, defaultValue = "test") User user)

如果要綁定數(shù)組的話胰柑,針對(duì)GET請(qǐng)求可以:

public String test(@RequestParam("ids") List<String> ids) {

請(qǐng)求路徑為:http://localhost:8080/world/test.html?ids=12,123,使用逗號(hào)進(jìn)行分割即可爬泥。

2. PathVariable注解

Spring MVC中用于將URL中的占位符{xxx}柬讨,綁定到控制器方法的參數(shù)上,該注解特別適用于REST的請(qǐng)求方式:

@GetMapping("/test.html/{user}")
@ResponseBody
public User test(@PathVariable("user") String user) {
}

該注解有三個(gè)參數(shù):

  1. value袍啡,URL中占位符的名稱踩官,通過(guò)該名稱來(lái)綁定對(duì)應(yīng)的參數(shù);
  2. name境输,同樣蔗牡,和value參數(shù)功能一樣,是Spring4.3.3之后添加的參數(shù)嗅剖,目的應(yīng)該也是用于代替原先value屬性不太直白的描述方式蛋逾;
  3. required,該參數(shù)表示是否必須窗悯,默認(rèn)是true区匣,也就是必須要傳入,如果不傳入?yún)?shù)的話蒋院,會(huì)直接提示異常亏钩。這個(gè)參數(shù)需要注意下,接下來(lái)我們來(lái)看下欺旧。

比如我們想我們的test方法同時(shí)匹配/test.html/test.html/{user}這兩個(gè)url姑丑,我們可能會(huì)直接按照如下的方式:

@GetMapping(value = "/test.html/{user}")
@ResponseBody
public String test(@PathVariable(name = "user", required = false) String user) {
    System.out.println(user);
}

??這種方式可以匹配/test.html/{user},但匹配不了/test.html辞友,提示404異常栅哀,因?yàn)槠ヅ涞臅r(shí)候根據(jù)默認(rèn)的Ant方式的AntPathMatcher匹配器震肮,這是兩個(gè)url,無(wú)法直接匹配留拾,那該如何實(shí)現(xiàn)呢戳晌?
??不過(guò),根據(jù)api對(duì)應(yīng)的文檔痴柔,我們能大致了解如何來(lái)解決這個(gè)問(wèn)題:

Whether the path variable is required.
Defaults to true, leading to an exception being thrown if the path variable is missing in the incoming request. Switch this to false if you prefer a null or Java 8 java.util.Optional in this case. e.g. on a ModelAttribute method which serves for different requests.

我們可以通過(guò)Java8中的Optional 來(lái)將該參數(shù)設(shè)置為可選的钳垮,但是我們的RequestMapping里必須要列出所有可能匹配的url

@GetMapping(value = {"/test.html/{user}", "/test.html"})
@ResponseBody
public String test(@PathVariable(name = "user") Optional<String> user) {
}

這種情況下叁丧,required=false并不是必須的煤蚌,也就是說(shuō)這時(shí)候該屬性不生效锯茄,這個(gè)時(shí)候就可以解決我們上面的這個(gè)問(wèn)題了。不過(guò)我們也可以不借助于java.util.Optional來(lái)解決這個(gè)問(wèn)題谈火,這個(gè)時(shí)候就需要借助參數(shù)required=false來(lái)實(shí)現(xiàn)了:

@GetMapping(value = {"/test.html/{user}", "/test.html"})
@ResponseBody
public String test(@PathVariable(name = "user", required = false) String user) {
}

其實(shí)和上面那種實(shí)現(xiàn)方式類似侈询,也就是直接參數(shù)匹配,不借助于Optional類糯耍,但這時(shí)候required就必須是false了妄荔。這里參考:https://stackoverflow.com/questions/47567364/optional-pathvariable-in-rest-controller-spring-4

這里需要注意下,這個(gè)特性是Spring4.3.3之后支持的谍肤。

下面再看簡(jiǎn)單說(shuō)下使用該注解需要注意的情況:

  1. PathVariable的參數(shù)可以是任何簡(jiǎn)單類型啦租,比如int,long荒揣,Date等等篷角,如果不是這些基礎(chǔ)類型,Spring會(huì)拋出TypeMismatchException異常系任,不過(guò)我們也可以自定義支持類型恳蹲;
  2. 由于是綁定URL中的參數(shù),所以就需要考慮URL中一些特殊的字符的處理俩滥,比如空格``嘉蕾,點(diǎn)號(hào).,問(wèn)號(hào)?霜旧,斜杠號(hào)/等错忱,當(dāng)我們進(jìn)行參數(shù)綁定的時(shí)候記得做相應(yīng)的處理。
  3. 由于URL畢竟是要暴露對(duì)外的挂据,所以要注意相應(yīng)的安全性以清,避免別人根據(jù)某一個(gè)參數(shù)可以推斷出另外的值,從而可能獲取到別人相關(guān)的數(shù)據(jù)崎逃,也就是需要注意下敏感數(shù)據(jù)與公共數(shù)據(jù)的問(wèn)題掷倔,其實(shí)這也是REST請(qǐng)求中要注意的問(wèn)題。
  4. 和上文說(shuō)的類似个绍,就是要考慮下使用場(chǎng)景問(wèn)題勒葱。
3. RequestBody注解

??該注解和RequestParam有點(diǎn)類似浪汪,同樣用于綁定參數(shù),但不是用于綁定表單提交的數(shù)據(jù)凛虽,也就是不是用于綁定Content-Typeapplication/x-www-form-urlencoded情況下的參數(shù)死遭,一般用于綁定Content-Typeapplication/jsonapplication/xml等類型的參數(shù)涩维。
??我們可以通過(guò)配置HttpMessageConverter來(lái)支持我們的Content-Type類型,一般情況下袁波,我們使用最多的是application/json這種格式的參數(shù)傳遞瓦阐,而在Spring中,默認(rèn)支持json傳遞對(duì)象的converter是MappingJackson2HttpMessageConverter篷牌。

該注解只有一個(gè)參數(shù):

required睡蟋,參數(shù)是否必需,默認(rèn)是true枷颊,Spring3.2版本引入戳杀。

@GetMapping(value = {"/test.html"})
@ResponseBody
public String test(@RequestBody(required = false) User user) {
}

Spring其實(shí)還默認(rèn)提供了多種HttpMessageConverter,比如StringHttpMessageConverter(Content-Typetext/plain)夭苗,MappingJackson2XmlHttpMessageConverter(Content-Typeapplication/xml信卡,text/xml)等,如果想了解更多题造,可以支持查看HttpMessageConverter的各個(gè)實(shí)現(xiàn)類傍菇。
有兩點(diǎn)可能需要注意下:

  1. 使用RequestBody的時(shí)候,注意參數(shù)名稱什么的要匹配界赔,如果傳入了一個(gè)后端對(duì)象里沒(méi)有的參數(shù)丢习,會(huì)直接提示參數(shù)不匹配400異常;
  2. 由于HttpMessageConverter有一個(gè)FormHttpMessageConverter的實(shí)現(xiàn)淮悼,所以說(shuō)RequestBody也是支持Content-Typeapplication/x-www-form-urlencoded的情況的咐低,只不過(guò)處理的結(jié)果放到了一個(gè)MultiValueMap<String, ?>中,不過(guò)這種情況并不常見(jiàn)袜腥,如果想了解更多的話见擦,可以查看下FormHttpMessageConverter的文檔,里面有詳細(xì)的說(shuō)明羹令。
4. ResponseBody注解

??該注解和RequestBody是對(duì)應(yīng)的锡宋,RequestBody是用于請(qǐng)求的時(shí)候傳遞相應(yīng)格式的數(shù)據(jù),而該注解則是響應(yīng)的時(shí)候返回相關(guān)格式的數(shù)據(jù)特恬。關(guān)于ResponseBody就不多說(shuō)了执俩,具體的配置相關(guān)的東西和RequestBody是一致的,因?yàn)檫@兩個(gè)注解是對(duì)應(yīng)的關(guān)系癌刽。

5. RestController注解

??Spring4.0之后引入的注解役首,是@Controller注解和@ResponseBody注解的結(jié)合尝丐。添加該注解后,表明這個(gè)類中的所有方法都將具有@ResponseBody的特性衡奥,也就是所有的返回試圖的方法都將直接返回字符串爹袁,而配置的試圖解析器也不會(huì)生效。
??其他的話矮固,功能和Controller一樣失息,參數(shù)也是只有value一個(gè)參數(shù)。

6. InitBinder注解

在Spring MVC中档址,我們經(jīng)常會(huì)涉及到表單中的日期字符串和JavaBean對(duì)象中的Date類型的轉(zhuǎn)換盹兢,而默認(rèn)情況下,Spring MVC是不支持這種格式轉(zhuǎn)換的守伸,這時(shí)候就需要使用@InitBinder注解來(lái)自定義轉(zhuǎn)換類型绎秒。

@InitBinder
public void initBinder(WebDataBinder binder) {
    binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));
}

然后定義我們的控制器參數(shù):

@GetMapping(value = {"/test.html"})
public String test(@RequestParam("date") Date date, @RequestParam("user") String user) {
    System.out.println(date);
}

打印結(jié)果:

Sat Dec 09 00:00:00 CST 2017

使用@InitBinder注解,然后借助WebDataBinder類尼摹,這樣在綁定表單前见芹,先注冊(cè)這些編輯器。其實(shí)Spring提供了許多類型轉(zhuǎn)換的實(shí)現(xiàn)蠢涝,比如CustomDateEditor玄呛、CustomBooleanEditor、CustomNumberEditor和二、CustomMapEditor等等把鉴,我們可以根據(jù)我們的需要有選擇的注冊(cè)這些編輯器。

一般情況下儿咱,我們將該@InitBinder放于使用ControllerAdvice所配置的全局對(duì)象中庭砍,這樣,它將對(duì)所有的控制器方法都生效混埠。

7. RequestMapping GetMapping等注解
7.1 RequestMapping

??RequestMapping這個(gè)注解應(yīng)該是我們使用注解最多的幾個(gè)之一怠缸,這個(gè)注解會(huì)將 HTTP 請(qǐng)求映射到 MVC 和 REST 控制器對(duì)應(yīng)的處理方法上,可用于控制器的類或者方法上钳宪。
我們來(lái)看下它的參數(shù):

  1. name揭北,方法映射的名稱;
  2. value吏颖,匹配的請(qǐng)求的url數(shù)組搔体,也就是path的別名;
  3. path半醉,匹配的請(qǐng)求的url數(shù)組疚俱,和value功能相同,Spring4.2引入該參數(shù)缩多;
  4. method呆奕,HTTP請(qǐng)求的參數(shù)類型养晋,數(shù)組格式可支持多種類型,GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE梁钾。如果用于類級(jí)別上绳泉,所有的方法都將支持此映射方法類型;
  5. params姆泻,映射請(qǐng)求的參數(shù)零酪,也是數(shù)組格式,支持myParam拇勃,myParam=myValue四苇,flag!=true格式,只有參數(shù)滿足相應(yīng)的條件時(shí)才會(huì)映射這個(gè)請(qǐng)求潜秋;舉個(gè)簡(jiǎn)單的例子:
@GetMapping(value = {"/test.html"}, params = "flag=true")
public String test(@RequestParam("date") Date date, @RequestParam("flag") Boolean flag) {
}

當(dāng)請(qǐng)求到這個(gè)方法蛔琅,并且參數(shù)包含flag=true時(shí)才會(huì)進(jìn)入這個(gè)方法胎许,執(zhí)行相應(yīng)的操作峻呛,否則就會(huì)提示400異常。也就是說(shuō)請(qǐng)求的url必須包含該參數(shù)辜窑,而不管方法的參數(shù)中是否有該參數(shù)钩述。

Expressions can be negated by using the "!=" operator, with such parameters having to be present in the request (allowed to have any value). Finally, "!myParam" style expressions indicate that the specified parameter is not supposed to be present in the request.

  1. headers,支持的請(qǐng)求頭類型穆碎,數(shù)組格式牙勘,同樣也是支持My-HeaderMy-Header=myValue所禀,My-Header!=myValue格式的類型方面,當(dāng)然還支持通配符(*),比如:
@RequestMapping(value = "/something", headers = "content-type=text/*")

這種情況下將會(huì)匹配Content-Type 是text/html色徘,text/plain等類型恭金。同樣如果需要了解更多,可自行查看具體的HTTP請(qǐng)求頭類型褂策。

  1. consumes横腿,指定請(qǐng)求的提交內(nèi)容類型(Content-Type),只有Content-Type匹配所給出的類型時(shí)斤寂,才進(jìn)行請(qǐng)求映射操作耿焊。數(shù)組類型,支持通配符遍搞,并且支持 "!" 操作符罗侯,比如"!text/plain",它將匹配除了text/plain之外的所有Content-Type類型溪猿。
 consumes = "text/plain"
 consumes = {"text/plain", "application/*"}
  1. produces歇父,和consumes相反蒂培,前者指的是提交時(shí)候的數(shù)據(jù)類型Content-Type,也就是客戶端發(fā)送的數(shù)據(jù)類型榜苫,而produces指的是客戶端接收的數(shù)據(jù)類型Accept护戳。它是和consumes相對(duì)應(yīng)的,比如說(shuō)我們使用UTF-8生成了一個(gè)JSON數(shù)據(jù)垂睬,則返回的時(shí)候應(yīng)該設(shè)置application/json; charset=UTF-8媳荒。
produces = "text/plain"
produces = {"text/plain", "application/*"}
produces = "application/json; charset=UTF-8"
7.2 GetMapping

??在Spring4.3之后,Spring引入了一些組合級(jí)的注解來(lái)簡(jiǎn)化常用HTTP方法的映射驹饺,這些注解分別是:GetMapping钳枕,PostMappingPutMapping赏壹,DeleteMapping鱼炒,PatchMapping。比如GetMapping注解就相當(dāng)于@RequestMapping(method = RequestMethod.GET)蝌借,它們的參數(shù)什么的都和RequestMapping一樣昔瞧,就不多說(shuō)了,大家可以有選擇的使用菩佑。

8. ControllerAdvice RestControllerAdvice注解

??該注解用于為控制器做一些全局配置自晰,可以通過(guò)配置掃描路徑來(lái)指定為哪些控制器進(jìn)行配置,默認(rèn)情況下稍坯,@ControllerAdvice中的方法適用于所有控制器酬荞。
??一般情況下,配置了ControllerAdvice注解的類一般會(huì)包含@ExceptionHandler注解瞧哟,@InitBinder注解和@ModelAttribute注解混巧,這些方法將適用于所有被掃描到的控制器的RequestMapping方法。

來(lái)看一下它的幾個(gè)參數(shù):

  1. basePackages勤揩,所要管理的控制器所在的包咧党,數(shù)組格式。比如:
@ControllerAdvice(basePackages={"org.my.pkg", "org.my.other.pkg"})
@ControllerAdvice(basePackages="org.my.pkg")
  1. value雄可,該屬性是basePackages屬性的別名凿傅,目的是為了允許更簡(jiǎn)潔的聲明。
  2. basePackageClasses数苫,指定特定的控制器類聪舒,該全局配置只對(duì)這些類生效,同樣是數(shù)組格式虐急。比如:@ControllerAdvice(basePackageClasses = HelloController.class)箱残,則該ControllerAdvice所修飾的配置類只對(duì)HelloController生效。
  3. assignableTypes,和上面的basePackageClasses類似被辑,這個(gè)屬性也是為了指定特定的控制器類燎悍,不同的是,該屬性指定的是基類盼理,而該控制器的配置對(duì)該基類的繼承類也都生效谈山。
  4. annotations,指定所有使用了該注解類型的控制器類宏怔,數(shù)組類型奏路。比如:@ControllerAdvice(annotations = Controller.class),也就是該配置對(duì)所有使用Controller注解的類生效臊诊。

另外鸽粉,對(duì)于RestControllerAdvice注解,功能和ControllerAdvice一樣抓艳,但需要注意一點(diǎn):RestControllerAdvice所修飾的@ExceptionHandler將自動(dòng)具有@ResponseBody的功能触机,也就是在ControllerAdvice下原先我們所返回的視圖,在RestControllerAdvice下玷或,將會(huì)返回字符串儡首,而不會(huì)進(jìn)入對(duì)應(yīng)的視圖頁(yè)面。

@ExceptionHandler
public String exception(Exception e, Model model) {
    model.addAttribute("message", e.getMessage());
    return "/exception";
}

在RestControllerAdvice下庐椒,將直接返回"/exception"椒舵,而不會(huì)進(jìn)入對(duì)應(yīng)的異常視圖頁(yè)面蚂踊。

ControllerAdvice最常用的情況就是和ExceptionHandler注解一起约谈,構(gòu)建全局的異常管理頁(yè)面。

9. ExceptionHandler注解

上文已經(jīng)大致了解過(guò)該注解犁钟,用于在異常情況下的后續(xù)操作棱诱,可以跳轉(zhuǎn)至異常頁(yè)面,也可以指定特定的異常信息返回涝动,最常用的情況上面已經(jīng)說(shuō)過(guò)迈勋,就是用于和ControllerAdvice注解配合使用。參數(shù)只有一個(gè):

value醋粟,用于指定具體的異常類型靡菇,默認(rèn)情況下的異常為方法參數(shù)列表中列出的所有異常;使用時(shí)我們可以在方法參數(shù)中指明具體的異常類米愿,也可以配置該參數(shù)指明異常類厦凤。

10. ModelAttribute注解

ModelAttrribute注解我們也經(jīng)常用到,一般情況下我們是用于兩方面:

    1. 用于方法上育苟,這樣的話较鼓,ModelAttrribute注解標(biāo)記的方法將在所有RequestMapping所標(biāo)記的方法之前執(zhí)行,如果有返回值,則自動(dòng)將該返回值加入到模型對(duì)象中博烂,比如Model對(duì)象或ModelMap對(duì)象香椎;
    1. 運(yùn)用在參數(shù)上,又分為兩種情況禽篱,參數(shù)是單個(gè)參數(shù)還是對(duì)象畜伐;
      參數(shù)是單個(gè)參數(shù):先去Model或ModelMap中查找是否有該對(duì)象,如果有躺率,注入到該參數(shù)中(客戶端傳過(guò)來(lái)的值將不再綁定)烤礁,如果沒(méi)有,再將客戶端傳過(guò)來(lái)的值綁定到該參數(shù)上肥照,并且自動(dòng)將該參數(shù)加入到Model或ModelMap中脚仔,以便View層使用;
      參數(shù)是對(duì)象:同樣舆绎,先去Model或ModelMap中查找是否有該對(duì)象鲤脏,如果有,注入到該參數(shù)中吕朵,然后將客戶端傳過(guò)來(lái)的值綁定到參數(shù)上猎醇,這時(shí)候會(huì)覆蓋掉數(shù)據(jù)模型中的該對(duì)象,也就是說(shuō)URI對(duì)象具有高優(yōu)先級(jí)努溃;

我們先來(lái)看下該注解的幾個(gè)參數(shù)硫嘶,然后再仔細(xì)來(lái)看下上面這兩種情況:

  • name,要綁定到Model的對(duì)象的名稱梧税,默認(rèn)情況下沦疾,是根據(jù)方法參數(shù)類型或方法返回類型推斷出來(lái)的,比如mypackage.OrderAddress的名稱是orderAddress第队,List<mypackage.OrderAddress>的名稱是orderAddressList(該屬性Spring4.3之后才引入)哮塞;
  • value,name的別名凳谦,和name功能完全一致忆畅;
  • binding,是否允許在@ModelAttribute方法參數(shù)或@ModelAttribute方法返回值上聲明數(shù)據(jù)綁定尸执,默認(rèn)是true家凯。

接下來(lái)我們來(lái)詳細(xì)了解下這兩種情況,以下的幾種情況都使用ModelMap來(lái)測(cè)試:

(1)用于方法上如失,方法返回值為void的情況:

@ModelAttribute
public void init(ModelMap modelMap) {
    modelMap.addAttribute("userId", "123");
}

對(duì)應(yīng)的測(cè)試接口:

@RequestMapping("/hello.html")
public String hello(ModelMap modelMap, String id) {
    modelMap.addAttribute("id", "456");
    System.out.println(modelMap);
     return "hello";
}

可以看到绊诲,在執(zhí)行hello方法之前,init方法已經(jīng)執(zhí)行岖常,所以ModelMap中已經(jīng)有了"userId"對(duì)象驯镊。

(2)用于方法上,方法返回值為對(duì)象的情況,這時(shí)候ModelMap參數(shù)可以不傳了板惑,我們先來(lái)看下返回基礎(chǔ)類型的情況:

@ModelAttribute
public String init() {
    return "userId";
}

這時(shí)候我們調(diào)用hello方法的時(shí)候橄镜,同樣可以發(fā)現(xiàn)ModelMap中已經(jīng)有一個(gè)值了,但ModelMap中的值是{"string","userId"}冯乘,可以看到洽胶,如果ModelAttribute沒(méi)有配置name的話,那么默認(rèn)情況下將根據(jù)方法參數(shù)類型或方法返回類型進(jìn)行推斷出來(lái)裆馒。我們?cè)賮?lái)看下:

@ModelAttribute
public List<String> init() {
    List<String> list = new ArrayList<>();
    list.add("123");
    return list;
}

同樣姊氓,可以看到ModelMap中的值是{"stringList", List對(duì)象}

@ModelAttribute
public User users() {
    User user = new User();
    user.setId("123");
    return user;
}

同樣喷好,可以看到ModelMap中的值是{"user", Object}翔横;

接下來(lái),我們?cè)O(shè)置ModelAttribute的name屬性梗搅,以上面的List對(duì)象為例禾唁,再來(lái)看下ModelMap對(duì)象中的值:

@ModelAttribute(name = "userIdList")
public List<String> init() {
    List<String> list = new ArrayList<>();
    list.add("123");
    return list;
}

可以看到這次ModelMap中的鍵值對(duì)的鍵值是userIdList

(3)現(xiàn)在我們來(lái)看下用于方法中的參數(shù)上的情況:
第一種是單個(gè)參數(shù)的情況:

@ModelAttribute(name = "id")
public String init() {
    return "123";
}

@RequestMapping("/hello.html")
public String hello(ModelMap modelMap, @ModelAttribute("id") String id) {
    System.out.println(id);
    System.out.println(modelMap);
     return "hello";
}

這時(shí)候无切,我們發(fā)送請(qǐng)求:http://localhost:8080/hello.html?id=456荡短,我們可以看到,由于ModelMap中已經(jīng)有了名稱為id的對(duì)象哆键,所以直接從里面取出綁定到參數(shù)id上掘托,而沒(méi)有取客戶端過(guò)來(lái)的值,這時(shí)候id的值是123籍嘹;

我們稍微修改下闪盔,再來(lái)看一下:

@RequestMapping("/hello.html")
public String hello(ModelMap modelMap, @ModelAttribute String id) {
    System.out.println(id);
    System.out.println(modelMap);
     return "hello";
}

由于沒(méi)有配置ModelAttribute的name屬性,那么默認(rèn)將根據(jù)參數(shù)的類型來(lái)取值噩峦,也就是名稱為string的對(duì)象锭沟。我們發(fā)送請(qǐng)求:http://localhost:8080/hello.html?string=456抽兆,這時(shí)候ModelMap中沒(méi)有识补,然后從客戶端取值,值為456辫红,綁定到參數(shù)id上凭涂,然后自動(dòng)綁定到ModelMap中。

這時(shí)候來(lái)看下第二種情況贴妻,參數(shù)是對(duì)象的情況:

@RequestMapping(value = "/test2.html", method = RequestMethod.GET)
public String  test2(@ModelAttribute("user1") User user, ModelMap modelMap) {
    System.out.println(user);
    System.out.println(modelMap);
    return "hello";
}

  @ModelAttribute("user1")
public User getUser() {
    User user = new User();
    user.setId("123");
    user.setName("name1");
    return user;
}

這時(shí)候切油,我們發(fā)送請(qǐng)求:/world/test2.html?id=345,可以看下此時(shí)對(duì)象user和數(shù)據(jù)模型ModelMap中的值:

User{name='name1', id='345', aDouble=null}

可以看到名惩,對(duì)象user中的值被覆蓋為了345澎胡。

(4)再來(lái)看一下ModelAttribute和RequestMapping一起使用的情況:

@RequestMapping("/hello.html")
@ModelAttribute("attribute")
public String hello(ModelMap modelMap, @ModelAttribute(name = "id") String id) {
    System.out.println(id);
    System.out.println(modelMap);
     return "hello";
}

這時(shí)候該方法的返回值并不僅僅是一個(gè)視圖,并且還是ModelMap中對(duì)象名稱為attribute的值,這時(shí)候我們?cè)陧?yè)面上使用${attribute}可以看到攻谁,正常打印出了hello稚伍。

該參數(shù)一般情況下也是配合@ControllerAdvice用于全局的配置。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末戚宦,一起剝皮案震驚了整個(gè)濱河市个曙,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌受楼,老刑警劉巖垦搬,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異艳汽,居然都是意外死亡猴贰,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門河狐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)糟趾,“玉大人,你說(shuō)我怎么就攤上這事甚牲∫逯#” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵丈钙,是天一觀的道長(zhǎng)非驮。 經(jīng)常有香客問(wèn)我,道長(zhǎng)雏赦,這世上最難降的妖魔是什么劫笙? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮星岗,結(jié)果婚禮上填大,老公的妹妹穿的比我還像新娘。我一直安慰自己俏橘,他們只是感情好允华,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著寥掐,像睡著了一般靴寂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上召耘,一...
    開(kāi)封第一講書(shū)人閱讀 51,631評(píng)論 1 305
  • 那天百炬,我揣著相機(jī)與錄音,去河邊找鬼污它。 笑死剖踊,一個(gè)胖子當(dāng)著我的面吹牛庶弃,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播德澈,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼虫埂,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了圃验?” 一聲冷哼從身側(cè)響起掉伏,我...
    開(kāi)封第一講書(shū)人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎澳窑,沒(méi)想到半個(gè)月后斧散,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡摊聋,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年鸡捐,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片麻裁。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡箍镜,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出煎源,到底是詐尸還是另有隱情色迂,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布手销,位于F島的核電站歇僧,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏锋拖。R本人自食惡果不足惜诈悍,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望兽埃。 院中可真熱鬧侥钳,春花似錦、人聲如沸柄错。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)鄙陡。三九已至冕房,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間趁矾,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工给僵, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留毫捣,地道東北人详拙。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蔓同,于是被迫代替她去往敵國(guó)和親饶辙。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355