文章目录
- 引导
- 作用
- 使用方法
- 总结几点
引导
在项目中,controller中经常看到@ModelAttribute或者@ModelAttribute(“someName”)这种用法,这到底是个什么意思呢?本文带你一探究竟。
作用
@ModelAttribute,即org.springframework.web.bind.annotation.ModelAttribute,是spring的一个注解,可以用在方法或者属性上。被该注解标注的方法会在该controller的请求方法执行之前执行,比如你定义一个TestController,其中一个方法test()标注@RequestMapping("/api/test"),然后发起一个请求/api/test,那么在test执行前,该类中所有@ModelAttribute标注的方法会先执行,执行之后的结果会放在Model中,后续test方法可以通过Model获得一些全局属性。那么问题来了,Model是什么,这个暂时可以理解为该类的一个全局属性,是一个map形式。
简单理解就是:
- 该注解标注的方法会在handler具体方法执行之前,作为全局属性存放在Model,供后续handler具体方法执行的时候调用
在知道了ModelAttribute的执行时间和作用,我们来看看这个注解怎么用。
使用方法
该注解标注的方法可以带有和请求方法一样的参数,比如请求方法带有一个String userId,那么该方法也可以带有,两个方法对应的值是一样的,但要注意的是:
- 能自动获取的值是可以用@RequestParam拿到的值,即get请求的?后接的参数或者post请求的body里的参数,且如果是body里的参数,则此post请求对应的Content-Type为application/x-www-form-urlencoded,如果为application/json则无法用@RequestParam获取到,@ModelAttribute方法的参数也就获取不到,参数为null。
private static final String USER_ID = "userId";
@ModelAttribute(USER_ID)
public String getUserId(String userId) {
System.out.println(userId);
return "my" + userId;
}
如上面的代码,就是自动获取的方式,我的测试请求可以用如下格式:
Get /api/test/model?userId=123
Post /api/test
Content-Type: application/x-www-form-urlencoded
userId=234
另一种方式是在方法的参数前标明获取方式:
private static final String USER_ID = "userId";
@ModelAttribute(USER_ID)
public String getUserId(@PathVariable("userId") String userId) {
System.out.println(userId);
return "my" + userId;
}
如上,这种情况下对应的请求需要在路径中包含userId,且需要注意的是:
如果用了这种方式,那么这个类中所有的请求方法对应的uri都路径中都需要包含userId的占位符
比如我请求了如下接口
Get /api/test/model/tt
//会报错"Missing URI template variable 'userId' for method parameter of type String"
同理,还可以用@RequestParam @RequestBody等获取参数
使用的话我们可以直接用如下的方式
public Object getSomeThing1(@ModelAttribute(USER_ID) String userID) {
return userID;
}
不加参数怎么用呢?
举个例子:
@ModelAttribute
public UserData getuserData() {
UserData userData = new UserData();
userData.setUserId("id");
Map<String, String> map = new HashMap<>();
map.put("testKey", "testValue");
userData.setData(map);
System.out.println(userData);
return userData;
}
我们定义了一个getuserData方法,返回了一个userData实例,由于我们没有像上面定义getUserId方法一样直接指定@ModelAttribute的value值,返回后对应的key默认为返回类型且首字母小写,即userData。通过定义这个方法,我们可以在model中获得一个key为userData的value,值为该方法的返回值。
如下为方法执行后model中的值。
{
"userData": {
"userId": "id",
"data": {
"testKey": "testValue"
}
}
}
那么定义好了,怎么在方法中用呢?
@RequestMapping(value = "/api/test/model/post", method = RequestMethod.POST)
public Object postUserData(@ModelAttribute UserData data) {
return data;
}
这样我们就可以获得一个UserData实例了,及时我的请求中没有任何参数。
注意:上面的例子我们获取了一个userData实例,如果对不同的请求我想得到不同的实例怎么办呢?
- 首先可以通过类似于上面getUserId(String UserId)这种方法实现,也就是你的请求参数中添加一个userId,在@ModelAttribute修饰的方法中构造自己的UserData实例,这样就可以
- 其次我们可以用下面的getuserData()的方式,只传递一个userId参数,然后代码不变,由于ModelAttribute会自动获取@RequestParam可以获取到的值,会用请求中的值替换model中预设的值。
例子:
Post /api/test/model/post?userId=popo
最后返回的值有原来的
{
"userId": "id",
"data": {
"testKey": "testValue"
}
}
变成了
{
"userId": "popo",
"data": {
"testKey": "testValue"
}
}
这个变化只是因为我的请求加了参数,代码未变。
总结几点
- @ModelAttribute适合给一个controller增加一些全局的变量
- 如果返回一个String值,可以用上面例子中的@ModelAttribute(USER_ID) String userID 这种方式,也可以在请求方法中直接引入model或者modelMap进行get,但不可以直接@ModelAttribute String userID。
- 如果返回的是一个对象,一个实例,那么可以直接@ModelAttribute UserData data使用,也可以@ModelAttribute(“userData”) UserData data使用,还可以用Model或者ModelMap进行get.