かまたま日記3

プログラミングメイン、たまに日常

SpringMVCでスラッシュ含みのパラメタを@ParamVariableに渡す

Spring3からUrlRewriteFilterを使わなくても@ParamVariableアノテーションを使えばURLとパラメタのマッピングが簡単にできます。

    @RequestMapping(value = "/blog/post/{username}/{year}/{month}/{day}", method = RequestMethod.GET)
    public String getBlogPost(
                @PathVariable String username
                @PathVariable int year
                @PathVariable int month
                @PathVariable int day
    ) {
        ・・・・・
    }

ただ、"/"含みの文字列を一つのパラメタとして渡すことができないみたいです

    // {resourcePath}に"/"が含まれている場合、パラメタを渡せない例(1)
    @RequestMapping(value = "/file/{username}/{resourcePath}", method = RequestMethod.GET)
    public String getResource(
                @PathVariable String username
                @PathVariable String resourcePath
    ) {
        ・・・・・
    }

    // {resourcePath}に"/"が含まれている場合、パラメタを渡せない例(2) - 正規表現を使ってみる
    @RequestMapping(value = "/file/{username}/{resourcePath:.*}", method = RequestMethod.GET)
    public String getResource2(
                @PathVariable String username
                @PathVariable String resourcePath
    ) {
        ・・・・・
    }

現状そういう場合はUrlRewriteFilterを使うか、以下の裏ワザ的方法で可能なようです。

    @RequestMapping(value = "/file/{username}/**", method = RequestMethod.GET)
    public String getResource(
                HttpServletRequest request,
                @PathVariable String username
    ) {
        final String resourcePath = extractPathFromPattern(request);
        ・・・・・
    }

    /*
     * リクエストのURLパスから、今回マッチしたパターンを取り除いた文字列を返す。
     */
    private static String extractPathFromPattern(final HttpServletRequest request){
        String path = (String)request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
        String bestMatchPattern = (String)request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
        return new AntPathMatcher().extractPathWithinPattern(bestMatchPattern, path);
    }

ちなみに

GrailsのUrlMappingならスラッシュ含みのパスをパラメタとしてマッピングできて楽ちんです。

class UrlMappings {
    static mappings = {
        "/file/$username/$resourcePath**?" {
            controller = "file"
            action = "getResource"
        }
    }
}