Как упростить REST-контроллеры с одинаковыми методами и разными заголовками? - PullRequest
0 голосов
/ 31 января 2020

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

Пример метода: (не реальный код)
Для 1-го потребителя:

@PostMapping("/number")
Integer getNumber(@RequestHeader("no") String number, @RequestBody User user) {
    /*...*/
}

Для 2-го потребителя:

@PostMapping("/number")
Integer getNumber(@RequestHeader("number") String number, @RequestBody User user) {
    /*...*/
}

У меня до 10 методов в одном контроллере, и они должны иметь одинаковые имена и логики c, но разные заголовки. Префикс пути запроса может быть другим.


Вопрос:

Как упростить контроллер REST и не создавать 2 разных контроллера с одинаковыми методами и одинаковыми логами c?


Что я пробовал:

Я попробовал несколько примеров, чтобы создать один контроллер с 2 разными интерфейсами с одинаковыми методами, но с разным отображением.

Пример:

Класс контроллера

@RestController
@RequestMapping(path ="/application")
@Api(tags = {"application"})
public class ApplicationController implements AppMapping1, AppMapping2 {

    @Override
    public Integer getNumber(String number, User user) {
        /*...*/
    }
}

Первый интерфейс

interface AppMapping1 {

    @PostMapping("/num")
    Integer getNumber(@RequestHeader("num") String number, @RequestBody User user);
}

Второй интерфейс

interface AppMapping2 {

    @PostMapping("/number")
    Integer getNumber(@RequestHeader("number") String number, @RequestBody User user);
}

Результат:

Контроллер сопоставляется только с первым интерфейсом. Так что http://.../application/num работает нормально, но http://.../application/number - получает 404 код ошибки. Это означает, что Java Spring-Boot не имеет такой функциональности. Нужны еще идеи.

Проект разработан с Java 8; spring-boot:2.1.1.RELEASE; gradle

Ответы [ 4 ]

1 голос
/ 31 января 2020

Согласно this , если мы не уверены, какие заголовки будут присутствовать, или нам нужно их больше, чем мы хотим в сигнатуре нашего метода, мы можем использовать аннотацию @RequestHeader без конкретное c имя.

У вас есть несколько вариантов для типа переменной: Map, MultiValueMap или HttpHeaders объект.

Образец

@PostMapping("/number")
public Integer getNumber(@RequestHeader Map<String, String> headers) {

    if (Optional.ofNullable(headers.get("no")).isPresent()){
        //...
    }
    else if (Optional.ofNullable(headers.get("number")).isPresent())
    {
        //...
    }

}
1 голос
/ 31 января 2020

Не удобно обслуживать повторение одного и того же блока кода два или более раз просто для получения одного и того же ввода с разными именами (number и no). Вместо этого рекомендуется прочитать все заголовки и пройти по ним, чтобы получить ввод с использованием разных имен.

Пример кода

@PostMapping("/number")
public Integer getNumber(@RequestHeader Map<String, String> headers) {
    String number = headers.containsKey("number") ? headers.get("number") : headers.get("no");
    if(Objects.isNull(number)) {
        throw new RuntimeException("Number input not received from header!");
    }

    // relevant processing
}
0 голосов
/ 31 января 2020

Лучший способ - добавить HttpServletRequest в качестве аргумента вашего единственного контроллера и выполнить несколько логик c с картой заголовка, предоставленной объектом HttpServletRequest.

Если вы хотите увидеть полный пример взгляните здесь . Я реализовал один контроллер, который упаковывает все мои логики c в соответствии с заголовками / методами и так далее. Вы можете настроить logi c по своему усмотрению с помощью HttpServletRequest.

0 голосов
/ 31 января 2020

Вы можете удалить аннотацию @RequestHeader и рассмотреть возможность сделать следующее:

    @PostMapping("/number")
    Integer getNumber(HttpServletRequest request, @RequestBody User user) {
      String number = request.getHeader("num");
      if(number == null){
         number = request.getHeader("number");
      }    
      /*...*/
    }

Если вы хотите более чистый подход, подумайте о создании класса util, который принимает объект HttpServletRequest и возвращает нужный заголовок. значение.

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