简体   繁体   中英

Spring boot parsing @RequestBody

I have this old endpoint that I am trying to upgrade to using spring boot. It is currently used by a few services so I would like to keep it the same.

The old endpoint accepts a Request Body of userName=1234&password=1234 .

As an example of how it is called is curl -X POST "http://localhost:8080/AuthService/login" -H "accept: */*" -H "Content-Type: application/json" -d "userName=123&password=123"

How can I get spring to take the Request Body exactly like my old endpoint but map the input into an Object for me?

The old endpoint was using Apache Access and is like this. It was configured to transform any public method in the class into an endpoint.

public RequestStatus login(String userName, String password) {
    ...
}

I have translated it over to Spring Boot like this

@ApiOperation(value = "To login", response = RequestStatus.class)
@ResponseBody
@RequestMapping(value = "/login", method = RequestMethod.POST)
public ResponseEntity<ReturnValue> login(@RequestBody() String info) {
    Login login = new Login(info);
    ....
}


public class Login {

    private String password;
    private String userName;

    public Login(String info) {
        String[] values = info.split("&");
        for (String value : values) {
            String[] pair = value.split("=");
            if (pair.length == 2) {
                switch (pair[0]) {
                    case "password":
                        password = pair[1];
                        break;
                    case "userName":
                        userName = pair[1];
                        break;
                }
            }
        }
    }
}

But that method of transforming the Request Body into the object is really ugly and error prone and I would like to improve it.

Spring boot will automagically map json to objects for you. Just delete the parens after your request body annotation, make your parameter type login and delete the constructor from login.

@ApiOperation(value = "To login", response = RequestStatus.class)
@ResponseBody
@RequestMapping(value = "/login", method = RequestMethod.POST)
public ResponseEntity<ReturnValue> login(@RequestBody Login login) {
    ....
}

public class Login {

    private String password;
    private String userName;
    .... // getters
}

First, convert the body to a map:

public Map<String, String> bodyToMap(String bodyStr) {
  Map<String, String> body = new HashMap<>();
  String[] values = bodyStr.split("&");
  for (String value : values) {
    String[] pair = value.split("=");
    if (pair.length == 2) {
      body.put(pair[0], pair[1]);
    }
  }
  return body;
}

Then use jackson's ObjectMapper to covert the map to your POJO

ObjectMapper mapper = new ObjectMapper();
Map<String, String> body = bodyToMap(info);
Login loginInfo = mapper.convertValue(body, Login.class);

You can check for more effective queryparam-style string to map converter here (You should, in case you have more legacy endpoints that have the same key like key1=value1_1&key1=value1_2&key2=value2_1 ) : Parse a URI String into Name-Value Collection

Add consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE to your method and also change you input parameter to a @RequestParam Map.

@RequestMapping(value = "/login", method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public @ResponseBody ResponseEntity<ReturnValue> login(@RequestParam Map<String, String> body) {
    String username = body.get("username");
    String password = body.get("password");

    //authenticate etc..

    return ResponseEntity.ok(returnValue);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM