[英]Spring @GetMapping is being ignored
I have the following controller:我有以下控制器:
@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);
}
}
I would expect an http GET call to http://localhost:8080/api/bmw
to return me the result of the getCars
method.我希望对
http://localhost:8080/api/bmw
的 http GET 调用返回getCars
方法的结果。 Instead, the call is delegated to the getModel
method.相反,调用被委托给
getModel
方法。 This returns an error, because there is no {model}
path variable.这将返回错误,因为没有
{model}
路径变量。
How come my http calls are delegated to the incorrect @GetMapping
?为什么我的 http 调用被委托给不正确的
@GetMapping
?
Here you can see the version of spring-boot-starter-web
that I pull in via hateoas
:在这里你可以看到我通过
hateoas
的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-hateoas:jar:2.1.9.RELEASE:compile
[INFO] |[信息] | +- org.springframework.boot:spring-boot-starter-web:jar:2.1.9.RELEASE:compile
+- 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
- 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
+- 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
- org.apache.tomcat.embed:tomcat-embed-websocket:jar:9.0.26:compile
[INFO] |[信息] | +- org.springframework.hateoas:spring-hateoas:jar:0.25.2.RELEASE:compile
+- org.springframework.hateoas:spring-hateoas:jar:0.25.2.RELEASE:compile
[INFO] |[信息] | - org.springframework.plugin:spring-plugin-core:jar:1.2.0.RELEASE:compile
- org.springframework.plugin:spring-plugin-core:jar:1.2.0.RELEASE:compile
I've enabled the mappings
endpoint of Spring Actuator and I can even see that the endpoint that is being ignored is available:我启用了 Spring Actuator 的
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
}
]
}
}
}
EDIT I've added an interceptor that enables me to see what the target handlerMethod
will be.编辑我添加了一个拦截器,使我能够看到目标
handlerMethod
将是什么。
The handlerMethod
is the correct one: handlerMethod
是正确的:
public org.springframework.hateoas.Resources com.example.CarController.getCars(java.lang.String)
公共 org.springframework.hateoas.Resources com.example.CarController.getCars(java.lang.String)
Yet I still get the following error:但是我仍然收到以下错误:
Internal server error: Missing URI template variable 'model' for method parameter of type String
内部服务器错误:缺少字符串类型的方法参数的 URI 模板变量“模型”
I can't wrap my head around the fact that the handlerMethod
does not expect the model
parameter, but spring still throws an error because of it.我无法
handlerMethod
不需要model
参数这一事实,但 spring 仍然因此引发错误。
In your case, @RequestMapping("/api/{brand}") expects an input brand which is not found as you have used the annotation at class level.在您的情况下,@RequestMapping("/api/{brand}") 需要一个输入品牌,但由于您在类级别使用了注释,因此找不到该品牌。 You can correct it the following way:
您可以通过以下方式更正:
@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);
}
}
So getCars() method will expect an input brand and getModel() will expect two inputs brand and model.因此 getCars() 方法将需要一个输入品牌,而 getModel() 将需要两个输入品牌和型号。 Hope it helps!
希望能帮助到你!
Check your method mapping again:再次检查您的方法映射:
As you said, you want to call gatCars method based on brand, you have to provide value in get mappings so function should be:正如您所说,您想根据品牌调用 gatCars 方法,您必须在获取映射中提供价值,因此功能应该是:
@GetMapping(value = "/{model}")
public Resources<Car> getCars(@PathVariable("brand") String brand) {
return new Resources<>(carService.getCars(brand));
}
Request is going to getModel cause it matches the signature.请求将 getModel 因为它匹配签名。 Correct the getModel signature as below.
更正 getModel 签名,如下所示。
http://localhost:8080/api/bmw/x5 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);
}
I think that a path variable can not be put into annotation @RequestMapping
for the entire controller class.我认为不能将路径变量放入整个控制器类的注释
@RequestMapping
中。 I suggest changing your @RequestMapping("/api/{brand}")
to @RequestMapping("/api")
and then change我建议将您的
@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);
}
to到
@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);
}
It turns out that a @RestControllerAdvice
was the culprit:事实证明,
@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.");
}
}
Because the getCars
method did not have a @PathVariable("model")
, the exception was being thrown.因为
getCars
方法没有@PathVariable("model")
,所以抛出了异常。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.