2
votes

Comment mapper des paramètres de requête dynamiques dans Spring Boot RestController

Est-il possible de mapper des paramètres de requête avec des noms dynamiques à l'aide de Spring Boot? Je voudrais mapper des paramètres tels que ceux-ci:

@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");
    }
}

Je pourrais faire quelque chose comme ça, mais cela impliquerait de connaître tous les filtres possibles, et je voudrais que ce soit dynamique: p>

@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
    ) {
        //
    }
}

Si possible, je recherche quelque chose qui permettra à l'utilisateur de définir n'importe quel nombre de valeurs de filtre possibles, et pour celles-ci d'être mappées sous forme de HashMap code> par Spring Boot.

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

Une réponse publiée sur cette question suggère d'utiliser les paramètres @RequestParam Map , mais cela capturera tous les paramètres de requête, pas seulement ceux correspondant filtre [*] .


2 commentaires

Copie possible de Spring MVC populate @RequestParam Map


Liés mais ils ne l'ont jamais vraiment résolu.


3 Réponses :


1
votes

Les variables matricielles fonctionnent-elles pour vous? Si je vous comprends bien, cela peut ressembler à ceci:

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

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

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

}


1 commentaires

Intéressant, je n'ai jamais vu cette façon de formater les paramètres de requête auparavant. Étant donné qu'il a sa propre annotation dans Spring ( @MatrixVariable ), c'est peut-être ainsi que les services Spring / Java le font généralement. Je suis habitué aux Rails qui utilisent foo = bar , filter [x] = y , list [] = x & list [] = y - que je trouve plus lisible.



0
votes

Cela semble être un problème résoluble. Les solutions ne sont pas idéales pour autant que je sache, mais il existe des moyens.

Une tentative précédente semblait vouloir trouver une solution parfaite où toute la composition du filtre était connue en transit.

Spring MVC populate

L'intégralité des critères dynamiques définis par l'utilisateur peut être transmis avec un schéma de base que vous définissez , comme un paramètre clé = valeur du client, puis décomposé en ses éléments une fois qu'il est reçu.

Vous pouvez également envoyer deux paramètres: "fields" et "values", où les listes de chacun y sont respectivement encodées, avec un délimiteur prudent de votre choix (peut être un caractère spécial encodé que l'utilisateur impossible de taper physiquement, peut-être).

Vous avez toujours besoin, comme pour toute autre approche où le côté client soumet des critères (comme des critères de filtre), d'une protection complète contre toute utilisation malveillante des paramètres, tout comme le client essayant d'y intégrer des critères SQL (Injection SQL).

Mais tant que le code client suit la syntaxe convenue, vous pouvez recevoir n'importe quel nombre de paramètres dynamiques de leur part en une seule fois.

Client:

@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. 

C'est un exemple simplifié montrant des délimiteurs trop faciles à "casser", mais l'idée est un schéma simple, voire entièrement lisible (pas de mal à le faire) juste dans le but de regrouper vos noms de champs et les valeurs ensemble pour un transport facile.

Serveur:

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


1 commentaires

Merci pour la réponse. J'ai choisi de formater les filtres en utilisant ce que je considère comme un formatage "standard", et ce à quoi j'ai l'habitude de venir d'un fond Ruby on Rails. J'aurais tendance à privilégier le format f [x] = y . Je suis favorable à l'idée de rouler sur ma propre norme pour représenter les filtres, en raison des possibilités de problèmes que vous citez tels que l'injection SQL et de m'assurer que les délimiteurs fonctionnent correctement.



3
votes

Vous pouvez mapper plusieurs paramètres sans définir leurs noms dans @RequestParam en utilisant une carte:

@GetMapping("/api/lala")
public String searchByQueryParams(@RequestParam Map<String,String> searchParams) {
    ...
}


0 commentaires