SpringMVC前后端参数交互
Controller中使用JSON方式有多种
关键在于ajax请求是将数据以什么形式传递到后台
HTTP请求中:
- 如果是get请求,那么表单参数以name=value&name1=value1的形式附到url的后面(QueryString Parameters),
- 如果是post请求,那么表单参数是在请求体中,也是以name=value&name1=value1的形式在请求体中(Form Data)
前端常用参数提交方式:
- POST + JSON字符串形式
- POST + JSON对象形式
- GET + 参数字符串
方式一: POST + JSON字符串形式,如下:
//前端 var data = { userAccount: lock_username, userPasswd:md5(lock_password).toUpperCase() } $.ajax({ url : ctx + "/unlock.do", type : "POST", data : JSON.stringify(data), //转JSON字符串 dataType: 'json', contentType:'application/json;charset=UTF-8', //contentType很重要 success : function(result) { console.log(result); } }); 注意 1.json数据必须用JSON.stringify()方法转换成字符串 2.contentType不能省略 //后端 @RequestMapping(value = "unlock.do",method = RequestMethod.POST) @ResponseBody public Msg methodName(@RequestBody User user) { logger.info("user:"+user); return Msg.success(); } 注意 @RequestBody不可以省略,如果不加的话spring mvc后台无法接受data参数 @RequestParam 、@RequestBody 说明 @RequestParam用来处理ContentType: 为 application/x-www-form-urlencoded编码的内容 @RequestBody该注解常用来处理Content-Type: 不是application/x-www-form-urlencoded编码的内容,例如application/json, application/xml等 @RequestBody接收的是一个Json对象的字符串,而不是一个Json对象。在ajax请求往往传的都是Json对象,用 JSON.stringify(data)的方式就能将对象变成字符串。
参考资料: https://blog.csdn.net/HelloWorld20151118/article/details/77104047
方式二: POST + JSON对象形式,如下:
//请求数据,登录账号 +密码 ar data = { userAccount: lock_username, userPasswd:md5(lock_password).toUpperCase() } $.ajax({ url : ctx + "/unlock.do", type : "POST", data : data, //直接用JSON对象 contentType : "application/x-www-form-urlencoded", dataType: 'json', success : function(result) { console.log(result); } });
说明:
-
如果使用原生AJAX POST请求时,需要明确设置Request Header xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); 因为原生AJAX默认使用的Content-Type是text/plain;charset=UTF-8,参数请求体在(Request Payload)中
-
如果使用jquery的$.ajax post请求是不需要明确设置 "contentType" 这个请求头,默认已经设置。
tomcat容器会对如下两种格式数据特殊处理:
- 表单提交且Content-Type为application/x-www-form-urlencoded,因为表单提交数据是键值对的方式;
- 文件上传做特殊处理;
tomcat容器对于Content-Type不是application/x-www-form-urlencoded的数据只能通过获取原始数据流的方式来进行解析,因为请求数据格式不固定,不一定是键值对的方式,所以服务器无法知道具体的处理方式;那么这样提交的参数我们该怎么获取呢?当然是使用最原始的方式,读取输入流来获取了(参考:FastJsonHttpMessageConverter),原始方式当然也可以接收Content-Type是application/x-www-form-urlencoded得POST请求数据
类名:org.apache.catalina.connector.Request protected void parseParameters() { this.parametersParsed = true; Parameters parameters = this.coyoteRequest.getParameters(); boolean success = false; try { parameters.setLimit(this.getConnector().getMaxParameterCount()); String enc = this.getCharacterEncoding(); boolean useBodyEncodingForURI = this.connector.getUseBodyEncodingForURI(); if(enc != null) { parameters.setEncoding(enc); if(useBodyEncodingForURI) { parameters.setQueryStringEncoding(enc); } } else { parameters.setEncoding("ISO-8859-1"); if(useBodyEncodingForURI) { parameters.setQueryStringEncoding("ISO-8859-1"); } } parameters.handleQueryParameters(); if(this.usingInputStream || this.usingReader) { success = true; return; } if(!this.getConnector().isParseBodyMethod(this.getMethod())) { success = true; return; } String contentType = this.getContentType(); if(contentType == null) { contentType = ""; } int semicolon = contentType.indexOf(59); if(semicolon >= 0) { contentType = contentType.substring(0, semicolon).trim(); } else { contentType = contentType.trim(); } // 这里是处理文件上传请求 if("multipart/form-data".equals(contentType)) { this.parseParts(false); success = true; return; } // 这里如果contentType是非application/x-www-form-urlencoded请求直接返回,不再进行处理。 // 从上面代码可以看出,Content-Type==不是application/x-www-form-urlencoded==的POST请求是不会读取请求体数据和进行相应的参数处理的,即不会解析表单数据来放到request parameter map中。所以通过request.getParameter(name)是获取不到的。 if(!"application/x-www-form-urlencoded".equals(contentType)) { success = true; return; } int len = this.getContentLength(); if(len <= 0) { if("chunked".equalsIgnoreCase(this.coyoteRequest.getHeader("transfer-encoding"))) { Object formData1 = null; Context context; byte[] formData2; try { formData2 = this.readChunkedPostBody(); } catch (IllegalStateException var17) { parameters.setParseFailedReason(FailReason.POST_TOO_LARGE); context = this.getContext(); if(context != null && context.getLogger().isDebugEnabled()) { context.getLogger().debug(sm.getString("coyoteRequest.parseParameters"), var17); } return; } catch (IOException var18) { parameters.setParseFailedReason(FailReason.CLIENT_DISCONNECT); context = this.getContext(); if(context != null && context.getLogger().isDebugEnabled()) { context.getLogger().debug(sm.getString("coyoteRequest.parseParameters"), var18); } return; } if(formData2 != null) { parameters.processParameters(formData2, 0, formData2.length); } } } else { int formData = this.connector.getMaxPostSize(); Context e; if(formData >= 0 && len > formData) { e = this.getContext(); if(e != null && e.getLogger().isDebugEnabled()) { e.getLogger().debug(sm.getString("coyoteRequest.postTooLarge")); } this.checkSwallowInput(); parameters.setParseFailedReason(FailReason.POST_TOO_LARGE); return; } e = null; byte[] e1; if(len < 8192) { if(this.postData == null) { this.postData = new byte[8192]; } e1 = this.postData; } else { e1 = new byte[len]; } try { if(this.readPostBody(e1, len) != len) { parameters.setParseFailedReason(FailReason.REQUEST_BODY_INCOMPLETE); return; } } catch (IOException var19) { Context context1 = this.getContext(); if(context1 != null && context1.getLogger().isDebugEnabled()) { context1.getLogger().debug(sm.getString("coyoteRequest.parseParameters"), var19); } parameters.setParseFailedReason(FailReason.CLIENT_DISCONNECT); return; } // 处理POST请求参数,把它放到requestparameter map中(即request.getParameterMap获取到的Map,request.getParameter(name)也是从这个Map中获取的) parameters.processParameters(e1, 0, len); } success = true; } finally { if(!success) { parameters.setParseFailedReason(FailReason.UNKNOWN); } } } protected int readPostBody(byte[] body, int len) throws IOException { int offset = 0; do { int inputLen = this.getStream().read(body, offset, len - offset); if(inputLen <= 0) { return offset; } offset += inputLen; } while(len - offset > 0); return len; } 类:com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter @Override protected Object readInternal(Class<? extends Object> clazz, HttpInputMessage inputMessage ) throws IOException, HttpMessageNotReadableException { return readType(getType(clazz, null), inputMessage); } private Object readType(Type type, HttpInputMessage inputMessage) throws IOException { try { InputStream in = inputMessage.getBody(); return JSON.parseObject(in, fastJsonConfig.getCharset(), type, fastJsonConfig.getFeatures()); } catch (JSONException ex) { throw new HttpMessageNotReadableException("JSON parse error: " + ex.getMessage(), ex); } catch (IOException ex) { throw new HttpMessageNotReadableException("I/O error while reading input message", ex); } } 原始方式接收数据,自己开发: private String getRequestPayload(HttpServletRequest req) { StringBuildersb = new StringBuilder(); try(BufferedReaderreader = req.getReader();) { char[]buff = new char[1024]; intlen; while((len = reader.read(buff)) != -1) { sb.append(buff,0, len); } }catch (IOException e) { e.printStackTrace(); } returnsb.toString(); }
方式三: GET + 参数字符串请求
$.ajax({ url : ctx + "/unlock.do", type : "GET", dataType: "text", data : "userAccount="+lock_username+"&userPasswd=" + hex_md5(lock_password).toUpperCase(),//等价于URL后面拼接参数 success : function(result) { console.log(result); } }); 或者 ar data = { userAccount: lock_username, userPasswd:md5(lock_password).toUpperCase() } $.ajax({ url : ctx + "/unlock.do", type : "GET", dataType: "text", data : data,//等价于URL后面拼接参数 success : function(result) { console.log(result); } });
jquery:GET方式(选项processData:true情况下) data请求中将附加在 URL 后