3

Is it possible to map query parameters with dynamic names using Spring Boot? I would like to map parameters such as these:

/products?filter[name]=foo
/products?filter[length]=10
/products?filter[width]=5

I could do something like this, but it would involve having to know every possible filter, and I would like it to be dynamic:

@RestController
public class ProductsController {
    @GetMapping("/products")
    public String products(
            @RequestParam(name = "filter[name]") String name,
            @RequestParam(name = "filter[length]") String length,
            @RequestParam(name = "filter[width]") String width
    ) {
        //
    }
}

If possible, I'm looking for something that will allow the user to define any number of possible filter values, and for those to be mapped as a HashMap by Spring Boot.

@RestController
public class ProductsController {
    @GetMapping("/products")
    public String products(
            @RequestParam(name = "filter[*]") HashMap<String, String> filters
    ) {
        filters.get("name");
        filters.get("length");
        filters.get("width");
    }
}

An answer posted on this question suggests using @RequestParam Map<String, String> parameters, however this will capture all query parameters, not only those matching filter[*].

james246
  • 1,884
  • 1
  • 15
  • 28

3 Answers3

11

You can map multiple parameters without defining their names in @RequestParam using a map:

@GetMapping("/api/lala")
public String searchByQueryParams(@RequestParam Map<String,String> searchParams) {
    ...
}
Sma Ma
  • 3,343
  • 2
  • 31
  • 39
2

Does matrix variables work for you? If I understand you correctly, can be like this:

// GET /products/filters;name=foo;length=100

@GetMapping("/products/filters") public void products( @MatrixVariable MultiValueMap matrixVars) {

// matrixVars: ["name" : "foo", "length" : 100]

}

Juey
  • 123
  • 1
  • 6
  • Interesting, I haven't seen this way of formatting query parameters before. Given it has it's own annotation in Spring (`@MatrixVariable`) then perhaps that is how Spring/Java services generally do it. I'm used to Rails which uses `foo=bar`, `filter[x]=y`, `list[]=x&list[]=y` - which I find more readable. – james246 Jan 08 '19 at 10:10
0

This seems like a solvable problem. The solutions are not ideal far as I know, but there are ways.

A previous attempt seemed bent on finding a perfect solution where the entire composition of the filter was known in-transit.

Spring MVC populate

The entirety of the dynamic criteria that user defines can be transmitted with some basic scheme you define, as one key=value parameter from the client, then decomposed into its elements once it is received.

You could also send two parameters: "fields" and "values", where the lists of each are encoded in there respectively, with some cautious delimiter of your choosing (could be an encoded special character that the user cannot physically type, perhaps).

You still need, as with everything other approach where the client side is submitting criteria (like filter criteria), full protection from any malicious use of the parameters, just as the client trying to embed SQL criteria in them (SQL Injection).

But so long as the client code follows the agreed syntax, you can receive any number of dynamic parameters from them in one shot.

Client:

/products?filter=field1--value1||field2--value2||field3--value3... 

That is a simplified example showing delimiters that are too easy to "break", but the idea is some simple, even fully readable (no harm in doing so) scheme just for the purpose of packing your field names and values together for easy transit.

Server:

@RequestMapping(value = "/products", method = RequestMethod.GET)
    public String doTheStuff(@RequestParam(value = "filter") String encodedFilter) {

.. decompose the filter here, filter everything they've sent for disallowed characters etc. 
John Fantastico
  • 332
  • 1
  • 7
  • 1
    Thanks for the response. I've chosen to format the filters using what I'd consider "standard" formatting, and what I'm used to coming from a Ruby on Rails background. I'd tend to favour the `f[x]=y` format. I'm adervse to rolling my own standard for representing filters, due to the possibilities for problems you cite such as SQL injection and making sure delimeters are working properly. – james246 Jan 08 '19 at 10:07