「@RequestMapping」アノテーションのパスの先頭は「スラッシュ(“/”)」は省略できることを知りました。
というのも、こんな感じのControllerを見ていた際、アノテーションでのパス指定の箇所にスラッシュがないものが混ざってました。
@RequestMapping("/api/hoge/panda")
class PandaController(
) {
@GetMapping("/{userId}")
fun get(
@PathVariable userId: Long
) = hogehoge
@PostMapping("import")
fun import(
@RequestParam userIds: Set<Long>
) = hogehoge
@PostMapping("import")のところだけ先頭のパスがないですね。
ちなみに@GetMappingのようなメソッドに付与しているアノテーションは@RequestMappingのショートカットアノテーションです。
さて、疑問に思ったのは、これだと
/api/hoge/panda/import ではなく、/api/hoge/pandaimportになってしまうのではないかと。
しかし動かしてみると問題なく動きます。マジか。
なんでスラッシュなしで動くのか?
2012年のstackoverflowが引っかかりました。
Use or not leading slash in value for @RequestMapping. Need official docs or point to Spring source? / gavenkoa
回答にはこんなことが書いてあります。
It does not matter: If the path does not start with an
/then Spring (DefaultAnnotationHandlerMapping) will add it.
なるほど、ということでGithubで該当箇所を見に行ってみます。
if (!typeLevelPattern.startsWith("/")) {
typeLevelPattern = "/" + typeLevelPattern;
}
確かにDefaultAnnotationHandlerMapping内で先頭がスラッシュで始まっていなかった場合を判定して付与してくれています。
DefaultAnnotationHandlerMappingはSpring5から削除されてた
でもよくみたらSpring3.2の時点でDefaultAnnotationHandlerMapping クラスはDeprecatedでした。
Spring5系の現在はクラス自体削除されてます。
じゃあ、今はどこで実装されているか、というと
PatternsRequestCondition クラスのinitPatternsで実装されてました。
private static Set initPatterns(String[] patterns) {
if (!hasPattern(patterns)) {
return EMPTY_PATH_PATTERN;
}
Set result = new LinkedHashSet<>(patterns.length);
for (String pattern : patterns) {
if (StringUtils.hasLength(pattern) && !pattern.startsWith("/")) {
pattern = "/" + pattern;
}
result.add(pattern);
}
return result;
}
ちなみにinitPatternsを呼び出しているPatternsRequestConditionメソッドは5.2系からDeprecatedになってます。Deprecate use of path extensions in request mapping and content negotiation
まとめ
と、いうわけで@RequestMappingのパスは先頭にスラッシュがない場合でも内部で付与して処理してくれる。
環境
Spring Boot: 2.3.8.RELEASE


コメント