読者です 読者をやめる 読者になる 読者になる

だったら壁にでも話してろよ。

技術ネタはQiitaに移行したので、出口のない悩みや考えを垂れ流すことにします。

Spring Framework で @RequestMapping にパターンを指定する

Spring Framework (とくに Spring MVC) を使用して、コントローラーを作成する場合、クラスに @Contoroller アノテーションを指定し、各アクションメソッド@RequestMapping アノテーションを指定し、引数に @PathVariable を指定することで、URL 内の変数を受け取ることができる、というのはよく知られているところ。

念のため、この例を挙げておくと、以下のようなコードになる。指定された ID を持つユーザーの詳細ページを返すようなアクション。

@Controller
@RequestMapping("user")
public class UserController {
    @RequestMapping("{id}")
    public String item(@PathVariable String id) {
        return "item";
    }
}

ところがここで、URL から取得した値に特定の文字制約を設けたい場合に、どのように記述するかというのはあまり知られていないように思う。

この文字制約は、先の例では、URL に ID を示す文字列が含まれているが、この ID には小英数しか許可しない、といった場合に使用することができる。

書き方としては、@RequestMapping アノテーションの URL 内で変数表現されている箇所に、{変数:正規表現} の形式で記述する。

これを先ほどのコード例に盛りこむと、以下のようになる。

@Controller
@RequestMapping("user")
public class UserController {
    @RequestMapping("{id:^[a-z0-9]+$}")
    public String item(@PathVariable String id) {
        return "item";
    }
}

この条件にマッチしない URL へのリクエストの場合は 404 が返却されることになる。また、正規表現で記述するため、否定の先読みなども使用することができる。これは類似の URL パターンが存在する場合に、これを除外したいときなどに利用する。書き方としては、(?!除外キーワード) のように記述する。

たとえば、/user/{id} という URL パターンと、/user/register という URL パターンが混在するような場合が考えられる。

これも先ほどのコードに盛り込んでみると、以下のようになる。

@Controller
@RequestMapping("user")
public class UserController {
    @RequestMapping("{id:(?!^register$)^[a-z0-9]+$}")
    public String item(@PathVariable String id) {
        return "item";
    }

    @RequestMapping("register")
    public String register() {
        return "register";
    }
}

さらに、否定の先読みを使用して、複数のキーワードを URL から除外したい場合には、(?!(?:除外キーワードA|除外キーワードB)) のように記述する。?: を先頭に使用するのは正規表現にマッチした文字列がキャプチャされないようにするため。

さらにこれを盛り込んでみると、以下のようになる。

@Controller
@RequestMapping("user")
public class UserController {
    @RequestMapping("{id:(?!^(?:register|update)$)^[a-z0-9]+$}")
    public String item(@PathVariable String id) {
        return "item";
    }

    @RequestMapping("register")
    public String register() {
        return "register";
    }

    @RequestMapping("update")
    public String update() {
        return "update";
    }
}

今回は @RequestMapping を使用した URL 上の変数組み立てを、基本形から少しずつ変化を加えて紹介してみた。ここまでを知っておくと、Spring MVC を使用した URL 設計では、ほとんど困ることがないように思う。