1

我有以下控制器:

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

我已经启用了mappingsSpring 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是正确的:

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

但是我仍然收到以下错误:

内部服务器错误:字符串类型的方法参数缺少 URI 模板变量“模型”

我无法理解handlerMethod不期望model参数的事实,但是 spring 仍然会因此而引发错误。

4

4 回答 4

1

在您的情况下,@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() 将需要两个输入品牌和型号。希望能帮助到你!

于 2020-01-21T11:54:09.237 回答
0

再次检查您的方法映射:

正如你所说,你想基于品牌调用 gatCars 方法,你必须在 get 映射中提供值,所以函数应该是:

 @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);
  }
于 2020-01-21T11:03:38.800 回答
0

我认为不能将路径变量放入@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);
  }
于 2020-01-21T11:04:31.993 回答
0

事实证明,a@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"),所以抛出了异常。

于 2020-01-22T13:19:38.673 回答