简体   繁体   中英

Spring Controller: bind query parameters to custom POJO fields

I'm trying to map certain values from request query parameters to POJO parameters as the following. This is the POJO:

import lombok.*;
import org.springframework.format.annotation.DateTimeFormat;

import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
import java.util.Map;

@Data
@Builder
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class Person {
    @NotNull(message = "personId cannot be null")
    @Min(value = 0)
    private Long personId;

    @NotNull(message = "from date cannot be null")
    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
    private LocalDateTime from;

    @NotNull(message = "to date cannot be null")
    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
    private LocalDateTime to;

    private Map<String, String> filters;
}

And this is the controller:

    @GetMapping(path = "/persons")
    public ResponseEntity<Integer> getPersons(@Valid final Person personRequest) throws Exception {
        return ResponseEntity.ok(personService.getPersonsCount(personRequest));
    }

I want to map request query parameters to the attributes of this pojo. This is the expected request:

{application_url}/persons?personId=12&from=2017-03-22T00:00:00&to=2019-03-22T00:00:00&country=UK&company=xyz

I want to map personId, from, to to corresponding attributes in POJO and map the rest of query parameters nationality, company to the filters map. In other words personId, to, from are only static in the request and the rest of the parameters may vary, we can have salary=1000&minAage=31 instead of country=UK&company=xyz so I want to map the rest of the parameters to the filters map.

Is there a way to achieve so?

The way you can achieve it is to use @RequestParam Map<String, String> filters with other request parameters or just to use map for request parameters. Because all parameters would be included in map.


Example with all parameters in request:

@GetMapping(path = "persons")
public ResponseEntity<Integer> getPersons(@RequestParam Long personId,
                                          @RequestParam String from,
                                          @RequestParam String to,
                                          @RequestParam Map<String, String> filters) {
    Person person = Person.builder()
            .personId(personId)
            .from(getDate(from))
            .to(getDate(to))
            .filters(filterMap(filters))
            .build();
    return ResponseEntity.ok(personService.getPersonsCount(person));
}

private LocalDateTime getDate(String date) {
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
    return LocalDateTime.parse(date, formatter);
}

private Map<String, String> filterMap(Map<String, String> request) {
    request.remove("personId");
    request.remove("from");
    request.remove("to");
    return request;
}

The code is totally messed up. And since Map<String, String> filters is @RequestParam , so it includes all request parameters even what's defined above. So you need to remove pesonId , from , to if you don't want to be in filters map.

Example with request map only

@GetMapping(path = "persons")
public ResponseEntity<Integer> getPerson(@RequestParam Map<String, String> requestParams) {
    Person person = Person.builder()
             .personId(Long.valueOf(requestParams.get("personId")))
             .from(getDate(requestParams.get("from")))
             .to(getDate(requestParams.get("to")))
             .filters(filterRequest(requestParams))
             .build();
    return ResponseEntity.ok(personService.getPersonsCount(person));
}

private LocalDateTime getDate(String date) {
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
    return LocalDateTime.parse(date, formatter);
}

private Map<String, String> filterRequest(Map<String, String> request) {
    request.remove("personId");
    request.remove("from");
    request.remove("to");
    return request;
}  

However at least I don't know nice or simple configuration to convert path parameters to POJO before calling controller endpoint, so I suggest you to use something from these examples. Otherwise use request body or try to use this example

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