使用@RequestParam
Use the @RequestParam annotation to bind request parameters to a method parameter in your controller.
首先定义User
public class User {
private String phone;
private String password;
private String slat;
private boolean locked;
...
Getter and Setter
...
- 在前端通过表单提交数据,如果http请求是GET,则表单参数会以放入URL的查询参数中,例如:
那么 ,在后端Controller中,可以通过Request.getParamater()方法获取表单数据,也可以通过@RequestParam注解将数据绑定在参数上。http://localhost:port/...?phone=value1&password=value2
@RequestMapping("form") @ResponseBody public User form(@RequestParam("phone")String phone,@RequestParam("password")String password){ return new User(phone,password); }
-
如果请求方法是POST,表单数据存在请求体中。由于Tomcat对于Content-Typeapplication/x-www-form-urlencoded(POST请求)做了“特殊处理”,使得可以通request.getParamter()将值取出,所以可以在Controller方法参数上加上@RequestParam将数据绑定在参数上。
Tomcat的HttpServletRequest类的实现类为org.apache.catalina.connector.Request(实际上是org.apache.coyote.Request),而它对处理请求参数的方法为protected void parseParameters(),这个方法中对Content-Type multipart/form-data(文件上传)和application/x-www-form-urlencoded(POST请求)的处理代码如下:
protectedvoid parseParameters() { //省略部分代码...... parameters.handleQueryParameters();// 这里是处理url中的参数 //省略部分代码...... if ("multipart/form-data".equals(contentType)) { // 这里是处理文件上传请求 parseParts(); success = true; return; } if(!("application/x-www-form-urlencoded".equals(contentType))) {// 这里如果是非POST请求直接返回,不再进行处理 success = true; return; } //下面的代码才是处理POST请求参数 //省略部分代码...... try { if (readPostBody(formData, len)!= len) { // 读取请求体数据 return; } } catch (IOException e) { // Client disconnect if(context.getLogger().isDebugEnabled()) { context.getLogger().debug( sm.getString("coyoteRequest.parseParameters"),e); } return; } parameters.processParameters(formData, 0, len); // 处理POST请求参数,把它放到requestparameter map中(即request.getParameterMap获取到的Map,request.getParameter(name)也是从这个Map中获取的) // 省略部分代码...... } protected int readPostBody(byte body[], int len) throws IOException { int offset = 0; do { int inputLen = getStream().read(body, offset, len - offset); if (inputLen <= 0) { return offset; } offset += inputLen; } while ((len - offset) > 0); return len; }
从上面代码可以看出,在sevlet实现中,mutipart/form-data和application/x-www-form-urlencoded会被特殊处理,请求参数将被放置于request.paramter,这是一个map。我们可以从map中获取参数.。所以可以通过request,getParamater()和@RequestParam将数据取出来。
如果发起HTTP POST请求时,没有指定Content-type=application/x-www-form-urlencoded会如何?
首先,服务器为什么会对表单提交和文件上传做特殊处理,因为表单提交数据是名值对的方式,且Content-Type为application/x-www-form-urlencoded,而文件上传服务器需要特殊处理,普通的POST请求(Content-Type不是application/x-www-form-urlencoded)数据格式不固定,不一定是名值对的方式,所以服务器无法知道具体的处理方式,所以只能通过获取原始数据流的方式来进行解析。
此时,默认的Cotent-type=text/plain,这时服务器就不知道怎么解析数据了,所以才只能通过获取原始数据流的方式来进行解析请求数据,不能使用@RequestParam绑定数据。
Content-Type不是application/x-www-form-urlencoded的POST请求是不会读取请求体数据和进行相应的参数处理的,即不会解析表单数据来放到request parameter map中。所以通过request.getParameter(name)是获取不到的。
使用@RequestBody
-
在Controller方法中使用@RequestBody注解,请求头中的Content-type设置为application/x-www-form-urlencoded,Spring会使用FormHttpMessageConverter将表单数据写入MultiValueMap<String,String>中,在controller方法中可以通过map获得表单数据。
@RequestMapping("form1") @ResponseBody public User form1(@RequestBody MultiValueMap<String,String> user){ String phone = user.getFirst("phone"); String password = user.getFirst("password"); return new User(phone,password); }
-
请求头中的Content-type设置为application/json,将数据使用JSON数据格式传递后端,默认使用MappingJackson2HttpMessageConvert将其转换相应的参数类型。
@RequestMapping("form2") @ResponseBody public User form2(@RequestBody User user){ return user; }
————————————————