面试不是无情物,参数注解知多少?
前言
前两天面试的,面试官问我用在参数上的注解有哪些?
我想了一下说有RequestParam,每个参数都需要RequestParam修饰,可以设置required 等于false,表示该字段非必传。
面试官:还有呢?
我:只知道这么多了,RequestParam 注解用的比较多,其他的没怎么用?
面试官:好了,今天的面试就到这,后续有消息会通知你。挂掉电话
我:???
结束掉面试后,好好的看了下用在参数上的注解。
用在参数上的注解,主要是controller 层,用来接收请求中的参数。
常用的有三种
@RequestParm
@RequestBody
@PathVariable
下面我们一个个看下
@RequestParam
@RequestParam 注解接收请求的参数是从request.getParameterMap()中取的。我们来先看下这个例子:
@RequestMapping(value = "/hello",method = {RequestMethod.GET,RequestMethod.POST})
public String play(@RequestParam(value = "name",required = false) String name, HttpServletRequest request){
Map<String, String[]> map=request.getParameterMap();
for(Map.Entry<String, String[]> entry:map.entrySet()){
System.out.println(entry.getKey());
System.out.println(Arrays.toString(entry.getValue()));
}
return name+",你好!";
}
@RequestMapping 表示请求的相对路径,value 是相对路径的值,method 用来限制秋衣请求的类型,我这里设置的是可以get 和post 请求。
HttpServletRequest 这个参数是方便我们得到请求的request 里面的信息。
而RequestParam 注解就是用来接收 参数name 的。
我们看下RequestParam 的源码:
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestParam {
@AliasFor("name")
String value() default "";
@AliasFor("value")
String name() default "";
boolean required() default true;
String defaultValue() default "\n\t\t\n\t\t\n\ue000\ue001\ue002\n\t\t\t\t\n";
}
name和value 用来接收参数名,二者选其一就可以。required 默认为true 表示参数必须传,改成false 表示参数非必传。
我们现在运行看下结果
说明@RequestParam 注解是从request.parames()方法中获取到参数。
@RequestParam 可以接收post 和get 的参数。且parms 和body 中都添加的参数,会同时生效。
总结:
1、@RequestParam 注解,作用在单个参数上,并且参数不能是一个对象。因为我们看到request.getParameterMap() 接收的map 的类型为Map<String, String[]>。
2、@RequestParam 注解,多个参数可以使用多个注解,可以设置参数是否必传。
3、@RequestParam 注解获取参数是从request 中的parms 获取的。支持get 和post
@RequestBody
@RequestBody 注解是从请求体重获取参数。一个请求只有一个请求体,但是可以有多个参数,这就是为什么只能有一个@RequestBody 注解,但是可以有多个@RequestParam 注解。因为get请求没有请求体。所以@RequestBody 一般用来接收post 请求的参数,且用来接收前端传的json 字符串的。
我们还是上面的例子,稍作调整
@RequestMapping(value = "/hello1",method = {RequestMethod.GET,RequestMethod.POST})
public String play1(@RequestBody String name,String sex, HttpServletRequest request){
Map<String, String[]> map=request.getParameterMap();
for(Map.Entry<String, String[]> entry:map.entrySet()){
System.out.println(entry.getKey()+":"+Arrays.toString(entry.getValue()));
}
return name+",你好! \n你的性别是:"+sex;
}
发现name的值是name=小明&sex=男。这说明@RequestBody 注解只能使用一个,且获取到所有的参数,我们最好不要用单一的参数接收。
我们再稍作修改。通过map 来接收请求体。
@RequestMapping(value = "/hello1",method = {RequestMethod.GET,RequestMethod.POST})
public String play1(@RequestBody Map<String,Object> parms, HttpServletRequest request){
Map<String, String[]> map=request.getParameterMap();
for(Map.Entry<String, String[]> entry:map.entrySet()){
System.out.println(entry.getKey()+":"+Arrays.toString(entry.getValue()));
}
return parms.get("name")+",你好! \n你的性别是:"+parms.get("sex");
}
而控制台什么都没打印。
说明@RequestBody并不是从parms 中获取参数的,而是从从requestbody 中获取参数,并且是获取json 格式的参数。这时我们使用Content-Type=application/json。
如果我们使用Content-Type 等于application/x-www-form-urlencoded或者multipart/form-data 则会报错。因为不是这两者是key-value 模式的。
为什么会这样呢?因为@RequestBody 不仅能接收一个对象,还能接收一组对象。但是其他两种却不行。如下我们调整一下代码:
@RequestMapping(value = "/hello2",method = {RequestMethod.POST})
public String play2(@RequestBody List<Map<String,Object>> parms){
StringBuilder stringBuilder=new StringBuilder();
for(Map<String,Object> map:parms){
stringBuilder.append(map.get("name")+",你好! \n你的性别是:"+map.get("sex")+"\n");
}
return stringBuilder.toString();
}
可以看到@RequestBody 还是有自己的优势的,不仅如此,RequestBody不但可以接收map,还可以接收我们自定义的bean。如下:我们先创建一个user 实体
public class User {
private String name;
private String sex;
private int age;
//getter和setter 方法
}
然后写一个接口
@RequestMapping(value = "/hello3",method = {RequestMethod.GET,RequestMethod.POST})
public String play3(@RequestBody List<User> users){
StringBuilder stringBuilder=new StringBuilder();
for(User user:users){
stringBuilder.append(user.getName()+",你好! \n你的性别是:"+user.getSex()+"\n");
}
return stringBuilder.toString();
}
看到可以达到一样的效果,还省去了我们转换。
总结:
1、@RequestBody 注解 接收请求体中参数,接收post请求,不能接收get 请求。且只能有一个RequestBody 注解。
2、@RequestBody 注解多用来接收json 传参。可以是map,对象,list.
@PathVariable
@PathVariable 注解是接收请求路径中的占位符的值。如下:
@RequestMapping(value = "/hello4/{name}/{sex}",method = {RequestMethod.GET,RequestMethod.POST})
public String play4(@PathVariable String name,@PathVariable String sex) {
return name+",你好! \n你的性别是:"+sex;
}
其他的作用和RequestParam 是一样的。他只能接收单个参数,url 中有几个占位符,就有几个@Pathvariable 注解。
无注解接收参数
还有一种情况,放在最后,我们在接口的时候请求参数没有任何注解,也可以接收到请求的参数。看下面去掉@RequestParam 注解
@RequestMapping(value = "/hello5",method = {RequestMethod.GET,RequestMethod.POST})
public String play5(String name,String sex, HttpServletRequest request){
Map<String, String[]> map=request.getParameterMap();
for(Map.Entry<String, String[]> entry:map.entrySet()){
System.out.println(entry.getKey()+":"+Arrays.toString(entry.getValue()));
}
return name+",你好! \n你的性别是:"+sex;
}
并且还支持参数非必传。
我们再试试不用@RequestBody 注解
@RequestMapping(value = "/hello6",method = {RequestMethod.GET,RequestMethod.POST})
public String play6( User user){
return user.getName()+",你好! \n你的性别是:"+user.getSex();
}
发现并没有获取到值。
造成上述的原因:其实是默认是使用@RequestParam 注解,且 ruquires=false。所以当我们使用注解的时候,单个的参数也可以直接获取到。
后记
总算差不多了,现在面试官有本事再问我这个问题试试,看我不怼回去。
兄弟们,写作不易,觉得可以的点个赞和收藏哈哈。
推荐阅读