一、错误经过
写项目时,需要接收前端传过来的数组,于是用了往常接收字符串,数字等简单类型的方式接收,代码运行后报错。
最初的错误代码
前端代码
var itemList = ['31', '32', '33', '34', '35'];
$.ajax({
type: 'post',
dataType: 'json',
data: {
"payItem": itemList,
"payWay": 0,
"patientIdentity": "421023111101010011"
},
url: '/pay',
success: function (data) {
alert(data.msg);
}
})
控制器代码
@RequestMapping("/pay")
@ResponseBody
public Map<String, String> payApp(String[] payItem, Integer payWay, String patientIdentity, HttpServletRequest request) throws Exception {
Map<String, String> parameter = new HashMap<>();
System.out.println(Arrays.toString(payItem));
System.out.println(payWay);
System.out.println(patientIdentity);
parameter.put("msg", "ok");
return parameter;
}
错误的请求信息
参数
多次尝试
-
将前端请求方式修改成get——>没用; -
将前端的itemList 使用JSON.stringify(itemList) 转化一下?——>没用,只是参数名变了+传递参数转换成了JSON字符串
二、分析
后端接受参数的三种方式
- @RequestBody
- @RequestParam
- 不写注解修饰直接接收
请求中的三种内容类型
内容类型 | 说明 |
---|
application/x-www-form-urlencoded | 【默认方式,jQuery默认也是这个,可设置contentType属性进行修改】浏览器原生的表单,值为urlencoded之后的 key1=value1&key2=value2… | multipart/form-data | 浏览器原生的文件表单,用于传输文件 | application/json | 常用的请求头格式,值为json串 {“key1”:“value1”,“key2”:“value2”…} |
接收参数的三种方式对于三种内容类型的解析情况(不全,有几种我不知道)
内容类型 | @Requestbody | @RequestParam | 不写注解 | 说明 |
---|
application/x-www-form-urlencoded | 能解析 | 能解析 | 能解析 | SpringMVC会自动进行解析,所以通常用@RequestParam或不写注解。 | multipart/form-data | 不能解析 | | | | application/json,application/xml等 | 能解析 | | | SpringMVC不会自动进行解析,所以必须要加@requestbody注解 |
Get请求和Post请求的区别
-
参数/数据 存放位置不同。 Get请求是把参数放在URL中(无请求体),会将数据暴露在请求地址上;而Post请求是通过请求体RequestBody来传递参数,象对安全; -
发送请求的步骤不同。 GET:浏览器会将http的header与data一并发出去,服务器直接响应200(并返回数据); POST:浏览器先发送Header,当服务器响应了100之后,浏览器再发送data,最后服务器才响应200(返回数据)——>分了两步
@Requestbody和@RequestParam的区别
-
@RequestBody :用来接收前端传递给后端的json 字符串中的数据(数据在请求体中)——>所以只能发送POST请求; -
@RequestParam :将请求参数绑定到你控制器的方法参数上(是SpringMVC中接收普通参数的注解); -
@RequestBody 只能有一个,@RequestParam 可以有多个。
@RequestParam写与不写的区别
public void test(Integer payWay)
public void test(@RequestParam Integer payWay)
public void test(@RequestParam("pay") Integer payWay)
public void test(@RequestParam(value = "pay") Integer payWay)
- 方式一:不写时,前端的参数名需要和后端控制器的变量名保持一致才能生效;
- 方式二:写时,前端传过来的参数必须有 payWay ,不然就会报错。可以加上
required = false 设置为非必传; - 方式三:指定参数名,这个值与前端的参数名对应即可。
三、解决示例代码
方式一:使用@RequestParam
前端代码:
var itemList = ['31', '32', '33', '34', '35'];
$.ajax({
type: 'post',
dataType: 'json',
data: {
"payItem": itemList,
"payWay": 0,
"patientIdentity": "421023111101010011"
},
url: '/pay',
success: function (data) {
alert(data.msg);
}
})
后端代码
@RequestMapping("/pay")
@ResponseBody
public Map<String, String> payApp(@RequestParam(value = "payItem[]") String[] payItem, Integer payWay, String patientIdentity) {
Map<String, String> parameter = new HashMap<>();
for (String item : payItem) {
System.out.println(item);
}
parameter.put("msg", "ok");
return parameter;
}
注意:细心的可以发现,这里@RequestParam 的value 值为什么会是payItem[] 怪异的“姿势”?
其实答案在前面就已经知道了,使用浏览器的开发者工具——>网络——>访问链接——>荷载,可以看到前端传递的参数如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
没错这就是为什么value = "payItem[]" 的原因。
方式二:使用@RequestBody
思路:由于使用@RequestBody 必须为post请求,且请求内容必须为application/json 的,且只能使用一个,所以我们其余参数使用url拼接的方式接收。
即用@RequestBody 接收post请求方式传递过来的数据,其余参数使用”伪get“方式传递。
前端代码
$.ajax({
type: 'post',
dataType: 'json',
contentType: "application/json",
data: JSON.stringify(itemList),
url: '/pay?' + 'payWay=' + payWay + '&patientIdentity=' + $('#patient-id').val(),
success: function (data) {
if (data.status === 'ok') {
alert(data.msg);
location.href = 'pay-main.html'
} else {
alert(data.msg);
}
}
})
【关于第三点】当dataType指定为json后,1.4+以上的jquery版本对json格式要求更加严格。如果不是严格的json格式,就不能正常执行success回调函数。
即写法data: { “ids” : JSON.stringify(str) } 是错误的,正确写法是data:JSON.stringify(str)。
后端代码
@RequestMapping("/pay")
@ResponseBody
public Map<String, String> payApp(@RequestBody String[] payItem, Integer payWay, String patientIdentity) {
Map<String, String> parameter = new HashMap<>();
for (String item : payItem) {
System.out.println(item);
}
parameter.put("msg", "ok");
return parameter;
}
四、总结
推荐使用方式一,方式二太过于繁琐,且使用”伪get“的形式传递数据会破坏数据的安全性。
方式一的要点就是:往常我们接收参数时,前端的参数名和后端控制器的变量名是保持一致的,但是传递数组的時候,前端的参数名比较怪异(eg:arry[]),无法简单的与控制器中的变量名对应上,所以需要使用@RequestParam注解显式设置一下。
|