SpringMVC系列第4篇:接受參數(shù)有多少種方式?
大家好,我是【路人甲 Java】號(hào)主路人,本文如果對(duì)你有幫助,點(diǎn)個(gè)在看,順便忙轉(zhuǎn)發(fā)一下,非常需要大家的支持,對(duì) java 有興趣的朋友歡迎加我微信 itsoku 交流。
1、本文內(nèi)容
Controller 中的方法如何接收 http 請(qǐng)求過(guò)來(lái)的參數(shù)呢?
具體有哪些方式呢?
這些就是本文討論的重點(diǎn),本文主要圍繞下面這些方式來(lái)介紹參數(shù)的接收
接收 Servlet 中的參數(shù):HttpServletRequest、HttpServletResponse、HttpSession 通過(guò)方法形參名稱接收參數(shù) 通過(guò)@RequestParam 接收參數(shù) 通過(guò) 1 個(gè)對(duì)象接收參數(shù) 通過(guò)多個(gè)對(duì)象接收參數(shù) 組合對(duì)象接收參數(shù)(對(duì)象中嵌套對(duì)象集合等等) 通過(guò)@PathVariable 接受 url 中的參數(shù)
2、接收 Servlet 中的參數(shù)
比如我們想在方法中用到 servlet 中的對(duì)象:HttpServletRequest、HttpServletResponse、HttpSession,那么可以直接在方法的參數(shù)中聲明這些對(duì)象即可,SpringMVC 會(huì)自動(dòng)將這些參數(shù)傳遞進(jìn)來(lái),用到哪個(gè)就聲明哪個(gè)
@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;
}
對(duì)應(yīng)的表單
<form method="post" action="receiveparam/test1.do">
姓名:<input name="name" value="路人"/> <br/>
年齡:<input name="age" value="30"/><br/>
<input type="submit" value="提交">
form>
3、解決亂碼問(wèn)題
如果大家直接創(chuàng)建一個(gè) springmvc 項(xiàng)目運(yùn)行上面的案例,會(huì)發(fā)現(xiàn) name 為中文的時(shí)候,會(huì)是亂碼,這里需要在 web.xml 中添加下面配置,解決亂碼問(wèn)題
<filter>
<filter-name>characterEncodingFilterfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>UTF-8param-value>
init-param>
<init-param>
<param-name>forceRequestEncodingparam-name>
<param-value>trueparam-value>
init-param>
<init-param>
<param-name>forceResponseEncodingparam-name>
<param-value>trueparam-value>
init-param>
filter>
<filter-mapping>
<filter-name>characterEncodingFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
上面這段配置主要是添加了一個(gè)過(guò)濾器,這個(gè)過(guò)濾器會(huì)處理所有請(qǐng)求,相當(dāng)于對(duì)所有請(qǐng)求會(huì)執(zhí)行下面操作,而 encoding 我們?cè)O(shè)置的是 UTF-8
request.setCharacterEncoding(encoding);
response.setCharacterEncoding(encoding);
4、通過(guò)方法形參名稱接收參數(shù)
表單
<form method="post" action="receiveparam/test2.do">
姓名:<input name="name" value="路人"/> <br/>
年齡:<input name="age" value="30"/><br/>
<input type="submit" value="提交">
form>
控制器方法
/**
* springmvc調(diào)用這個(gè)方法之前,會(huì)根據(jù)方法參數(shù)名稱,請(qǐng)求中獲取參數(shù)的值,將其傳入
* 過(guò)程:
* 1、將request.getParameter("name")傳遞給方法的第1個(gè)參數(shù)name
* 2、將Integer.valueOf(request.getParameter("age"))傳遞給方法的第2個(gè)參數(shù)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 表單中的參數(shù)名稱和控制器方法中的參數(shù)名稱一樣,會(huì)按照名稱一一對(duì)應(yīng)進(jìn)行賦值。
5、通過(guò)@RequestParam 接收參數(shù)
如果方法的參數(shù)名稱和表單中的參數(shù)名稱不一致的時(shí)候,可以通過(guò) @RequestParam 注解的 value 屬性來(lái)指定表單中參數(shù)的名稱。
比如下面表單的 2 個(gè)名稱分別為: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>
對(duì)應(yīng)的方法如下,2 個(gè)形參的參數(shù)名稱分別為 name 和 age,和表單中的名稱不一致了,那么可以在方法的參數(shù)前面加上@RequestParam 注解,注解的 value 為表單中元素的名稱,參數(shù) name 希望接受表單中 pname 的值,那么就需要在 name 這個(gè)參數(shù)前面加上@RequestParam("pname"),方法的第 2 個(gè)參數(shù)也一樣,加上了@RequestParam("page")
/**
* 如果方法的參數(shù)名稱和表單中的參數(shù)名稱不一致的時(shí)候,可以通過(guò) @RequestParam注解的value屬性來(lái)指定表單中參數(shù)的名稱
* 比如:@RequestParam("pname") String name 接收 request.getParameter("pname") 的值
* 1、將request.getParameter("pname")傳遞給方法的第1個(gè)參數(shù)name
* 2、將Integer.valueOf(request.getParameter("page"))傳遞給方法的第2個(gè)參數(shù)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用來(lái)將請(qǐng)求的參數(shù)和方法的參數(shù)進(jìn)行綁定,這個(gè)注解還有幾個(gè)屬性,也比較常用,大家熟悉下
public @interface RequestParam {
//參數(shù)名稱
@AliasFor("name")
String value() default "";
//同value屬性
@AliasFor("value")
String name() default "";
//參數(shù)是不是必須的,默認(rèn)為true,如果請(qǐng)求中沒(méi)有這個(gè)參數(shù),springmvc會(huì)報(bào)錯(cuò)
boolean required() default true;
//默認(rèn)值
String defaultValue() default ValueConstants.DEFAULT_NONE;
}
6、通過(guò) 1 個(gè)對(duì)象接收參數(shù)
通常方法不要超過(guò) 5 個(gè),當(dāng) http 請(qǐng)求的參數(shù)多的時(shí)候,我們可以使用一個(gè)對(duì)象來(lái)接收,對(duì)象中的參數(shù)名稱和 http 請(qǐng)求中的參數(shù)名稱一致。
比如有下面表單
<form method="post" action="receiveparam/test4.do">
姓名:"name" value="路人"/>
年齡:"age" value="30"/>
<input type="submit" value="提交">
</input type=</form method=我們可以定義一個(gè) UserInfoDto 類來(lái)接收表單中的參數(shù),這個(gè)類中有 2 個(gè)屬性名稱和上面表單中的屬性名稱一樣。
public class UserInfoDto {
//姓名
private String name;
//年齡
private Integer age;
//省略了get、set方法
@Override
public String toString() {
return "UserModel{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
對(duì)應(yīng)控制器的代碼如下
/**
* 傳遞對(duì)象信息,參數(shù)比較多的時(shí)候,可以通過(guò)對(duì)象來(lái)傳遞信息
* 比如表單中2個(gè)參數(shù)(name、age)
* 那么可以定義一個(gè)類 UserInfoDto(2個(gè)屬性:name、age) 來(lái)接收表單提交的參數(shù)
* 控制器的方法參數(shù)為:(UserInfoDto userInfoDto)
* springmvc調(diào)用這個(gè)方法的時(shí)候,會(huì)自動(dòng)將UserModel創(chuàng)建好,并且將請(qǐng)求中的參數(shù)按名稱設(shè)置到 UserInfoDto 的屬性中,然后傳遞進(jìn)來(lái)
* 相當(dāng)于會(huì)執(zhí)行下面代碼:
* UserInfoDto user = new UserInfoDto();
* user.setName(request.getParameter("name"));
* user.setAge(Integer.valueOf(request.getParameter("age")));
* 然后將user對(duì)象傳給當(dāng)前方法的第一個(gè)參數(shù)
*
* @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、通過(guò)多個(gè)對(duì)象接收參數(shù)
上面我們將 form 表單有一個(gè)對(duì)象來(lái)接收,實(shí)際上也可以用多個(gè)對(duì)象來(lái)接收。
表單如下
<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 個(gè)元素,我們用 2 個(gè)對(duì)象來(lái)接收,前面 2 個(gè)元素用 UserInfoDto 對(duì)象來(lái)接收,后面 2 個(gè)對(duì)象用 WorkInfoDto 對(duì)象來(lái)接收,我們需要定義 2 個(gè)類: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;
//工作地點(diǎn)
private String workAddress;
//省略了get、set方法
@Override
public String toString() {
return "WorkInfoDto{" +
"workYears=" + workYears +
", workAddress='" + workAddress + '\'' +
'}';
}
}
對(duì)應(yīng)的控制器方法如下
/**
* 也可以用多個(gè)對(duì)象來(lái)接收
* 比如表單有4個(gè)元素[name,age,workYear,workAddress]
* 其中請(qǐng)求的參數(shù) name,age 賦值給UserInfoDto中的2個(gè)屬性(name,age)
* 另外2個(gè)參數(shù) workYear,workAddress 賦值給WorkInfoDto中的2個(gè)屬性(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、組合對(duì)象接收參數(shù)(對(duì)象中嵌套對(duì)象、集合等等)
如下表單
<form method="post" action="receiveparam/test6.do">
姓名:"userInfo.name" value="路人"/>
年齡:"userInfo.age" value="30"/>
工作年限:"workInfo.workYears" value="10"/>
年齡:"workInfo.workAddress" value="上海市"/>
第1份工作公司:<input name="experienceInfos[0].company" value="百度"/>
第1份職位:<input name="experienceInfos[0].position" value="Java開(kāi)發(fā)"/>
第2份工作公司:<input name="experienceInfos[1].company" value="阿里"/>
第2份職位:<input name="experienceInfos[1].position" value="Java資深開(kāi)發(fā)"/>
<input type="submit" value="提交">
</input type=</input name=</input name=</input name=</input name=</form method=對(duì)應(yīng)的控制器
@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;
}
重點(diǎn)要看方法參數(shù)UserDto這個(gè)類型的結(jié)構(gòu)
/**
* 用戶信息
*/
public class UserDto {
//個(gè)人基本信息
private UserInfoDto userInfo;
//工作信息
private WorkInfoDto workInfo;
//工作經(jīng)驗(yàn)(0到n個(gè))
private List experienceInfos;
//省略了get、set方法
@Override
public String toString() {
return "UserDto{" +
"userInfo=" + userInfo +
", workInfo=" + workInfo +
", experienceInfos=" + experienceInfos +
'}';
}
}
UserDto 類中有 3 個(gè)屬性,2 個(gè)對(duì)象,一個(gè) List 集合,再來(lái)看看這 3 個(gè)類的代碼
/**
* 用戶基本信息
*/
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;
//工作地點(diǎn)
private String workAddress;
//省略了get、set方法
@Override
public String toString() {
return "WorkInfoDto{" +
"workYears=" + workYears +
", workAddress='" + workAddress + '\'' +
'}';
}
}
/**
* 工作經(jīng)驗(yàn)
*/
public class ExperienceInfoDto {
//公司
private String company;
//職位
private String position;
//省略了get、set方法
@Override
public String toString() {
return "ExperienceInfoDto{" +
"company='" + company + '\'' +
", position='" + position + '\'' +
'}';
}
}
這里主要注意下集合數(shù)據(jù)的傳遞方式,表單中的名稱需要有下標(biāo),從 0 開(kāi)始,如下圖:

9、通過(guò)@PathVariable 接受 url 中的參數(shù)
有時(shí)候我們請(qǐng)求的 url 是下面這樣的,有一部是動(dòng)態(tài)的,也就是/userInfo/后面的部分,是 userId,具體 userId 的值是多少我們不知道,此時(shí)我們?cè)趺崔k?
/userInfo/1
/userInfo/2
/userInfo/3
/userInfo/4
...
/userInfo/{userId}
這種情況下就可以用到多態(tài) url 了,比如下面控制器的代碼,注意@RequestMapping注解的 value 值為/receiveparam/{v1}/{v2}.do,被{}包裹的部分就是動(dòng)態(tài)的部分,方法參數(shù)中可以通過(guò)@PathVariabl取到 url 動(dòng)態(tài)部分的值。
/**
* 動(dòng)態(tài)url:url中可以使用{變量名稱}來(lái)表示動(dòng)態(tài)的部分,{}包裹的部分可以替換為任意內(nèi)容
* 比如:/receiveparam/{v1}/{v2}.do可以接受:/receiveparam/1/2.do、/receiveparam/路人/30.do 等等
* @PathVariable("變量名稱")可以獲取到url中動(dòng)態(tài)部分的內(nèi)容,將其賦值給方法的形參
* 比如當(dāng)前方法收到了請(qǐng)求:/receiveparam/路人/30.do
* 那么方法的第1個(gè)參數(shù)p1的值為:路人
* 第2個(gè)參數(shù)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;
}

請(qǐng)求和值對(duì)應(yīng)關(guān)系
| 請(qǐng)求 url | 方法參數(shù) p1 的值 | 方法參數(shù) p2 的值 |
|---|---|---|
| /receiveparam/路人/30.do | 路人 | 30 |
| /receiveparam/1/2.do | 1 | 2 |
上面這些接受參數(shù)的方式可以組合,比如下面這樣,同時(shí)有 servlet 對(duì)象和自定義對(duì)象
@RequestMapping("/receiveparam/test8.do")
public ModelAndView test8(HttpServletRequest request, HttpServletResponse response, UserDto userDto)
10、案例代碼及測(cè)試用例
10.1、代碼地址
https://gitee.com/javacode2018/springmvc-series
可以下載下來(lái)部署到 tomcat 中運(yùn)行查看上面每個(gè)案例的結(jié)果。
10.2、案例代碼有兩種運(yùn)行方式
10.2.1、方式 1:瀏覽器中查看效果
將 chat02-receiveparam 模塊部署到 tomcat 中,然后訪問(wèn)首頁(yè)即可看到案例,如下圖
http://localhost:8080/chat02/

10.2.2、方式 2:HTTP Client 的方式查看效果
通過(guò) idea 中的HTTP Client來(lái)運(yùn)行測(cè)試用例,HTTP Client用法不知道的朋友,可以移步:異常高效的接口測(cè)試?yán)?HTTP Client
如下圖,HTTP Client 測(cè)試用例代碼都在chat02-receiveparam/src/test/resources/ReceiveParamController.http中

下篇文章將介紹 json 格式數(shù)據(jù)的接收及原理。
11、推薦一個(gè)高質(zhì)量的公眾號(hào)
這里給大家推薦一個(gè)公眾號(hào):Java 充電社,掃碼大家關(guān)注下,這個(gè)號(hào)中會(huì)定期發(fā)布一些高質(zhì)量的 java 專題視頻,幫大家充電。
