Spring @GetMapping 被忽略

Spring @GetMapping is being ignored

我有以下控制器:

@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://localhost:8080/api/bmw 的 http GET 调用将 return 我 getCars 方法的结果。相反,调用被委托给 getModel 方法。这 return 是一个错误,因为没有 {model} 路径变量。

为什么我的 http 调用被委派给了不正确的 @GetMapping

在这里你可以看到我通过 hateoas:

拉入的 spring-boot-starter-web 的版本

[INFO] +- org.springframework.boot:spring-boot-starter-hateoas:jar:2.1.9.RELEASE:compile
[INFO] | +- org.springframework.boot:spring-boot-starter-web:jar:2.1.9.RELEASE:compile
[INFO] | | - org.springframework.boot:spring-boot-starter-tomcat:jar:2.1.9.RELEASE:compile
[INFO] | | +- org.apache.tomcat.embed:tomcat-embed-core:jar:9.0.26:compile
[INFO] | | - org.apache.tomcat.embed:tomcat-embed-websocket:jar:9.0.26:compile
[INFO] | +- org.springframework.hateoas:spring-hateoas:jar:0.25.2.RELEASE:compile
[INFO] | - org.springframework.plugin:spring-plugin-core:jar:1.2.0.RELEASE:compile

我已经启用了 Spring 执行器的 mappings 端点,我什至可以看到被忽略的端点可用:

{
  "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
        }
      ]
    }
  }
}

编辑我添加了一个 interceptor 使我能够看到目标 handlerMethod 是什么。

handlerMethod 是正确的:

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

但我仍然收到以下错误:

Internal server error: Missing URI template variable 'model' for method parameter of type String

我无法理解 handlerMethod 不需要 model 参数这一事实,但 spring 仍然会因此抛出错误。

再次检查您的方法映射:

如您所说,您想根据品牌调用 gatCars 方法,您必须在获取映射中提供值,因此函数应该是:

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

请求将获取模型,因为它与签名匹配。更正 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);
  }

我认为不能将路径变量放入整个控制器 class 的注释 @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);
  }

在您的情况下,@RequestMapping("/api/{brand}") 需要一个未找到的输入品牌,因为您在 class 级别使用了注释。您可以通过以下方式更正它:

@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() 方法需要两个输入品牌和型号。希望对您有所帮助!

原来一个@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"),抛出异常。