原文
https://mp.weixin.qq.com/s/2iC6f-WWZKvx9DdvmFFTZA
公众号:路人甲java
1、本文内容
Controller 中的方法如何接收 http 请求过来的参数呢?
具体有哪些方式呢?
这些就是本文讨论的重点,本文主要围绕下面这些方式来介绍参数的接收
接收 Servlet 中的参数:HttpServletRequest、HttpServletResponse、HttpSession
通过方法形参名称接收参数
通过@RequestParam 接收参数
通过 1 个对象接收参数
通过多个对象接收参数
组合对象接收参数(对象中嵌套对象集合等等)
通过@PathVariable 接受 url 中的参数
2、接收 Servlet 中的参数
比如我们想在方法中用到 servlet 中的对象:HttpServletRequest、HttpServletResponse、HttpSession,那么可以直接在方法的参数中声明这些对象即可,SpringMVC 会自动将这些参数传递进来,用到哪个就声明哪个
@RequestMapping("/receiveparam/test1.do")
publicModelAndViewtest1(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 =newModelAndView();
modelAndView.setViewName("/WEB-INF/view/result.jsp");
modelAndView.addObject("msg", msg);
returnmodelAndView;
}
对应的表单
姓名:
年龄:
form>
3、解决乱码问题
如果大家直接创建一个 springmvc 项目运行上面的案例,会发现 name 为中文的时候,会是乱码,这里需要在 web.xml 中添加下面配置,解决乱码问题
characterEncodingFilterfilter-name>
org.springframework.web.filter.CharacterEncodingFilterfilter-class>
encodingparam-name>
UTF-8param-value>
init-param>
forceRequestEncodingparam-name>
trueparam-value>
init-param>
forceResponseEncodingparam-name>
trueparam-value>
init-param>
filter>
characterEncodingFilterfilter-name>
/*url-pattern>
filter-mapping>
上面这段配置主要是添加了一个过滤器,这个过滤器会处理所有请求,相当于对所有请求会执行下面操作,而 encoding 我们设置的是 UTF-8
request.setCharacterEncoding(encoding);
response.setCharacterEncoding(encoding);
4、通过方法形参名称接收参数
表单
姓名:
年龄:
form>
控制器方法
/**
* springmvc调用这个方法之前,会根据方法参数名称,请求中获取参数的值,将其传入
* 过程:
* 1、将request.getParameter("name")传递给方法的第1个参数name
* 2、将Integer.valueOf(request.getParameter("age"))传递给方法的第2个参数age
*
*@paramname
*@paramage
*@return
*/
@RequestMapping("/receiveparam/test2.do")
publicModelAndViewtest2(String name, Integer age){
String msg = String.format("name:%s,age:%s", name, age);
System.out.println(msg);
ModelAndView modelAndView =newModelAndView();
modelAndView.setViewName("/WEB-INF/view/result.jsp");
modelAndView.addObject("msg", msg);
returnmodelAndView;
}
这种情况下,form 表单中的参数名称和控制器方法中的参数名称一样,会按照名称一一对应进行赋值。
5、通过@RequestParam 接收参数
如果方法的参数名称和表单中的参数名称不一致的时候,可以通过 @RequestParam 注解的 value 属性来指定表单中参数的名称。
比如下面表单的 2 个名称分别为:pname 和 page
姓名:
年龄:
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
*
*@paramname
*@paramage
*@return
*/
@RequestMapping("/receiveparam/test3.do")
publicModelAndViewtest3(@RequestParam("pname")String name,
@RequestParam("page")Integer age)
{
String msg = String.format("name:%s,age:%s", name, age);
System.out.println(msg);
ModelAndView modelAndView =newModelAndView();
modelAndView.setViewName("/WEB-INF/view/result.jsp");
modelAndView.addObject("msg", msg);
returnmodelAndView;
}
@RequestParam用来将请求的参数和方法的参数进行绑定,这个注解还有几个属性,也比较常用,大家熟悉下
public@interfaceRequestParam {
//参数名称
@AliasFor("name")
Stringvalue()default"";
//同value属性
@AliasFor("value")
Stringname()default"";
//参数是不是必须的,默认为true,如果请求中没有这个参数,springmvc会报错
booleanrequired()defaulttrue;
//默认值
StringdefaultValue()defaultValueConstants.DEFAULT_NONE;
}
6、通过 1 个对象接收参数
通常方法不要超过 5 个,当 http 请求的参数多的时候,我们可以使用一个对象来接收,对象中的参数名称和 http 请求中的参数名称一致。
比如有下面表单
姓名:"name" value="路人"/>
年龄:"age" value="30"/>
我们可以定义一个 UserInfoDto 类来接收表单中的参数,这个类中有 2 个属性名称和上面表单中的属性名称一样。
publicclassUserInfoDto{
//姓名
privateString name;
//年龄
privateInteger age;
//省略了get、set方法
@Override
publicStringtoString(){
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对象传给当前方法的第一个参数
*
*@paramuserInfoDto
*@return
*/
@RequestMapping("/receiveparam/test4.do")
publicModelAndViewtest4(UserInfoDto userInfoDto){
String msg = String.format("userDto:%s", userInfoDto);
System.out.println(msg);
ModelAndView modelAndView =newModelAndView();
modelAndView.setViewName("/WEB-INF/view/result.jsp");
modelAndView.addObject("msg", msg);
returnmodelAndView;
}
7、通过多个对象接收参数
上面我们将 form 表单有一个对象来接收,实际上也可以用多个对象来接收。
表单如下
姓名:
年龄:
工作年限:
年龄:
form>
表单中有 4 个元素,我们用 2 个对象来接收,前面 2 个元素用 UserInfoDto 对象来接收,后面 2 个对象用 WorkInfoDto 对象来接收,我们需要定义 2 个类:UserInfoDto 和 WorkInfoDto
/**
* 用户基本信息
*/
publicclassUserInfoDto{
//姓名
privateString name;
//年龄
privateInteger age;
//省略了get、set方法
@Override
publicStringtoString(){
return"UserModel{"+
"name='"+ name +'\''+
", age="+ age +
'}';
}
}
/**
* 工作基本信息
*/
publicclassWorkInfoDto{
//工作年限
privateInteger workYears;
//工作地点
privateString workAddress;
//省略了get、set方法
@Override
publicStringtoString(){
return"WorkInfoDto{"+
"workYears="+ workYears +
", workAddress='"+ workAddress +'\''+
'}';
}
}
对应的控制器方法如下
/**
* 也可以用多个对象来接收
* 比如表单有4个元素[name,age,workYear,workAddress]
* 其中请求的参数 name,age 赋值给UserInfoDto中的2个属性(name,age)
* 另外2个参数 workYear,workAddress 赋值给WorkInfoDto中的2个属性(workYear,workAddress)
*
*@paramuserInfoDto
*@paramworkInfoDto
*@return
*/
@RequestMapping("/receiveparam/test5.do")
publicModelAndViewtest5(UserInfoDto userInfoDto, WorkInfoDto workInfoDto){
String msg = String.format("userInfoDto:[%s], workInfoDto:[%s]", userInfoDto, workInfoDto);
System.out.println(msg);
ModelAndView modelAndView =newModelAndView();
modelAndView.setViewName("/WEB-INF/view/result.jsp");
modelAndView.addObject("msg", msg);
returnmodelAndView;
}
8、组合对象接收参数(对象中嵌套对象、集合等等)
如下表单
姓名:"userInfo.name" value="路人"/>
年龄:"userInfo.age" value="30"/>
工作年限:"workInfo.workYears" value="10"/>
年龄:"workInfo.workAddress" value="上海市"/>
第1份工作公司:
第1份职位:
第2份工作公司:
第2份职位:
对应的控制器
@RequestMapping("/receiveparam/test6.do")
publicModelAndViewtest6(UserDto userDto){
String msg = String.format("userDto:[%s]", userDto);
System.out.println(msg);
ModelAndView modelAndView =newModelAndView();
modelAndView.setViewName("/WEB-INF/view/result.jsp");
modelAndView.addObject("msg", msg);
returnmodelAndView;
}
重点要看方法参数UserDto这个类型的结构
/**
* 用户信息
*/
publicclassUserDto{
//个人基本信息
privateUserInfoDto userInfo;
//工作信息
privateWorkInfoDto workInfo;
//工作经验(0到n个)
privateListexperienceInfos;
//省略了get、set方法
@Override
publicStringtoString(){
return"UserDto{"+
"userInfo="+ userInfo +
", workInfo="+ workInfo +
", experienceInfos="+ experienceInfos +
'}';
}
}
UserDto 类中有 3 个属性,2 个对象,一个 List 集合,再来看看这 3 个类的代码
/**
* 用户基本信息
*/
publicclassUserInfoDto{
//姓名
privateString name;
//年龄
privateInteger age;
//省略了get、set方法
@Override
publicStringtoString(){
return"UserModel{"+
"name='"+ name +'\''+
", age="+ age +
'}';
}
}
/**
* 工作基本信息
*/
publicclassWorkInfoDto{
//工作年限
privateInteger workYears;
//工作地点
privateString workAddress;
//省略了get、set方法
@Override
publicStringtoString(){
return"WorkInfoDto{"+
"workYears="+ workYears +
", workAddress='"+ workAddress +'\''+
'}';
}
}
/**
* 工作经验
*/
publicclassExperienceInfoDto{
//公司
privateString company;
//职位
privateString position;
//省略了get、set方法
@Override
publicStringtoString(){
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
*
*@paramp1
*@paramp2
*@return
*/
@RequestMapping("/receiveparam/{v1}/{v2}.do")
publicModelAndViewtest7(@PathVariable("v1")String p1, @PathVariable("v2")String p2){
String msg = String.format("p1:[%s],p2:[%s]", p1, p2);
System.out.println(msg);
ModelAndView modelAndView =newModelAndView();
modelAndView.setViewName("/WEB-INF/view/result.jsp");
modelAndView.addObject("msg", msg);
returnmodelAndView;
}
请求和值对应关系
请求 url方法参数 p1 的值方法参数 p2 的值
/receiveparam/路人/30.do路人30
/receiveparam/1/2.do12
上面这些接受参数的方式可以组合,比如下面这样,同时有 servlet 对象和自定义对象
@RequestMapping("/receiveparam/test8.do")
publicModelAndViewtest8(HttpServletRequest request, HttpServletResponse response, UserDto userDto)
10、案例代码及测试用例
10.1、代码地址
https://gitee.com/javacode2018/springmvc-series
可以下载下来部署到 tomcat 中运行查看上面每个案例的结果。
10.2、案例代码有两种运行方式
10.2.1、方式 1:浏览器中查看效果
将 chat02-receiveparam 模块部署到 tomcat 中,然后访问首页即可看到案例,如下图
http://localhost:8080/chat02/
网友评论