<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    神奇好望角 The Magical Cape of Good Hope

    庸人不必自擾,智者何需千慮?
    posts - 26, comments - 50, trackbacks - 0, articles - 11
      BlogJava :: 首頁 ::  :: 聯系 :: 聚合  :: 管理

    JAX-RS 從傻逼到牛叉 3:路徑匹配

    Posted on 2011-10-09 12:43 蜀山兆孨龘 閱讀(4257) 評論(1)  編輯  收藏 所屬分類: Java EESOA

    JAX-RS 的核心功能是處理向 URI 發送的請求,所以它提供了一些匹配模式以便簡化對 URI 的解析。樓主在本系列的上一篇文章中已經使用了最簡單的路徑參數,本文將介紹一些稍微高級點的咚咚。

    模板參數

    前面已經見過用 @Path("{id}")@PathParam("id") 來匹配路徑參數 id。這種匹配方式可以被嵌入到 @Path 注解中的任何地方,從而匹配多個參數,例如下面的代碼用來查找 ID 在某一范圍內的電影:

            @GET
            @Path("{min}~{max}")
            @Produces(MediaType.APPLICATION_JSON)
            public List<Movie> findMovies(@PathParam("min") int min, @PathParam("max") int max) {
        

    于是,GET /ms/rest/movie/5~16 就將返回 ID 為 5 到 16 的電影。此處的 minmax 已被自動轉換為 int 類型。JAX-RS 支持多種類型的自動轉換,詳見 @PathParam 的文檔。

    根據 HTTP 規范,參數可能會編碼。默認情況下,JAX-RS 會自動解碼。如果希望得到未解碼的參數,只需在參數上再加個 @Encoded 注解。該注解適用于大多數 JAX-RS 注入類型,但并不常用。

    模板參數雖然靈活,也可能會帶來歧義。例如想用 {firstName}-{lastName} 匹配一個人的姓名,但恰好某人的名(lastName)含有“-”字符,像 O-live K 這種,匹配后就會變成姓 live-K,名 O。這種場景很難避免,一種簡單的解決方法就是對參數值進行兩次編碼,然后在服務端代碼解碼一次,因為 JAX-RS 默認會進行一次解碼,或者加上 @Encoded 注解,自己進行兩次解碼。

    另外,在一個復雜系統中,多個 @Path 可能會造成路徑混淆,例如 {a}-{b}{a}-z 都能匹配路徑 a-z。雖然 JAX-RS 定義了一些規則來指定匹配的優先級,但這些規則本身就比較復雜,并且也不能完全消除混淆。樓主認為,設計一個 REST 系統的核心就是對 URI 的設計,應當小心處理 URI 的結構,合理分類,盡量保證匹配的唯一性,而不要過度使用晦澀的優先級規則。樓主將在下一篇文章介紹優先級規則。

    正則表達式

    模板參數可以用一個正則表達式進行驗證,寫法是在模板參數的標識符后面加一個冒號,然后跟上正則表達式字符串。例如在根據 ID 查詢電影信息的代碼中,模板參數 {id} 只能是整數,于是代碼可以改進為:

            @GET
            @Path("{id : \\d+}")
            @Produces(MediaType.APPLICATION_JSON)
            public List<Movie> findMovies(@PathParam("min") int min, @PathParam("max") int max) {
        

    冒號左右的空格將被忽略。用正則表達式驗證數據很有局限性,可惜 JAX-RS 目前并不能直接集成 Bean 驗證框架,因此復雜的驗證只能靠自己寫代碼。

    查詢參數

    查詢參數很常見,就是在 URI 的末尾跟上一個問號和一系列由“&”分隔的鍵值對,例如查詢 ID 為 5 到 16 的電影也可以設計為 /ms/rest/movie?min=5&max=16。JAX-RS 提供了 QueryParam 來注入查詢參數:

            @GET
            @Produces(MediaType.APPLICATION_JSON)
            public List<Movie> findMovies(@DefaultValue("0") @QueryParam("min") int min,
                    @DefaultValue("0") @QueryParam("max") int max) {
        

    查詢參數是可選的。如果 URI 沒有設定某個查詢參數,JAX-RS 就會根據情況為其生成 0、空字符串之類的默認值。如果要手動設定默認值,需要像上面的代碼一樣用 @DefaultValue 注解來指定。另外還可以加上 Encoded 注解來得到編碼的原始參數。

    有的查詢參數是一對多的鍵值對,例如 /xyz?a=def&a=pqr,這種情況只需將注入的參數類型改為 List 即可。

    矩陣參數

    矩陣參數應該屬于 URI 規范中的非主流類型,但它實際上比查詢參數更靈活,因為它可以嵌入到 URI 路徑中的任何一段末尾(用分號隔開),用來標識該段的某些屬性。例如 GET /ms/rest/movie;year=2011/title;initial=A 表示在 2011 年出品的電影中查找首字母為 A 的標題。year 是電影的屬性,而 initial 是標題的屬性,這比把它們都作為查詢參數放在末尾更直觀可讀。匹配 URI 的時候,矩陣參數將被忽略,因此前面的 URI 匹配為 /ms/rest/movie/title。矩陣參數可以用 @MatrixParam 來注入:

            @GET
            @Path("title")
            @Produces(MediaType.APPLICATION_JSON)
            public List<String> findTitles(@MatrixParam("year") int year,
                    @MatrixParam("initial") String initial) {
        

    如果 URI 的多個段中含有相同名稱的矩陣參數,例如 /abc;name=XXX/xyz;name=OOO,這種直接注入就失效了,只能用下面要講的編程式訪問來取得。

    編程式訪問

    如果簡單的注入不能達到目的,就需要通過注入 PathSegmentUriInfo 對象來直接編程訪問 URI 的信息。

    一個 PathSegment 對象代表 URI 中的一個路徑段,可以從它得到矩陣參數。它可以通過 @PathParam 來注入,這要求該路徑段必須整個被定義為一個模板參數。例如下面的代碼也可以用來處理 GET /ms/rest/movie/{id}

            @GET
            @Path("{id}")
            @Produces(MediaType.APPLICATION_JSON)
            public Movie findMovie(@PathParam("id") PathSegment ps) {
        

    @PathParam 也可以注入多個段,如果想把 /a/b/c/d 匹配到 /a/{segments}/d,直接注入一個字符串顯然不行,因為 b/c 是兩個路徑段。唯一的選擇是把注入的類型改為 List<PathSegment>。樓主嚴重不推薦用一個模板參數匹配多個路徑段,因為這很容易干擾其他匹配的設計,最后搞成一團亂麻。URI 路徑段應當盡量設計得簡單明晰,再輔以矩陣參數或查詢參數就能應付大多數場景。不論對服務端還是客戶端開發人員來說,簡潔的 URI 既便于管理,又便于使用。網上有不少關于 URI 設計指南的文章,此處不再贅述。

    如果想完全手動解析路徑,則可以用 @Context 注入一個 UriInfo 對象,通過此對象可以得到 URI 的全部信息,詳見 API 文檔。例如:

            @GET
            @Path("{id}/{segments}")
            @Produces(MediaType.PLAIN_TEXT)
            public String getInfo(@PathParam("id") int id, @Context UriInfo uriInfo) {
        

    UriInfo 主要用在某些特殊場合下起輔助作用,設計良好的 URI 用普通的注入就能完成大部分匹配。


    工欲善其事必先利其器,為此 JAX-RS 提供了這些利器來解析 URI。至于如何用這些器來做出一個好系統,則還是依賴于 URI 本身的設計。


    評論

    # re: JAX-RS 從傻逼到牛叉 3:路徑匹配  回復  更多評論   

    2011-10-14 04:32 by 與你同飛
    謝謝樓主的文章,很長見識。
    主站蜘蛛池模板: 一区免费在线观看| 中文字幕亚洲情99在线| 一区二区在线视频免费观看| 日本高清免费aaaaa大片视频| 亚洲最大的成人网| 午夜男人一级毛片免费| 国产成人精品日本亚洲语音 | 亚洲熟伦熟女专区hd高清| 99re热免费精品视频观看| 亚洲一久久久久久久久| 国产免费怕怕免费视频观看| 黄色毛片免费网站| 亚洲人成人77777网站| 成人网站免费看黄A站视频| 西西人体44rt高清亚洲 | 无人在线观看完整免费版视频| 中文字幕亚洲男人的天堂网络| 大学生一级特黄的免费大片视频| 亚洲精品人成网线在线播放va | 亚洲精品私拍国产福利在线| 午夜免费福利片观看| 亚洲综合伊人制服丝袜美腿| 拔擦拔擦8x华人免费久久| 一级做a爱过程免费视频高清 | 国产日本亚洲一区二区三区| 男女交性永久免费视频播放 | 免费观看激色视频网站bd| 亚洲国产系列一区二区三区 | 亚洲最大的成网4438| 久久久高清免费视频 | 黄网站色视频免费看无下截| 国产亚洲精品拍拍拍拍拍| 69视频在线是免费观看| 亚洲av无码有乱码在线观看| 综合亚洲伊人午夜网 | 亚洲av日韩av综合| 亚洲高清无码专区视频| 久久国产精品一区免费下载| 亚洲人成网站999久久久综合| 中文字幕精品亚洲无线码二区| 在线视频精品免费|