概述
??由于以前學(xué)習(xí)Spring的時(shí)候?qū)W習(xí)的不太系統(tǒng)进栽,所以通過(guò)本篇及以下幾篇文章來(lái)重新梳理下Spring中常用注解的使用德挣,從而加深對(duì)Spring注解的理解,本篇文章來(lái)看下Spring-web中常用的一些注解快毛。
- 本系列學(xué)習(xí)的Spring版本是:4.3.14格嗅,工程基于全注解的實(shí)現(xiàn)。
- 強(qiáng)烈建議學(xué)習(xí)的時(shí)候先看官網(wǎng)文檔:https://docs.spring.io/spring/docs/4.3.14.RELEASE/spring-framework-reference/html/mvc.html
- 本篇注解包括:
RequestParam
唠帝,PathVariable
屯掖,RequestBody
,ResponseBody
襟衰,RestController
贴铜,InitBinder
,RequestMapping
,GetMapping
绍坝,ControllerAdvice
徘意,RestControllerAdvice
,ExceptionHandler
轩褐,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ù):
value
,前端傳入的參數(shù)名稱秒拔,通過(guò)該名稱來(lái)綁定參數(shù)到相應(yīng)的對(duì)象上莫矗;name
,和value參數(shù)功能一樣砂缩,是Spring4.2之后添加的作谚,目的么,應(yīng)該是為了代替原先value這個(gè)屬性不太直白的描述方式庵芭;required
妹懒,該參數(shù)是否必須,默認(rèn)是true双吆,也就是必須要傳入眨唬,如果不傳入?yún)?shù)的話,會(huì)直接提示異常400好乐;defaultValue
匾竿,如果沒(méi)有傳遞參數(shù),參數(shù)的默認(rèn)值蔚万。當(dāng)然岭妖,如果required=true的話,那該屬性就沒(méi)有意義了反璃。
該注解的一些注意事項(xiàng):
- 當(dāng)設(shè)置required=false昵慌,也就是可以不傳參數(shù)的時(shí)候,會(huì)給參數(shù)賦值為null淮蜈,這時(shí)候如果參數(shù)的類型是基本類型 int 等斋攀,則會(huì)直接報(bào)錯(cuò),所以定義參數(shù)的時(shí)候能優(yōu)先使用包裝類型就使用包裝類型礁芦;
- 一般情況下蜻韭,基于約定,如果方法的參數(shù)中沒(méi)有使用該注解柿扣,那么前端的參數(shù)將綁定到同名的查詢參數(shù)上肖方。因?yàn)锧RequestParam參數(shù)并不是必須的,這種情況下不傳遞參數(shù)也不會(huì)提示異常未状,和required=false的情況類似俯画。
- 該注解一般用于表單提交的方式,也就是用于
Content-Type
是application/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ù):
value
袍啡,URL中占位符的名稱踩官,通過(guò)該名稱來(lái)綁定對(duì)應(yīng)的參數(shù);name
境输,同樣蔗牡,和value參數(shù)功能一樣,是Spring4.3.3之后添加的參數(shù)嗅剖,目的應(yīng)該也是用于代替原先value屬性不太直白的描述方式蛋逾;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ō)下使用該注解需要注意的情況:
- PathVariable的參數(shù)可以是任何簡(jiǎn)單類型啦租,比如int,long荒揣,Date等等篷角,如果不是這些基礎(chǔ)類型,Spring會(huì)拋出TypeMismatchException異常系任,不過(guò)我們也可以自定義支持類型恳蹲;
- 由于是綁定URL中的參數(shù),所以就需要考慮URL中一些特殊的字符的處理俩滥,比如空格``嘉蕾,點(diǎn)號(hào)
.
,問(wèn)號(hào)?
霜旧,斜杠號(hào)/
等错忱,當(dāng)我們進(jìn)行參數(shù)綁定的時(shí)候記得做相應(yīng)的處理。- 由于URL畢竟是要暴露對(duì)外的挂据,所以要注意相應(yīng)的安全性以清,避免別人根據(jù)某一個(gè)參數(shù)可以推斷出另外的值,從而可能獲取到別人相關(guān)的數(shù)據(jù)崎逃,也就是需要注意下敏感數(shù)據(jù)與公共數(shù)據(jù)的問(wèn)題掷倔,其實(shí)這也是REST請(qǐng)求中要注意的問(wèn)題。
- 和上文說(shuō)的類似个绍,就是要考慮下使用場(chǎng)景問(wèn)題勒葱。
3. RequestBody注解
??該注解和RequestParam有點(diǎn)類似浪汪,同樣用于綁定參數(shù),但不是用于綁定表單提交的數(shù)據(jù)凛虽,也就是不是用于綁定Content-Type
是application/x-www-form-urlencoded
情況下的參數(shù)死遭,一般用于綁定Content-Type
是application/json
,application/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-Type
為text/plain
)夭苗,MappingJackson2XmlHttpMessageConverter
(Content-Type
為application/xml
信卡,text/xml
)等,如果想了解更多题造,可以支持查看HttpMessageConverter的各個(gè)實(shí)現(xiàn)類傍菇。
有兩點(diǎn)可能需要注意下:
- 使用RequestBody的時(shí)候,注意參數(shù)名稱什么的要匹配界赔,如果傳入了一個(gè)后端對(duì)象里沒(méi)有的參數(shù)丢习,會(huì)直接提示參數(shù)不匹配400異常;
- 由于HttpMessageConverter有一個(gè)
FormHttpMessageConverter
的實(shí)現(xiàn)淮悼,所以說(shuō)RequestBody也是支持Content-Type
為application/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ù):
name
揭北,方法映射的名稱;value
吏颖,匹配的請(qǐng)求的url數(shù)組搔体,也就是path的別名;path
半醉,匹配的請(qǐng)求的url數(shù)組疚俱,和value功能相同,Spring4.2引入該參數(shù)缩多;method
呆奕,HTTP請(qǐng)求的參數(shù)類型养晋,數(shù)組格式可支持多種類型,GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE梁钾。如果用于類級(jí)別上绳泉,所有的方法都將支持此映射方法類型;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.
headers
,支持的請(qǐng)求頭類型穆碎,數(shù)組格式牙勘,同樣也是支持My-Header
,My-Header=myValue
所禀,My-Header!=myValue
格式的類型方面,當(dāng)然還支持通配符(*),比如:
@RequestMapping(value = "/something", headers = "content-type=text/*")
這種情況下將會(huì)匹配Content-Type 是text/html
色徘,text/plain
等類型恭金。同樣如果需要了解更多,可自行查看具體的HTTP請(qǐng)求頭類型褂策。
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/*"}
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
钳枕,PostMapping
,PutMapping
赏壹,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ù):
basePackages
勤揩,所要管理的控制器所在的包咧党,數(shù)組格式。比如:
@ControllerAdvice(basePackages={"org.my.pkg", "org.my.other.pkg"})
@ControllerAdvice(basePackages="org.my.pkg")
value
雄可,該屬性是basePackages
屬性的別名凿傅,目的是為了允許更簡(jiǎn)潔的聲明。basePackageClasses
数苫,指定特定的控制器類聪舒,該全局配置只對(duì)這些類生效,同樣是數(shù)組格式虐急。比如:@ControllerAdvice(basePackageClasses = HelloController.class)
箱残,則該ControllerAdvice所修飾的配置類只對(duì)HelloController生效。assignableTypes
,和上面的basePackageClasses
類似被辑,這個(gè)屬性也是為了指定特定的控制器類燎悍,不同的是,該屬性指定的是基類盼理,而該控制器的配置對(duì)該基類的繼承類也都生效谈山。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)常用到,一般情況下我們是用于兩方面:
- 用于方法上育苟,這樣的話较鼓,ModelAttrribute注解標(biāo)記的方法將在所有RequestMapping所標(biāo)記的方法之前執(zhí)行,如果有返回值,則自動(dòng)將該返回值加入到模型對(duì)象中博烂,比如Model對(duì)象或ModelMap對(duì)象香椎;
- 運(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í)努溃;
- 運(yùn)用在參數(shù)上,又分為兩種情況禽篱,參數(shù)是單個(gè)參數(shù)還是對(duì)象畜伐;
我們先來(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用于全局的配置。