Spring MVC 教程-如何接受请求中的参数?

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬

学习必须往深处挖,挖的越深,基础越扎实!

阶段1、深入多线程

阶段2、深入多线程设计模式

阶段3、深入juc源码解析


阶段4、深入jdk其余源码解析


阶段5、深入jvm源码解析

码哥源码部分

码哥讲源码-原理源码篇【2024年最新大厂关于线程池使用的场景题】

码哥讲源码【炸雷啦!炸雷啦!黄光头他终于跑路啦!】

码哥讲源码-【jvm课程前置知识及c/c++调试环境搭建】

​​​​​​码哥讲源码-原理源码篇【揭秘join方法的唤醒本质上决定于jvm的底层析构函数】

码哥源码-原理源码篇【Doug Lea为什么要将成员变量赋值给局部变量后再操作?】

码哥讲源码【你水不是你的错,但是你胡说八道就是你不对了!】

码哥讲源码【谁再说Spring不支持多线程事务,你给我抽他!】

终结B站没人能讲清楚红黑树的历史,不服等你来踢馆!

打脸系列【020-3小时讲解MESI协议和volatile之间的关系,那些将x86下的验证结果当作最终结果的水货们请闭嘴】

1、本文内容

Controler中的方法如何接收http请求过来的参数呢?

具体有哪些方式呢?

这些就是本文讨论的重点,本文主要围绕下面这些方式来介绍参数的接收

  • 接收Servlet中的参数:HttpServletRequest、HttpServletResponse、HttpSession
  • 通过方法形参名称接收参数
  • 通过@RequestParam接收参数
  • 通过1个对象接收参数
  • 通过多个对象接收参数
  • 组合对象接收参数(对象中嵌套对象集合等等)
  • 通过@PathVariable接受url中的参数

2、接收Servlet中的参数

比如我们想在方法中用到servlet中的对象:HttpServletRequest、HttpServletResponse、HttpSession,那么可以直接在方法的参数中声明这些对象即可,SpringMVC会自动将这些参数传递进来,用到哪个就声明哪个

    @RequestMapping("/receiveparam/test1.do")
    public ModelAndView test1(HttpServletRequest request,
                              HttpServletResponse response,
                              HttpSession session) {
        String name = request.getParameter("name");
        String age = request.getParameter("age");
        String msg = String.format("name:%s,age:%s", name, age);
        System.out.println(msg);
    
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("/WEB-INF/view/result.jsp");
        modelAndView.addObject("msg", msg);
        return modelAndView;
    }

对应的表单

    <form method="post" action="receiveparam/test1.do">
        姓名:<input name="name" value="路人"/> <br/>
        年龄:<input name="age" value="30"/><br/>
        <input type="submit" value="提交">
    </form>

3、解决乱码问题

如果大家直接创建一个springmvc项目运行上面的案例,会发现name为中文的时候,会是乱码,这里需要在web.xml中添加下面配置,解决乱码问题

    <!-- 添加CharacterEncodingFilter过滤器,这个类中会对request和response设置表名,解决参数乱码问题 -->
    <filter>
        <filter-name>characterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <!-- forceRequestEncoding为true,将设置request.setCharacterEncoding(encoding); -->
            <param-name>forceRequestEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <!-- forceRequestEncoding为true,将设置response.setCharacterEncoding(encoding); -->
            <param-name>forceResponseEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

上面这段配置主要是添加了一个过滤器,这个过滤器户处理所有请求,相当于对所有请求会执行下面操作,而encoding我们设置的是UTF-8

    request.setCharacterEncoding(encoding);
    response.setCharacterEncoding(encoding);

4、通过方法形参名称接收参数

表单

    <form method="post" action="receiveparam/test2.do">
        姓名:<input name="name" value="路人"/> <br/>
        年龄:<input name="age" value="30"/><br/>
        <input type="submit" value="提交">
    </form>

控制器方法

    /**
     * springmvc调用这个方法之前,会根据方法参数名称,请求中获取参数的值,将其传入
     * 过程:
     * 1、将request.getParameter("name")传递给方法的第1个参数name
     * 2、将Integer.valueOf(request.getParameter("age"))传递给方法的第2个参数age
     *
     * @param name
     * @param age
     * @return
     */
    @RequestMapping("/receiveparam/test2.do")
    public ModelAndView test2(String name, Integer age) {
        String msg = String.format("name:%s,age:%s", name, age);
        System.out.println(msg);
    
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("/WEB-INF/view/result.jsp");
        modelAndView.addObject("msg", msg);
        return modelAndView;
    }

这种情况下,form表单中的参数名称和控制器方法中的参数名称一样,会按照名称一一对应进行赋值。

5、通过@RequestParam接收参数

如果方法的参数名称和表单中的参数名称不一致的时候,可以通过 @RequestParam注解的value属性来指定表单中参数的名称。

比如下面表单的2个名称分别为:pname和page

    <form method="post" action="receiveparam/test3.do">
        姓名:<input name="pname" value="路人"/> <br/>
        年龄:<input name="page" value="30"/><br/>
        <input type="submit" value="提交">
    </form>

对应的方法如下,2个形参的参数名称分别为name和age,和表单中的名称不一致了,那么可以在方法的参数前面加上@RequestParam注解,注解的value为表单中元素的名称,参数name希望接受表单中pname的值,那么就需要在name这个参数前面加上@RequestParam("pname"),方法的第2个参数也一样,加上了@RequestParam("page")

    /**
     * 如果方法的参数名称和表单中的参数名称不一致的时候,可以通过 @RequestParam注解的value属性来指定表单中参数的名称
     * 比如:@RequestParam("pname") String name 接收 request.getParameter("pname") 的值
     * 1、将request.getParameter("pname")传递给方法的第1个参数name
     * 2、将Integer.valueOf(request.getParameter("page"))传递给方法的第2个参数age
     *
     * @param name
     * @param age
     * @return
     */
    @RequestMapping("/receiveparam/test3.do")
    public ModelAndView test3(@RequestParam("pname") String name,
                              @RequestParam("page") Integer age) {
        String msg = String.format("name:%s,age:%s", name, age);
        System.out.println(msg);
    
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("/WEB-INF/view/result.jsp");
        modelAndView.addObject("msg", msg);
        return modelAndView;
    }

@RequestParam用来将请求的参数和方法的参数进行绑定,这个注解还有几个属性,也比较常用,大家熟悉下

    public @interface RequestParam {
    
    	//参数名称
    	@AliasFor("name")
    	String value() default "";
    
    	//同value属性
    	@AliasFor("value")
    	String name() default "";
    
    	//参数是不是必须的,默认为true,如果请求中没有这个参数,springmvc会报错
    	boolean required() default true;
    
    	//默认值
    	String defaultValue() default ValueConstants.DEFAULT_NONE;
    
    }

6、通过1个对象接收参数

通常方法不要超过5个,当http请求的参数多的时候,我们可以使用一个对象来接收,对象中的参数名称和http请求中的参数名称一致。

比如有下面表单

    <form method="post" action="receiveparam/test4.do">
        姓名:<input name="name" value="路人"/> <br/>
        年龄:<input name="age" value="30"/><br/>
        <input type="submit" value="提交">
    </form>

我们可以定义一个UserInfoDto类来接收表单中的参数,这个类中有2个属性名称和上面表单中的属性名称一样。

    public class UserInfoDto {
        //姓名
        private String name;
        //年龄
        private Integer age;
    
        //省略了get、set方法
    
        @Override
        public String toString() {
            return "UserModel{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }

对应控制器的代码如下

    /**
     * 传递对象信息,参数比较多的时候,可以通过对象来传递信息
     * 比如表单中2个参数(name、age)
     * 那么可以定义一个类 UserInfoDto(2个属性:name、age) 来接收表单提交的参数
     * 控制器的方法参数为:(UserInfoDto userInfoDto)
     * springmvc调用这个方法的时候,会自动将UserModel创建好,并且将请求中的参数按名称设置到 UserInfoDto 的属性中,然后传递进来
     * 相当于会执行下面代码:
     * UserInfoDto user = new UserInfoDto();
     * user.setName(request.getParameter("name"));
     * user.setAge(Integer.valueOf(request.getParameter("age")));
     * 然后将user对象传给当前方法的第一个参数
     *
     * @param userInfoDto
     * @return
     */
    @RequestMapping("/receiveparam/test4.do")
    public ModelAndView test4(UserInfoDto userInfoDto) {
        String msg = String.format("userDto:%s", userInfoDto);
        System.out.println(msg);
    
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("/WEB-INF/view/result.jsp");
        modelAndView.addObject("msg", msg);
        return modelAndView;
    }

7、通过多个对象接收参数

上面我们将form表单有一个对象来接收,实际上也可以用多个对象来接收。

表单如下

    <form method="post" action="receiveparam/test5.do">
        姓名:<input name="name" value="路人"/> <br/>
        年龄:<input name="age" value="30"/><br/>
    
        工作年限:<input name="workYears" value="10"/> <br/>
        年龄:<input name="workAddress" value="上海市"/><br/>
        <input type="submit" value="提交">
    </form>

表单中有4个元素,我们用2个对象来接收,前面2个元素用UserInfoDto对象来接收,后面2个对象用WorkInfoDto对象来接收,我们需要定义2个类:UserInfoDto和WorkInfoDto

    /**
     * 用户基本信息
     */
    public class UserInfoDto {
        //姓名
        private String name;
        //年龄
        private Integer age;
    
         //省略了get、set方法
    
        @Override
        public String toString() {
            return "UserModel{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    
    /**
     * 工作基本信息
     */
    public class WorkInfoDto {
        //工作年限
        private Integer workYears;
        //工作地点
        private String workAddress;
    
    	//省略了get、set方法
    
        @Override
        public String toString() {
            return "WorkInfoDto{" +
                    "workYears=" + workYears +
                    ", workAddress='" + workAddress + '\'' +
                    '}';
        }
    }

对应的控制器方法如下

    /**
     * 也可以用多个对象来接收
     * 比如表单有4个元素[name,age,workYear,workAddress]
     * 其中请求的参数 name,age 赋值给UserInfoDto中的2个属性(name,age)
     * 另外2个参数 workYear,workAddress 赋值给WorkInfoDto中的2个属性(workYear,workAddress)
     *
     * @param userInfoDto
     * @param workInfoDto
     * @return
     */
    @RequestMapping("/receiveparam/test5.do")
    public ModelAndView test5(UserInfoDto userInfoDto, WorkInfoDto workInfoDto) {
        String msg = String.format("userInfoDto:[%s], workInfoDto:[%s]", userInfoDto, workInfoDto);
        System.out.println(msg);
    
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("/WEB-INF/view/result.jsp");
        modelAndView.addObject("msg", msg);
        return modelAndView;
    }

8、组合对象接收参数(对象中嵌套对象、集合等等)

如下表单

    <form method="post" action="receiveparam/test6.do">
    
        姓名:<input name="userInfo.name" value="路人"/> <br/>
        年龄:<input name="userInfo.age" value="30"/><br/>
    
        工作年限:<input name="workInfo.workYears" value="10"/> <br/>
        年龄:<input name="workInfo.workAddress" value="上海市"/><br/>
    
        第1份工作公司:<input name="experienceInfos[0].company" value="百度"/> <br/>
        第1份职位:<input name="experienceInfos[0].position" value="Java开发"/> <br/>
    
        第2份工作公司:<input name="experienceInfos[1].company" value="阿里"/> <br/>
        第2份职位:<input name="experienceInfos[1].position" value="Java资深开发"/> <br/>
    
        <input type="submit" value="提交">
    </form>

对应的控制器

    @RequestMapping("/receiveparam/test6.do")
    public ModelAndView test6(UserDto userDto) {
        String msg = String.format("userDto:[%s]", userDto);
        System.out.println(msg);
    
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("/WEB-INF/view/result.jsp");
        modelAndView.addObject("msg", msg);
        return modelAndView;
    }

重点要看方法参数UserDto这个类型的结构

    /**
     * 用户信息
     */
    public class UserDto {
        //个人基本信息
        private UserInfoDto userInfo;
        //工作信息
        private WorkInfoDto workInfo;
        //工作经验(0到n个)
        private List<ExperienceInfoDto> experienceInfos;
    
        //省略了get、set方法
    
        @Override
        public String toString() {
            return "UserDto{" +
                    "userInfo=" + userInfo +
                    ", workInfo=" + workInfo +
                    ", experienceInfos=" + experienceInfos +
                    '}';
        }
    }

UserDto类中有3个属性,2个对象,一个List集合,再来看看这3个类的代码

    /**
     * 用户基本信息
     */
    public class UserInfoDto {
        //姓名
        private String name;
        //年龄
        private Integer age;
    
         //省略了get、set方法
    
        @Override
        public String toString() {
            return "UserModel{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    
    /**
     * 工作基本信息
     */
    public class WorkInfoDto {
        //工作年限
        private Integer workYears;
        //工作地点
        private String workAddress;
    
    	//省略了get、set方法
    
        @Override
        public String toString() {
            return "WorkInfoDto{" +
                    "workYears=" + workYears +
                    ", workAddress='" + workAddress + '\'' +
                    '}';
        }
    }
    
    /**
     * 工作经验
     */
    public class ExperienceInfoDto {
        //公司
        private String company;
        //职位
        private String position;
    
        //省略了get、set方法
    
        @Override
        public String toString() {
            return "ExperienceInfoDto{" +
                    "company='" + company + '\'' +
                    ", position='" + position + '\'' +
                    '}';
        }
    }

这里主要注意下集合数据的传递方式,表单中的名称需要有下标,从0开始,如下图:

9、通过@PathVariable接受url中的参数

有时候我们请求的url是下面这样的,有一部是动态的,也就是/userInfo/后面的部分,是userId,具体userId的值是多少我们不知道,此时我们怎么办?

    /userInfo/1
    /userInfo/2
    /userInfo/3
    /userInfo/4
    ...
    /userInfo/{userId}

这种情况下就可以用到动态url了,比如下面控制器的代码,注意@RequestMapping注解的value值为/receiveparam/{v1}/{v2}.do,被{}包裹的部分就是动态的部分,方法参数中可以通过@PathVariabl取到url动态部分的值。

    /**
     * 动态url:url中可以使用{变量名称}来表示动态的部分,{}包裹的部分可以替换为任意内容
     * 比如:/receiveparam/{v1}/{v2}.do可以接受:/receiveparam/1/2.do、/receiveparam/路人/30.do 等等
     * @PathVariable("变量名称")可以获取到url中动态部分的内容,将其赋值给方法的形参
     * 比如当前方法收到了请求:/receiveparam/路人/30.do
     * 那么方法的第1个参数p1的值为:路人
     * 第2个参数p2的职位30
     *
     * @param p1
     * @param p2
     * @return
     */
    @RequestMapping("/receiveparam/{v1}/{v2}.do")
    public ModelAndView test7(@PathVariable("v1") String p1, @PathVariable("v2") String p2) {
        String msg = String.format("p1:[%s],p2:[%s]", p1, p2);
        System.out.println(msg);
    
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("/WEB-INF/view/result.jsp");
        modelAndView.addObject("msg", msg);
        return modelAndView;
    }

请求和值对应关系

请求url方法参数p1的值方法参数p2的值
/receiveparam/路人/30.do路人30
/receiveparam/1/2.do12

上面这些接受参数的方式可以组合,比如下面这样,同时有servlet对象和自定义对象

    @RequestMapping("/receiveparam/test8.do")
    public ModelAndView test8(HttpServletRequest request, HttpServletResponse response, UserDto userDto)

10、案例代码及测试用例

10.1、代码地址

    https://gitee.com/javacode2018/springmvc-series

可以下载下来部署到tomcat中运行查看上面每个案例的结果。

10.2、案例代码有两种运行方式

10.2.1、方式1:浏览器中查看效果

1、将chat02-receiveparam模块部署到tomcat中,然后访问首页即可看到案例,如下图

    http://localhost:8080/chat02/

10.2.2、方式2:HTTP Client的方式查看效果

通过idea中的 HTTP Client 来运行测试用例

如下图,HTTP Client测试用例代码都在chat02-receiveparam/src/test/resources/ReceiveParamController.http

下篇文章将介绍json格式数据的接收及原理 。

  • 17
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值