Spring @GetMapping игнорируется - PullRequest
       28

Spring @GetMapping игнорируется

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

У меня есть следующий контроллер:

@RestController
@RequestMapping("/api/{brand}")
public class CarController {

  private final CarService carService;

  @Autowird
  public CarController(CarService carService) {
    this.carService = carService;
  }

  @GetMapping
  public Resources<Car> getCars(@PathVariable("brand") String brand) {
    return new Resources<>(carService.getCars(brand));
  }

  @GetMapping(value = "/{model}")
  public Car getModel(@PathVariable("brand") String brand, @PathVariable("model") String model) {
    return carService.getCar(brand, model);
  }
}

Я ожидал бы, что вызов HTTP GET для http://localhost:8080/api/bmw вернет мне результат метода getCars. Вместо этого вызов делегируется методу getModel. Это возвращает ошибку, поскольку отсутствует {model} переменная пути.

Почему мои вызовы http делегируются неверному @GetMapping?

Здесь вы можете увидеть версию spring-boot-starter-web что я использую через hateoas:

[INFO] + - org.springframework.boot: spring-boot-starter-hateoas: jar: 2.1.9.RELEASE: compile
[ИНФО] | + - org.springframework.boot: spring-boot-starter-web: jar: 2.1.9.RELEASE: компилировать
[INFO] | | - org.springframework.boot: spring-boot-starter-tomcat: jar: 2.1.9. ВЫПУСК: компилировать
[ИНФО] | | + - org. apache .tomcat.embed: tomcat-embed-core: jar: 9.0.26: компилировать
[ИНФО] | | - org. apache .tomcat.embed: tomcat-embed-websocket: jar: 9.0.26: скомпилировать
[ИНФО] | + - org.springframework.hateoas: spring-hateoas: jar: 0.25.2.RELEASE: compile
[INFO] | - org.springframework.plugin: spring-plugin-core: jar: 1.2.0.RELEASE: compile

Я включил конечную точку mappings Spring Actuator и могу даже видеть, что доступна конечная точка, которая игнорируется:

{
  "handler": "public org.springframework.hateoas.Resources<com.example.Car> com.example.CarController.getCars(java.lang.String)",
  "predicate": "{GET /api/{brand}, produces [application/hal+json]}",
  "details": {
    "handlerMethod": {
      "className": "com.example.CarController",
      "name": "getCars",
      "descriptor": "(Ljava/lang/String;)Lorg/springframework/hateoas/Resources;"
    },
    "requestMappingConditions": {
      "consumes": [],
      "headers": [],
      "methods": [
        "GET"
      ],
      "params": [],
      "patterns": [
        "/api/{brand}"
      ],
      "produces": [
        {
          "mediaType": "application/hal+json",
          "negated": false
        }
      ]
    }
  }
}

РЕДАКТИРОВАТЬ Я добавил перехватчик , который позволяет мне видеть, какой будет цель handlerMethod.

Правильный номер handlerMethod:

publi c org.springframework.hateoas.Resources com.example.CarController.getCars (java .lang.String )

Тем не менее я все еще получаю следующую ошибку:

Внутренняя ошибка сервера: отсутствует переменная шаблона URI 'модель' для параметра метода типа String

Я не могу обернуть голову тем фактом, что handlerMethod не ожидает параметр model, но из-за него пружина все равно выдает ошибку.

Ответы [ 4 ]

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

В вашем случае @RequestMapping ("/ api / {brand}") ожидает входной бренд, который не найден, так как вы использовали аннотацию на уровне класса. Вы можете исправить это следующим образом:

@RestController
@RequestMapping("/api")
public class CarController {

  private final CarService carService;

  @Autowird
  public CarController(CarService carService) {
    this.carService = carService;
  }

  @GetMapping(value = "/{brand}")
  public Resources<Car> getCars(@PathVariable("brand") String brand) {
    return new Resources<>(carService.getCars(brand));
  }

  @GetMapping(value = "/{brand}/{model}")
  public Car getModel(@PathVariable("brand") String brand, @PathVariable("model") String model) {
    return carService.getCar(brand, model);
  }
}

Таким образом, метод getCars () будет ожидать входную марку, а getModel () - две входные марки и модель. Надеюсь, это поможет!

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

Оказывается, виновником был @RestControllerAdvice:

@RestControllerAdvice(assignableTypes = {CarController.class})
public class InterceptModelPathParameterControllerAdvice {

  @Autowired
  CarService carService;

  @ModelAttribute
  public void validateModel(@PathVariable("model") String model) {
    if (!carService.isSupportedModel(model)) throw new RuntimeException("This model is not supprted by this application.");
  }
}

Поскольку метод getCars не имел @PathVariable("model"), возникло исключение.

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

Я думаю, что переменная пути не может быть помещена в аннотацию @RequestMapping для всего класса контроллера. Я предлагаю изменить @RequestMapping("/api/{brand}") на @RequestMapping("/api"), а затем изменить

  @GetMapping
  public Resources<Car> getCars(@PathVariable("brand") String brand) {
    return new Resources<>(carService.getCars(brand));
  }

  @GetMapping(value = "/{model}")
  public Car getModel(@PathVariable("brand") String brand, @PathVariable("model") String model) {
    return carService.getCar(brand, model);
  }

на

  @GetMapping(value = "/{brand}")
  public Resources<Car> getCars(@PathVariable("brand") String brand) {
    return new Resources<>(carService.getCars(brand));
  }

  @GetMapping(value = "/{brand}/{model}")
  public Car getModel(@PathVariable("brand") String brand, @PathVariable("model") String model) {
    return carService.getCar(brand, model);
  }
0 голосов
/ 21 января 2020

Проверьте сопоставление вашего метода еще раз:

Как вы сказали, вы хотите вызывать метод gatCars на основе бренда, вы должны указать значение в get mappings, поэтому функция должна быть:

 @GetMapping(value = "/{model}")
  public Resources<Car> getCars(@PathVariable("brand") String brand) {
    return new Resources<>(carService.getCars(brand));
  }

Запрос собирается получить getModel, потому что он соответствует подписи. Исправьте подпись getModel, как показано ниже.

http://localhost: 8080 / api / bmw / x5

  @GetMapping(value = "/{model}/{brand}")
  public Car getModel(@PathVariable("brand") String brand, @PathVariable("model") String model) {
    return carService.getCar(brand, model);
  }
...