Spring не позволяет отображать переменные пути ({thingName}
) в пустые String
. На практике это означает, что URL /thing/?findByComponent=component123
не не отображается на thing/{thingName}
с пустым {thingName}
, а скорее ожидает, что будет какое-то сопоставление для thing
. Поскольку нет конечной точки, которая сопоставляется с путем thing
(без переменной пути), возвращается ошибка 404
.
Чтобы решить эту проблему, вы можете разбить эту единственную конечную точку на две отдельные конечные точки:
@RequestMapping(value = "thing/{thingName}",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public String getThing(
@PathVariable(value = "thingName") String thingName,
@AuthenticationPrincipal User user) {
// ...
}
@RequestMapping(value = "thing",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public String getThings(,
@RequestParam(value = "findByComponent", required = false) String findByComponentQuery,
@AuthenticationPrincipal User user) {
// ...
}
Для получения дополнительной информации см. В Spring 3.0 можно ли сделать необязательную переменную пути? .
Флаг required=false
допускает два типа запросов:
/thing
/thing/<some_value>
Строго говоря, включение косой черты в конце URL (т. Е. /thing/
) означает, что было принято решение включить значение для переменной пути, но ничего не было предоставлено. В контексте API REST /thing
и /thing/
- это две разные конечные точки, где последняя означает, что ожидалось значение после завершающего слеша.
Обходной путь для того, чтобы не создавать три отдельных сопоставления запросов (по одному для каждого вышеописанного случая), состоит в том, чтобы установить значение @RequestMapping
для контроллера на базовый путь, а затем иметь сопоставление запроса ""
и "/{thingName}
для две конечные точки:
@RestController
@RequestMapping("thing")
public class ThingController {
@RequestMapping(value = "/{thingName}",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public String getThing(
@PathVariable(value = "thingName") String thingName) {
return "foo";
}
@RequestMapping(value = "",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public String getThings(
@RequestParam(value = "findByComponent", required = false) String findByComponentQuery) {
return "bar";
}
}
В этом случае произойдут следующие сопоставления:
/thing
: getThings
/thing/
: getThings
/thing/foo
: getThing
Примером этого обходного пути, включая тестовые примеры, может быть , найденный здесь .