SpringMVC之请求参数的获取方式

文章目录
  1. SpringMVC之请求参数的获取方式
    1. I. GET请求参数获取
      1. 1. 通过 HttpServletRequest获取参数
      2. 2. 直接方法参数获取
      3. 3. RequestParam注解方式获取请求参数
      4. 4. Bean方式获取参数
      5. 5. ModelAttribute注解方式
      6. 6. Path参数
    2. II. POST请求参数获取
      1. 1. HttpServletRequest方式获取参数
      2. 2. 方法参数获取
      3. 3. RequestParam注解方式
      4. 4. Bean方式
      5. 5. PathVariable
    3. III. 多媒体上传参数获取
      1. 1. 实例支持
    4. IV. 小结
      1. 1. 五种获取参数的姿势
      2. 2. 传文件使用姿势
    5. V. 其他
      1. 声明
      2. 扫描关注,java分享

SpringMVC之请求参数的获取方式

常见的一个web服务,如何获取请求参数?

一般最常见的请求为GET和POST,get请求的参数在url上可以获取,post请求参数除了url上还有可能在表单中,文件上传时,获取方式又和一般的参数获取不一样

本篇则主要集中在不同请求方式下,获取参数的使用姿势

首先需要搭建一个后端的请求,为了快速演示

利用spring-boot创建了一个机器简单的工程,依赖版本 1.5.4.RELEASE

I. GET请求参数获取

get请求参数,一般都是直接挂在请求的url上,所以获取这些参数还是比较简单的

1. 通过 HttpServletRequest获取参数

这个可以说是最基本最常见的的方式了,javax.servlet.ServletRequest#getParameter 来获取对应的参数,下面各处一个实例

1
2
3
4
5
6
7
8
9
10
11
@RestController
@RequestMapping(path = "webs/demo")
public class DemoController {

@RequestMapping(path = "req1")
public String req1(HttpServletRequest request) {
String user = request.getParameter("user");
String password = request.getParameter("password");
return "req1 user: " + user + " pwd: " + password;
}
}

根据上面暴露的接口,我们测试的case就很简单了

1
2
3
4
5
http://127.0.0.1:8080/webs/demo/req1?user=小灰灰Blog&password=123456
## 输出 req1 user: 小灰灰Blog pwd: 123456

http://127.0.0.1:8080/webs/demo/req1?user=小灰灰Blog
## 输出 req1 user: 小灰灰Blog pwd: null

说明

  • 这是一个最基本的获取参数的方式,get,post请求都适用的,通常在filter,intercepter中也是可以通过HttpServletRequest对象来获取请求参数
  • 除了获取常见的请求参数之外,HttpServletRequest可以获取请求头的完整信息
  • 在一次请求的生命周期内,可以通过下面的方式获取Request对象(当然也可以获取response对象)

    1
    2
    HttpServletRequest httpServletRequest = ((ServletRequestAttributes) 
    RequestContextHolder.getRequestAttributes()).getRequest();

2. 直接方法参数获取

直接给出case, 这个方法依然是放在上面的DemoController下面的

1
2
3
4
@RequestMapping(path = "req2")
public String req2(String user, String password) {
return "req2 user: " + user + " pwd: " + password;
}

请求验证

1
2
3
4
5
6
7
8
9
10
http://127.0.0.1:8080/webs/demo/req2?user=%E5%B0%8F%E7%81%B0%E7%81%B0Blog&password=123456
## 输出: req2 user: 小灰灰Blog pwd: 123456


http://127.0.0.1:8080/webs/demo/req2?password=123456
## 输出: req2 user: null pwd: 123456


http://127.0.0.1:8080/webs/demo/req2?password=123456&User=blog
## 输出: req2 user: null pwd: 123456

注意:

  • 上面这种使用方式,相当于直接将url参数映射到了Controller方法的参数上了
  • 方法参数名必须和url参数名完全一致(区分大小写)
  • 顺序无关
  • 若参数没传,则默认为null

一个疑问

上面的demo中Controller的方法参数都是String还好,如果将password改成int,会出现什么情况

代码稍作修改

1
2
3
4
@RequestMapping(path = "req2")
public String req2(String user, int password) {
return "req2 user: " + user + " pwd: " + password;
}

实际测试

1
2
3
4
5
6
7
8
9
10
11
12
13
# case1 
http://127.0.0.1:8080/webs/demo/req2?password=123456&user=blog
## 输出: req2 user: blog pwd: 123456


# case 2
http://127.0.0.1:8080/webs/demo/req2?password2=123456&user=blog
## 输出: 报错, Optional int parameter 'password' is present but cannot be translated into a null value due to being declared as a primitive type. Consider declaring it as object wrapper for the corresponding primitive type


# case 3
http://127.0.0.1:8080/webs/demo/req2?password=abc&user=blog
## 输出:报错, "Failed to convert value of type 'java.lang.String' to required type 'int'; nested exception is java.lang.NumberFormatException: For input string: "abc""

结果说明

  • 如果请求参数与方法参数类型不一致,会抛出转换异常
  • 如果方法参数为非封装基本类型,则url参数必须存在,否则报错

3. RequestParam注解方式获取请求参数

通过@RequestParam注解获取参数的方式和上面的一种比较类似,case如下

1
2
3
4
5
@RequestMapping(path = "req3", method = RequestMethod.GET)
public String req3(@RequestParam("user") String username,
@RequestParam("password") String pwd) {
return "req3 user: " + username + " pwd: " + pwd;
}

测试case

1
2
3
4
5
6
7
8
# case1 
http://127.0.0.1:8080/webs/demo/req3?password=123456&user=blog
## 输出: req3 user: blog pwd: 123456


# case2
http://127.0.0.1:8080/webs/demo/req3?password=123456
## 输出:报错, Required String parameter 'user' is not presen

说明

  • 不指定注解的name或value属性时,等同于第二种使用姿势
  • 注解的name属性或value属性,用实际的参数名来指定
  • controller的参数名与url参数名没有强关联(区别第二种方式)
  • 参数类型需要保证一致(通第二种方式)
  • 如果url参数可选,请设置require属性为false,如下
    1
    @RequestParam(name = "user",  required = false) String username

4. Bean方式获取参数

对于请求参数比较复杂的情况下,我比较喜欢这种使用姿势,管理起来方便简单

1
2
3
4
5
6
7
8
9
10
@Data
public static class UserDO {
String user;
String password;
}

@RequestMapping(path = "req4", method = RequestMethod.GET)
public String req4(UserDO userDO) {
return "req4 userDO: " + userDO;
}

测试case

1
2
3
4
5
6
7
8
# case1
http://127.0.0.1:8080/webs/demo/req4?password=123456&user=%E5%B0%8F%E7%81%B0%E7%81%B0Blog
## 输出: req4 userDO: DemoController.UserDO(user=小灰灰Blog, password=123456)


# case2
http://127.0.0.1:8080/webs/demo/req4?password=123456
## 输出: req4 userDO: DemoController.UserDO(user=null, password=123456)

说明

  • 定义一个bean,内部属性和请求参数对应
  • 允许参数不存在的情况,会使用null代替(所以,尽量不要使用非封装基本类型,否则参数不传时,会抛异常)
  • bean的属性,可以根据实际情况指定类型

5. ModelAttribute注解方式

@ModelAttribute注解的方法,会优于Controller之前执行,一般更常见于向视图传输数据使用,此处不详细展开,正常来讲,专门的获取参数不太会用这这种方式来玩

6. Path参数

Path参数,专指的是请求路径的参数,如

1
http://127.0.0.1:8080/webs/demo/req4?password=123456

上面这个url中,password是我们传统意义上的请求参数,其中path参数则是指其中 req4, demo这种path路径中的一环;对此,最常见的一个case就是常见的博客中,如开源中国的一个博客链接

1
https://my.oschina.net/u/566591/blog/1601400
  • 566591 : 这个参数主要用来区分用户
  • 1601400 : 这个参数则主要是表示对应的博文

一般path参数的获取方式如下

1
2
3
4
@RequestMapping(path = "req6/{user}/info")
public String req6(@PathVariable(name = "user") String user) {
return "req6 user: " + user;
}

测试case

1
2
3
4
5
6
7
8
9
10
11
# case1 
http://127.0.0.1:8080/webs/demo/req6/blog/info?user=haha
## 输出:req6 user: blog

# case2
http://127.0.0.1:8080/webs/demo/req6/blog?user=haha
## 输出: 404

# case3
http://127.0.0.1:8080/webs/demo/req6/info?user=haha
## 输出: 404

注意:

  • path参数的使用,需要确保参数存在且类型匹配
  • path参数和url参数不会相互影响

II. POST请求参数获取

POST请求参数,更多的是看提交表单参数是否可以获取到,以及如何获取,主要的手段依然是上面几种方式,下面验证下是否ok

1. HttpServletRequest方式获取参数

测试case,可以借助curl来实现post请求

1
2
3
4
5
6
7
8
9
10
11
12
# case1 
curl -d "user=小灰灰Blog&password=123456" "http://127.0.0.1:8080/webs/demo/req1"
## 输出: req1 user: 小灰灰Blog pwd: 123456

# case2
curl -d "user=小灰灰Blog" "http://127.0.0.1:8080/webs/demo/req1?password=123456"
## 输出:req1 user: 小灰灰Blog pwd: 12345


# case3
curl -d "user=小灰灰Blog" "http://127.0.0.1:8080/webs/demo/req1?user=greyBlog"
## 输出:req1 user: greyBlog pwd: null

curl也可以换成js请求测试方式

1
2
3
4
5
6
7
8
9
10
11
var formData = new FormData();
formData.append("user", "小灰灰Blog");

$.ajax({
url: 'http://127.0.0.1:8080/webs/demo/req1?password=123456',
type: 'post',
cache: false,
data: formData,
processData: false,
contentType: false
});

说明

  • 对于HttpServletReuqest方式获取参数时,get和post没什么区别
  • 若url参数和表单参数同名了,测试结果显示使用的是url参数(待确认,当然最好不要这么干)

2. 方法参数获取

几个测试demo如下

1
2
3
4
5
6
7
8
9
10
11
12
13
# case 1
curl -d "user=小灰灰Blog&password=123456" "http://127.0.0.1:8080/webs/demo/req2"
## 输出: req2 user: 小灰灰Blog pwd: 123456


# case 2
curl -d "password=123456" "http://127.0.0.1:8080/webs/demo/req2"
## 输出:req2 user: null pwd: 123456


# case 3
curl -d "password=123456" "http://127.0.0.1:8080/webs/demo/req2?user=blog"
## 输出: req2 user: blog pwd: 123456

基本上使用姿势和get没什么区别

3. RequestParam注解方式

1
2
3
4
5
6
7
8
9
10
11
12
13
# case 1
curl -d "password=123456&user=blog" "http://127.0.0.1:8080/webs/demo/req3"
## 输出: req3 user: blog pwd: 123456


# case 2
curl -d "password=123456" "http://127.0.0.1:8080/webs/demo/req3?user=blog"
## 输出: req3 user: blog pwd: 123456


# case 3
curl -d "password=123456&user=blog" "http://127.0.0.1:8080/webs/demo/req3?password=900"
## 输出:req3 user: blog pwd: 900,123456

注意

  • 和前面的两种方式不同的是,当post表单的参数和url参数同名时,会合并成一个字符串

4. Bean方式

1
2
3
4
5
6
7
8
9
10
11
12
13
## case1 
curl -d "password=123456&user=blog" "http://127.0.0.1:8080/webs/demo/req4?password=900"
## 输出 req4 userDO: DemoController.UserDO(user=blog, password=900,123456)


## case2
curl -d "password=123456&user=blog" "http://127.0.0.1:8080/webs/demo/req4"
## 输出 req4 userDO: DemoController.UserDO(user=blog, password=123456)


## case3
curl -d "password=123456" "http://127.0.0.1:8080/webs/demo/req4"
## 输出 req4 userDO: DemoController.UserDO(user=null, password=123456)

这种方式不区分get,post,所以完全复杂的交互接口,完全可以考虑用bean的方式来定义请求参数

5. PathVariable

这个没法玩…

III. 多媒体上传参数获取

上传文件的支持,对于传统的spring-mvc来说,可能需要一些添加一些相关配置,不在本文的范畴内,下面默认已经配置好

1. 实例支持

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RequestMapping(path = {"wx/upload", "wx/wx/upload"}, method = {RequestMethod.GET, RequestMethod.POST, RequestMethod.OPTIONS})
@ResponseBody
public String upload(HttpServletRequest request) {
MultipartFile file = null;
if (request instanceof MultipartHttpServletRequest) {
file = ((MultipartHttpServletRequest) request).getFile("image");
}

if (file == null) {
throw new IllegalArgumentException("图片不能为空!");
}

return "success";
}

简单来说,主要是利用HttpServletRequest来获取上传的文件

注意:

  • 如果接口必须要求上传文件,可以直接把参数声明为 MultipartHttpServletRequest, 此时调用方如果不传参数,会被异常拦截(可以通过@ControllerAdvice来拦截全局异常)
  • 如果可以不上传文件,则可以用上面的这种猥琐姿势,内部进行判断
  • ((MultipartHttpServletRequest) request).getFile(xxx)来获取指定名的上传文件

IV. 小结

1. 五种获取参数的姿势

方式 注意事项
HttpServletRequest获取参数 最常见通用
方法参数与请求参数同名 注意参数名统一,注意类型一致,尽量不用非包装基本类型
@RequestParam注解 同上,可注解内指定http参数名
Bean方式 定义一个bean,会将同名的http参数赋值进去,推荐
@PathVariable 注解 请求url参数

2. 传文件使用姿势

使用MultipartHttpServletRequest来获取上传的文件,当然也可以获取基本的请求参数

V. 其他

声明

尽信书则不如,已上内容,纯属一家之言,因本人能力一般,见解不全,如有问题,欢迎批评指正

扫描关注,java分享

QrCode

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×