springMVC Controller的传参方式非常灵活,灵活的好处是选择很多,反之弊端就是有时候很容易迷惑,本文是对常用的传参方式做个总结,还有很多方式本次不涉及,比如非前端传过来的参数httpservletrequest、httpservletresponse、modelview等和@PathVariable获取rest风格参数的方式不在讨论之列。
1.实验工具postman和一段controller代码
postman是大家比较常用的一个HTTP请求的客户端,在postman中请求参数有几个选项供选择
- none不传参数
- form-data
代表http请求中Content-Type请求头的值为multipart/form-data,它会将表单的数据处理为一条消息,以标签为单元,用分隔符分开。既可以上传键值对,也可以上传文件。当上传的字段是文件时,会有Content-Type来说明文件类型;content-disposition,用来说明字段的一些信息;由于有boundary隔离,所以multipart/form-data既可以上传文件,也可以上传键值对,它采用了键值对的方式,所以可以上传多个文件。在postman中可以看选择vaule时可以选择text和file类型。 - x-www-form-urlencoded
代表http请求中Content-Type请求头的值为application/x-www-from-urlencoded,会将表单内的数据转换为键值对,比如name=java&age = 23,一般用ajax提交页面表单采用的默认方式就是这个。 - raw
原始字符串, 可以上传任意格式的文本,可以上传text、json、xml、html等最常用的格式,一般传一个json字符串。请求头一般如下这样 Content-Type:“text/plain” 文本 ,Content-Type:“application/json” json格式,Content-Type:“application/xml” xml格式 ,Content-Type:“text/html” html格式 - binary
代表http请求中Content-Type请求头的值为Content-Type:application/octet-stream,从字面意思得知,只可以上传二进制数据,通常用来上传文件,由于没有键值,所以,一次只能上传一个文件。
2.先总结
1.本文总结的方式有5中:
- 使用@RequestBody来接收
- 采用实体类来接收
- 采用Map接收
- 采用单个参数并且不加@requestParament的方式的方式接受参数
- 采用单个参数并且加上@requestParament的方式的方式接受参数
2.get方法除了注意采用Map的方式接受参数 必须加上@RequestParam 其余的方法无论Content-Type为什么都能很好的完成参数的接收
3.post方法 如果用的是json格式的话只能用@RequestBody 接收json数据并解析其余的方式不行,反之其余四种方式不能接收JSON请求参数,正常的表单提交都可以。
4.@RequestMapping 默认不填提交方式的情况下用的是浏览器用的什么方法提交采用的就是什么方法不限制 填了方法会限制方法的请求方式
5.即使方法名称不同 @RequestMapping注解内容一样启动spring会报错
3.get方式请求
首先说明一下 Content-Type采用什么格式 对get方式没影响。
1.使用@RequestBody来接收
这种方式接收参数类型只能是String,拿的直接是请求体里面的字符串内容,springMVC似乎默认将get方式的参数组装成了json格式可以用@RequestBody接收请求体字符串并解析json获取到参数
@RequestMapping(value = "/add", method = RequestMethod.GET)
public Result addtUserGet(@RequestBody String user) {
JSONObject parseObject = JSON.parseObject(user);
String name = parseObject.getString("name");
String userid = parseObject.getString("userid");
String age = parseObject.getString("age");
String phone = parseObject.getString("phone");
User user2 = new User(name, age, phone, userid);
return ResultUtil.success(user2);
}
2.采用实体类来接收
@RequestMapping(value = "/addbyuser", method = RequestMethod.GET)
public Result addtUserGet(User user) {
return ResultUtil.success(user);
}
3.采用Map接收
采用MAP的方式接受参数 必须加上@RequestParam 个人感觉用这个不如一个个参数的传入来的实际,一个可读性不好,其次参数验证不好做,唯一的好处参数扩展性好。
@RequestMapping(value = "/addbymap", method = RequestMethod.GET)
public Result addtUserGet(@RequestParam Map<String, Object> map) {
String name = (String) map.get("name");
String userid = (String) map.get("userid");
String age = (String) map.get("age");
String phone = (String) map.get("phone");
User user = new User(name, age, phone, userid);
return ResultUtil.success(user);
}
4.采用单个参数并且不加@requestParament的方式的方式接受参数
这种方式默认是不会验证参数是否为空值的
@RequestMapping(value = "/addbywithoutrequestparament", method = RequestMethod.GET)
public Result addtUserGet(String name, String age, String phone, String userid) {
User user = new User(name, age, phone, userid);
return ResultUtil.success(user);
}
5.采用单个参数并且加上@requestParament的方式的方式接受参数
@RequestParam(value = “name”,defaultValue = “user”,required = false)
value 报文的字段名称 defaultValue 默认值 required 默认为true会自动验证是否为空
@RequestMapping(value = "/addbywithrequestparament", method = RequestMethod.GET)
public Result addtUserGetadd(
@RequestParam(value = "name", defaultValue = "yuwenkai1", required = false) String name,
@RequestParam String age, @RequestParam String phone, @RequestParam String userid) {
User user = new User(name, age, phone, userid);
return ResultUtil.success(user);
}
采用方式5可以做一个全局异常的处理来验证入参是否为空并返回给客户端友好提示
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* 在控制层做的全局异常拦截处理
* @author Administrator
*
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
/**
* 处理参数为空的异常
*/
@ExceptionHandler(value = MissingServletRequestParameterException.class)
public Result MissingServletRequestParameterExceptionHandler(HttpServletRequest req, MissingServletRequestParameterException e){
logger.info("请求路径:"+req.getRequestURI()+","+e.getParameterName()+"参数为空",e);
return new Result(500,e.getParameterName()+"不能为空");
}
}
4.post方式请求
首先说明一下 Content-Type采用什么格式对post的方式影响很大。这里我们将Content-Type="multipart/form-data 和Content-Type="application/x-www-form-urlencoded"算作一类普通的post提交,将raw中各种文本格式算作一类,因为实际开发中用的比较多的就是json格式,所以这一类就只考虑json文本。
1.使用@RequestBody来接收
这种方式接收参数类型只能是String,拿的直接是请求体里面的字符串内容,当请求是json数据时 Content-Type=“application/json” ,此时只能采用@RequestBody方式接受并解析json获取数据。其他请求头拿到的请求体字符串不是json格式的解析不了,拿到的数据结构是这样name=yuwenkaihh&age=12&phone=112&userid=888988。
@RequestMapping(value = ("/addtest"), method = RequestMethod.POST)
public Result addtUserGetpost(@RequestBody String user) {
JSONObject parseObject = JSON.parseObject(user);
String name = parseObject.getString("name");
String userid = parseObject.getString("userid");
String age = parseObject.getString("age");
String phone = parseObject.getString("phone");
User user2 = new User(name, age, phone, userid);
return ResultUtil.success(user2);
}
2.采用实体类来接收
Content-Type="multipart/form-data 和Content-Type="application/x-www-form-urlencoded"请求头是可以拿到请求参数的,但是采用json格式Content-Type="application/json"不行,而且有个好玩的现象,如果用get方式在URL加上参数同时再用post提交参数返回结果是这样的{ “code”: 0, “data”: { “name”: “name1,name”, “age”: “2677,234”, “phone”: “13129548996,122333”, “userid”: “666,666666” }, “errMsg”: “成功” },两种方式的参数都有。
@RequestMapping(value = "/addbyuser", method = RequestMethod.POST)
public Result addtUserGet(User user) {
return ResultUtil.success(user);
}
3.采用Map接收
Content-Type="multipart/form-data 和Content-Type="application/x-www-form-urlencoded"请求头是可以拿到请求参数的,但是采用json格式Content-Type="application/json"不行。采用MAP的方式接受参数 必须加上@RequestParam 个人感觉用这个不如一个个参数的传入来的实际,一个可读性不好,其次参数验证不好做,唯一的好处参数扩展性好。
@RequestMapping(value = "/addbymap", method = RequestMethod.POST)
public Result addtUserGet(@RequestParam Map<String, Object> map) {
String name = (String) map.get("name");
String userid = (String) map.get("userid");
String age = (String) map.get("age");
String phone = (String) map.get("phone");
User user = new User(name, age, phone, userid);
return ResultUtil.success(user);
}
4.采用单个参数并且不加@requestParament的方式的方式接受参数
Content-Type="multipart/form-data 和Content-Type="application/x-www-form-urlencoded"请求头是可以拿到请求参数的,但是采用json格式Content-Type="application/json"不行。这种方式默认是不会验证参数是否为空值的
@RequestMapping(value = "/addbywithoutrequestparament", method = RequestMethod.POST)
public Result addtUserGet(String name, String age, String phone, String userid) {
User user = new User(name, age, phone, userid);
return ResultUtil.success(user);
}
5.采用单个参数并且加上@requestParament的方式的方式接受参数
Content-Type="multipart/form-data 和Content-Type="application/x-www-form-urlencoded"请求头是可以拿到请求参数的,但是采用json格式Content-Type="application/json"不行。@RequestParam(value = “name”,defaultValue = “user”,required = false)value 报文的字段名称 defaultValue 默认值 required 默认为true会自动验证是否为空
@RequestMapping(value = "/addbywithrequestparament", method = RequestMethod.POST)
public Result addtUserGetadd(
@RequestParam(value = "name", defaultValue = "yuwenkai1", required = false) String name,
@RequestParam String age, @RequestParam String phone, @RequestParam String userid) {
User user = new User(name, age, phone, userid);
return ResultUtil.success(user);
}