10

I've just started using Spring, and I'm trying to receive a form-urlencoded POST body in a rest controller, but I can't for the life of me get it to work. Here's my "Hello World"-esque controller:

@RestController
public class MyController {
    @ResponseBody
    @RequestMapping(
        value = "/",
        method = RequestMethod.POST,
        consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
        produces = MediaType.TEXT_PLAIN_VALUE
    )
    public String index(@RequestBody String text) {
        return "Text: " + text;
    }
}

I've tried many different variations, all with differing errors. The particular configuration above produces the following error when receiving a POST request with a "text" parameter from Postman.

Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing: public java.lang.String com.mywebsite.controllers.MyController.index(java.lang.String)

I've looked at many other stackoverflow posts about this topic and tried to implement their various solutions to no avail. Here's a list of the most promising ones:

  1. Spring JSON request body not mapped to Java POJO
    • This is the ideal outcome for me, a POJO with all the parameters. However, when I tried this, all POJO fields were null no matter what I passed in.
  2. How to get Form data as a Map in Spring MVC controller?
    • Following the first solution on that post, using a MultiValueMap produces the same error as above.
    • In the second, the parameter map is empty every time.
  3. How to retrieve FORM/POST Parameters in Spring Controller?
    • Produces an empty map, similar to the one above.

There were a couple more that I can no longer find, and for most of these posts I've tried tweaking the annotations each time. I had great success when I tried GET and JSON POST requests, but for some reason these urlencoded requests refuse to work.

Matthew Olsson
  • 177
  • 1
  • 1
  • 11

2 Answers2

11

If you want to qet individual post parameters, just use RequestParam:

public String index(@RequestParam("text") String text) {
    return "Text: " + text;
}

If you want to get several parameters at once, create a Command class, with JavaBean properties matching the parameters:

public class Command {
    private String text;
    private Integer number;

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public Integer getNumber() {
        return number;
    }

    public void setNumber(Integer number) {
        this.number = number;
    }
}

and pass that as argument to your method:

public String index(Command command) {
    return "Text: " + command.getText();
}
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • Using `@RequestParam` was the first thing I tried, but when I looked into it a bit more it seemed that that annotation was for GET parameters, not POST parameters. I just tried it (to make sure) and, while it didn't throw an error, it also didn't pick up the value of the parameter I set. When I create a javabean with correctly-named variables, they all get set as null no matter what I pass in. To be clear, since I wasn't as specific as I could have been in the op, I'm sending a POST request with a Content-Type of `x-www-form-urlencoded` and body parameters. – Matthew Olsson Dec 17 '17 at 17:17
  • And why did it pick up instead? How do you send the request in the first place? This works fine, I've tested it. – JB Nizet Dec 17 '17 at 17:36
  • It just gets set to null. I send it from Postman, as a post request, with the content type set, and my parameters set as body key-pair values. Is it possible that some configuration in my project is off? Because it seems to work for most people, but not me for some reason. I am using Tomcat 7 if that changes anything or needs to be configured, but other than setting up a few pom dependencies, I haven't really touched any configuration stuff. – Matthew Olsson Dec 17 '17 at 17:43
  • The easiest way for us to solve the problem would be to have a complete minimal example reproducing the problem, along with a curl command sending the request. – JB Nizet Dec 17 '17 at 17:47
  • In doing so, it appears the problem is with Postman. When using curl, the data gets properly mapped to the pojo. I guess I'll go learn how to use curl then (never used it before today). Thanks for the help! Is it appropriate to mark this response as the answer even though the actual answer itself didn't necessarily solve the problem? – Matthew Olsson Dec 17 '17 at 18:13
  • Lately I found that this trick only works when the request method is either GET or POST. I've tried with PATCH and PUT, and the framework injected a totally empty pojo to my controller. After I switched to POST, everything works fine except that it's no longer RESTful. – Aetherus Nov 05 '18 at 09:09
  • tried extracting a single field with `@RequestParam` in a POST request and got `Required String parameter 'test' is not present` – Mr.Cat Nov 12 '20 at 16:32
4

This is how I managed to solve the issue

@RequestMapping(value = "/test/", method = RequestMethod.POST, headers = {"content-type=application/x-www-form-urlencoded"})
public void waboxapp(WebRequest request) {
    // then use something like:
    log.debug("request payload: " + request.getParameter("data"));
}
Neuron
  • 5,141
  • 5
  • 38
  • 59