Spring @GetMapping 被忽略
Posted
技术标签:
【中文标题】Spring @GetMapping 被忽略【英文标题】:Spring @GetMapping is being ignored 【发布时间】:2020-05-07 10:01:35 【问题描述】:我有以下控制器:
@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 调用返回getCars
方法的结果。相反,调用被委托给getModel
方法。这会返回错误,因为没有 model
路径变量。
为什么我的 http 调用被委派给了不正确的 @GetMapping
?
在这里你可以看到我通过hateoas
拉入的spring-boot-starter-web
的版本:
[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:compile [信息] | | - org.springframework.boot:spring-boot-starter-tomcat:jar:2.1.9.RELEASE:compile [信息] | | +- org.apache.tomcat.embed:tomcat-embed-core:jar:9.0.26:compile [信息] | | - org.apache.tomcat.embed:tomcat-embed-websocket:jar:9.0.26:compile [信息] | +- org.springframework.hateoas:spring-hateoas:jar:0.25.2.RELEASE:compile [信息] | - org.springframework.plugin:spring-plugin-core:jar:1.2.0.RELEASE:compile
我已经启用了 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
]
编辑我添加了一个interceptor,让我可以看到handlerMethod
的目标是什么。
handlerMethod
是正确的:
public org.springframework.hateoas.Resources com.example.CarController.getCars(java.lang.String)
但我仍然收到以下错误:
内部服务器错误:缺少字符串类型方法参数的 URI 模板变量“模型”
我无法理解handlerMethod
不期望model
参数这一事实,但spring 仍然因此而引发错误。
【问题讨论】:
【参考方案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() 将需要两个输入品牌和型号。希望对您有所帮助!
【讨论】:
【参考方案2】:再次检查您的方法映射:
正如你所说,你想根据品牌调用 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);
【讨论】:
【参考方案3】:我认为对于整个控制器类,不能将路径变量放入注解@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);
【讨论】:
Adding a placeholder to the @RequestMapping is allowed。我们的应用程序中有很多@RestControllers
可以像这样正常工作。只有这一个开始表现不正确。
@Titulum 很好,很高兴知道。我仍然会尝试我的建议,看看 Spring 是否以某种方式混合了匹配的签名并以某种方式给你一个误报匹配。我的建议使签名之间的差异更加明显。
我发布的链接不是在谈论同类型的占位符,而是如果你check out the reference, they have an example there。我已经尝试过你的建议,但它会导致相同的结果。我添加了mappings
端点(Spring Actuator)的一些输出,以表明端点确实存在。
好吧,此时我唯一的想法是将@GetMapping(value = "/brand/model")
更改为@GetMapping(value = "/brand/model/model")
,这样映射匹配就会看到这两个URL 互斥。但除此之外,我目前没有任何想法
这是个好主意,但我可能需要自定义模式匹配器。【参考方案4】:
原来@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")
,所以抛出异常。
【讨论】:
以上是关于Spring @GetMapping 被忽略的主要内容,如果未能解决你的问题,请参考以下文章
Spring 似乎忽略 required=false 请求参数
@GetMapping@PostMapping@PutMapping@DeleteMapping@PatchMapping
@RequestMapping 和 @GetMapping @PostMapping 区别
Sqoop 函数“--map-column-hive”被忽略