Как сопоставить параметры динамического запроса в Spring Boot RestController

Можно ли сопоставить параметры запроса с динамическими именами с помощью Spring Boot? Я хотел бы сопоставить такие параметры, как эти:

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

Я мог бы сделать что-то подобное, но для этого нужно было бы знать все возможные фильтры, и я бы хотел, чтобы он был динамичным:

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

Если возможно, я ищу что-то, что позволит пользователю определять любое количество возможных значений фильтра и чтобы они отображались как HashMap с помощью 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");
    }
}

В ответе, опубликованном на этот вопрос, предлагается использовать @RequestParam Map<String, String> parameters, однако он будет фиксировать параметры запроса все, а не только те, которые соответствуют filter[*].

Возможный дубликат Spring MVC заполняет @RequestParam Map <String, String>

user7294900 07.01.2019 14:39

Связано, но они так и не решили это.

John Fantastico 07.01.2019 15:20
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
3
2
12 792
3

Ответы 3

Вам подходят матричные переменные? Если я вас правильно понял, может быть так:

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

@GetMapping ("/ продукты / фильтры") общественные недействительные продукты ( @MatrixVariable MultiValueMap matrixVars) {

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

}

Интересно, что я раньше не видел такого способа форматирования параметров запроса. Учитывая, что у него есть собственная аннотация в Spring (@MatrixVariable), возможно, именно так обычно делают службы Spring / Java. Я привык к Rails, в котором используются foo=bar, filter[x]=y, list[]=x&list[]=y, которые я считаю более читаемыми.

james246 08.01.2019 11:10

Это похоже на решаемую проблему. Насколько я знаю, решения не идеальны, но есть пути.

Предыдущая попытка, казалось, была направлена ​​на поиск идеального решения, при котором весь состав фильтра был известен при транспортировке.

Spring MVC заполнить

Все динамические критерии, которые определяет пользователь, могут быть переданы с помощью некоторой базовой схемы, которую вы определяете, как один параметр ключ = значение от клиента, а затем разложить на его элементы после его получения.

Вы также можете отправить два параметра: «поля» и «значения», где списки каждого из них закодированы соответственно, с некоторым осторожным разделителем по вашему выбору (возможно, это может быть закодированный специальный символ, который пользователь не может физически ввести, возможно).

Как и во всем другом подходе, когда клиентская сторона отправляет критерии (например, критерии фильтрации), вам по-прежнему требуется полная защита от любого злонамеренного использования параметров, так же как клиент пытается встроить в них критерии SQL (SQL-инъекция).

Но пока клиентский код следует согласованному синтаксису, вы можете получить от них любое количество динамических параметров за один раз.

Клиент:

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

Это упрощенный пример, показывающий разделители, которые слишком легко «сломать», но идея заключается в некоторой простой, даже полностью читаемой (без вреда при этом) схеме, предназначенной только для объединения имен ваших полей и значений для облегчения передачи.

Сервер:

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

Спасибо за ответ. Я решил отформатировать фильтры, используя то, что я считаю «стандартным» форматированием, и то, что я привык исходить из фона Ruby on Rails. Я бы предпочел формат f[x]=y. Я рекомендую использовать свой собственный стандарт для представления фильтров из-за возможных проблем, которые вы цитируете, таких как SQL-инъекция и обеспечение правильной работы разделителей.

james246 08.01.2019 11:07

Вы можете сопоставить несколько параметров без определения их имен в @RequestParam, используя карту:

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

Другие вопросы по теме