专栏首页程序员爱酸奶面试不是无情物,参数注解知多少?

面试不是无情物,参数注解知多少?

前言

前两天面试的,面试官问我用在参数上的注解有哪些?我想了一下说有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。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。所以当我们使用注解的时候,单个的参数也可以直接获取到。

后记

总算差不多了,现在面试官有本事再问我这个问题试试,看我不怼回去。

本文分享自微信公众号 - 程序员爱酸奶(gh_d6fe115dd573),作者:QuellanAn

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-05-14

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 六、springboot 简单优雅是实现短信服务

    上一篇讲了 springboot 集成邮件服务,接下来让我们一起学习下springboot项目中怎么使用短信服务吧。项目中的短信服务基本上上都会用到,简单的注册...

    程序员爱酸奶
  • 手撸一个自定义starter,它不香吗

    springboot 中有很多的starter 。我们用起来很爽不是吗,之所以这么爽难道不是因为我们少了很多配置吗,之前我们想要使用jdbcTemplete 是...

    程序员爱酸奶
  • 教你springboot 如何优雅简单的整合 mybatis

    上一篇文章开始了我们的springboot序篇,我们配置了mysql数据库,但是我们sql语句直接写在controller中并且使用的是jdbcTemplate...

    程序员爱酸奶
  • Java性能优化之字符串优化处理

      String对象是Java中重要的数据类型,在大部分情况下我们都会用到String对象。其实在Java语言中,其设计者也对String做了大量的优化工作,这...

    Java后端技术
  • Spring Boot启动命令参数详解及源码分析

    使用过Spring Boot,我们都知道通过java -jar可以快速启动Spring Boot项目。同时,也可以通过在执行jar -jar时传递参数来进行配置...

    用户1161110
  • Java FTP下载文件

    河岸飞流
  • Java 通过RestHighLevelClient 使用ES的date_histogram 根据年月日做统计

    只写了后台,前端请求带上dateType给后台,后端返回封装了json字符串的map

    heasy3
  • JFinal 表自动绑定插件实现,实现零配置,支持多数据源

    因为java里的属性一般都是驼峰规则,代码看起来舒服一点,这里以数据库中以大写字母为例,表名为T_USER,对应Model名为User实现如下

    用户2603479
  • 商城项目-生成规格参数过滤

    如果用户尚未选择商品分类,或者聚合得到的分类数大于1,那么就没必要进行规格参数的聚合。因为不同分类的商品,其规格是不同的。

    cwl_java
  • 聊聊rocketmq的AclClientRPCHook

    rocketmq-remoting-4.5.2-sources.jar!/org/apache/rocketmq/remoting/RPCHook.java

    codecraft

扫码关注云+社区

领取腾讯云代金券