JAVA RESTful WebService實戰(zhàn)筆記(二)

資源定位之注解相關簡介

@QueryParam注解

接口描述 資源地址
分頁查詢列表數(shù)據(jù) /query-resource/test?start=24&size=10
排序并分頁查詢列表收 /query-resource/test?limit=5&sort=program
查詢單項數(shù)據(jù) /query-resource/test?id=9

JAX-RS2定義了@QueryParam注解來定義查詢參數(shù),如下表所示

接口描述 資源地址
分頁查詢列表數(shù)據(jù) /query-resource/test?start=24&size=10
排序并分頁查詢列表收 /query-resource/test?limit=5&sort=program
查詢單項數(shù)據(jù) /query-resource/test?id=9
1、分頁查詢
   /**
     *
     * @param start  起始條目  參數(shù)都使用了final進行限制
     *               符合Checkstyle風格 即輸入?yún)?shù)只作為邏輯算法的依據(jù)使用
     *               其本身并不會再找個過程中被修改
     * @param size 查詢的條目
     * @return
     */
    @Path("/page")  //page?start=0&size=10  訪問
    @GET
    @Consumes(MediaType.APPLICATION_JSON)  //指定請求返回的響應體為JSON
    @Produces(MediaType.APPLICATION_JSON)
    public User getByPaging(@QueryParam("start") final int start,@QueryParam("size") final int size){

        return null;
    }
2、排序查詢

    /**
     * @param limit  分頁查詢條目
     * @param sortName 排序規(guī)則
     * @return
     */
    @Path("/order")    //order?limit=10&sort=web 訪問
    @GET
    @Consumes(MediaType.APPLICATION_JSON)  //指定請求返回的響應體為JSON
    @Produces(MediaType.APPLICATION_JSON)
    public User getByOrder(@QueryParam("limit") final int limit,@QueryParam("sort") final int sortName){

        return null;
    }
3、單項查詢
    /**
     * @param segId  
     * @return
     */
    @Path("/query")    //order?id=10 訪問
    @GET
    @Consumes(MediaType.APPLICATION_JSON)  //指定請求返回的響應體為JSON
    @Produces(MediaType.APPLICATION_JSON)
    public User getByQuery(@QueryParam("id") final int segId){

        return null;
    }

@PathParam注解

接口描述 資源地址
基本路徑參數(shù) /path-resource/Eric
J結合查詢參數(shù) /path-resource/Eric?hometown=Luoma
帶有標點符號的資源路徑 /path-resource/199-1999
/path-resource/01,2012-12,2014
子資源變長的資源路徑 /path-resource/Asia/china/northeast/liaoning/shenyang/huanggu
//path-resource/q/restful;program=java;type=web
/path-resource/q2/restful;program=java;type=web

JAX-RS2定義@PathParam注解來定義路徑參數(shù)----每個參數(shù)對應一個子資源,示例列表如下:

接口描述 資源地址
基本路徑參數(shù) /path-resource/Eric
J結合查詢參數(shù) /path-resource/Eric?hometown=Luoma
帶有標點符號的資源路徑 /path-resource/199-1999
/path-resource/01,2012-12,2014
子資源變長的資源路徑 /path-resource/Asia/china/northeast/liaoning/shenyang/huanggu
//path-resource/q/restful;program=java;type=web
/path-resource/q2/restful;program=java;type=web
1、@Path注解

JAX-RS2定義@Path注解來定義資源路徑,@Path接收一個value參數(shù)來解析資源路徑地址,可以使用靜態(tài)定義的方式外,也可以使用動態(tài)變量的方式,格式:{參數(shù)名稱:正則表達式},例如資源地址:/path-resource、199-1999.參考示例如下

 @Path("{from:\\d+}-{to:\\d+}")    //order?id=10 訪問
    @GET
    @Consumes(MediaType.APPLICATION_JSON)  //指定請求返回的響應體為JSON
    @Produces(MediaType.APPLICATION_JSON)
    public User getByCondition(@QueryParam("from") final Integer from, @PathParam("to") final Integer to) {

        return null;
    }

在來一個復雜的例子:/path-resource、01,2012-12,2014(引入了逗號(,))

@Path("{beginMonth:\\d+},{beginYear:\\d+}-{endMonth:\\d+},{endYear:\\d+}")
2、正則表達式
3、路徑配查詢

查詢參數(shù)和路徑參數(shù)在一個接口中配合使用,可以更便捷的完成資源定位。

    /**
     * /path-resource/Eric?hometown=Luoma 
     *
     * @param user   Eric
     * @param hometown  Luoma
     * @return
     */
    @Path("{user:[a-zA-Z][a-zA-Z_0-9]*}")    //order?id=10 訪問
    @GET
    @Consumes(MediaType.APPLICATION_JSON)  //指定請求返回的響應體為JSON
    @Produces(MediaType.APPLICATION_JSON)
    public User getUserInfo(@QueryParam("user") final String user,
                            @DefaultValue("Shen Yang") @QueryParam("hometown") final String hometown) {

        return null;
    }
4、路徑區(qū)間

路徑區(qū)間(PathSegment)是對資源地址更加靈活的支持,使資源類的一個方法可以支持更加廣泛的資源地址的請求,例如下面的例子

/path-resource/Asia/china/northeast/liaoning/shenyang/huanggu
/path-resource/Asia/china/northeast/liaoning/shenyang/tiexi
/path-resource/china/liaoning/shenyang

如上所示的資源地址中含有固定子資源(shenyang),和動態(tài)子資源兩部分,對于動態(tài)匹配變長的子資源地址,PathSegment類型的參數(shù)結合正則表達式將大顯身手,如下:

    @Path("{region:.+}/shenyang/{district:\\w+}")              //order?id=10 訪問
    @GET
    @Consumes(MediaType.APPLICATION_JSON)  //指定請求返回的響應體為JSON
    @Produces(MediaType.APPLICATION_JSON)
    public User getByAddress(@PathParam("region")final List<PathSegment> region,
                             @PathParam("district") final String district) {
        
        final StringBuilder result = new StringBuilder();
        for (PathSegment pathSegment : region) {
            result.append(pathSegment.getPath()).append("-");
        }
        result.append("shenyang-" + district);

        return null;
    }

@MatrixParam注解

通過@MatrixParam注解來逐一的定義參數(shù),即通過聲明方式來獲取,示例代碼如下:

///path-resource/q2/program=java;type=web
    @Path("q2/{condition}")    //order?id=10 訪問
    @GET
    @Consumes(MediaType.APPLICATION_JSON)  //指定請求返回的響應體為JSON
    @Produces(MediaType.APPLICATION_JSON)
    public User getByCondition(@PathParam("condition") final PathSegment condition,
                               @MatrixParam("program") final String program,
                               @MatrixParam("type") final String type) {


        return null;
    }

@FormParam注解

JAX-RS2定義了@FormParam注解來定義表單參數(shù),相應的REST方法用以處理請求實體媒體類型為Content-Type:application/x-www-form-urlencoded的請求,示例代碼如下:

@Path("form-resource)
public class FormResource{
    @Post
    public String newPassword(
        @DefaultValue("ruolan") @FormParam(FromResource.USER) final String user,
        @Encoded @FormParam(FormParam.PW) final String password,
        @Encoded @FormParam(FormParam.NPW) final String newPassword,
        @FormParam(FormParam.VNPW) final String verification{
        }
    )
}

上述代碼中,newPassword()方法是@FormParam注解定義了user等4個參數(shù),這些參數(shù)是容器請求中獲取并且匹配的,測試代碼示例如下:

    @Test
    public void testPost(){
        final Form form = new Form();

        form.param(FormResource.USER,"ruolan");
        form.param(FormResource.PW,"北京");
        form.param(FormResource.NPW,"上海");
        form.param(FormResource.VNPW,"上海");

        final String result = target.("form-resource").request()
                .post(Entity.entity(form,MediaType.APPLICATION_FORM_URLENCODED_TYPE),String.class);
        FormTest.LOGGER.debug(result);
        Assert.assertEquals("encoded should let id to disable decoding",
                "ruolan:%E5%8C%97%E4%BA%AC:%E4%B8%8A%E6%B5%B7:上海",result);

    }

注意:

  • @Encoded注解用以標識禁用自動解碼,示例中的測試結果中%E4%B8%8A%E6%B5%B7是newPassword()方法中的參數(shù)值"上海"的編碼值,當對newPassword使用@Encoded注解,REST方法得到的參數(shù)值就不會被編碼
  • @DefaultValue注解,用以為客戶端沒有為其提供值的參數(shù) 提供默認的參數(shù)

@BeanParam注解

JAX-RS2定義了@BeanParam注解用于自定義參數(shù)組合,使REST方法可以使用簡潔的參數(shù)形式完成復雜的接口設計

public String getByAddress(@BeanParam Jaxrs2GuideParam param) {
//關注點2:參數(shù)組合 
public class Jaxrs2GuideParam {
    @HeaderParam("accept")
    private String acceptParam;
    @PathParam("region")
    private String regionParam;
    @PathParam("district")
    private String districtParam;
    @QueryParam("station")
    private String stationParam;
    @QueryParam("vehicle")
    private String vehicleParam;
 
public void testBeanParam() {
...
    final WebTarget queryTarget = target(path).path("China").path("northeast")
    .path("shenyang").path("tiexi")
.queryParam("station", "Workers Village").queryParam("vehicle", "bus");
    result = queryTarget.request().get().readEntity(String.class);
    //關注點3:查詢結果斷言 
    Assert.assertEquals("China/northeast:tiexi:Workers Village:bus", result);
}
 

//關注點4:復雜的查詢請求

http://localhost:9998/ctx-resource/China/shenyang/tiexi?station=Workers+Village&vehicle=bus 

在這段代碼中,getByAddress()方法只用了一個使用@BeanParam注解定義的Jaxrs2GuideParam類型的參數(shù),見關注點1;Jaxrs2GuideParam類定義了一系列REST方法會用到的參數(shù)類型,包括示例中使用的查詢參數(shù)"station"和路徑參數(shù)"region"等,從而使得getByAddress()方法可以匹配更為復雜的資源路徑,見關注點2;在變長子資源的例子基礎上,增加了查詢條件,但測試方法testBeanParam()發(fā)起的請求的資源地址見關注點4;可以看出這是一個較為復雜的查詢請求。其中路徑部分包括China/shenyang/tiexi,查詢條件包括station=Workers+Village和vehicle=bus。這些條件均在Jaxrs2GuideParam類中可以匹配,因此從關注點3的測試斷言中可以看出,該請求響應的預期結果是

"China/northeast:tiexi:Workers Village:bus"。

@CookieParam注解

JAX-RS2定義了@CookieParam注解用以匹配Cookie中的鍵值對信息,示例如下。

@GET
public String getHeaderParams(@CookieParam("longitude") final String longitude,
    @CookieParam("latitude") final String latitude,
    @CookieParam("population") final double population,
    @CookieParam("area") final int area) {//關注點1:資源方法入?yún)?
    return longitude + "," + latitude + " population=" + population + ",area=" + area;
@Test
public void testContexts() {
    final Builder request = target(path).request();
    request.cookie("longitude", "123.38");
    request.cookie("latitude", "41.8");
    request.cookie("population", "822.8");
    request.cookie("area", "12948");
    result = request.get().readEntity(String.class);
    //關注點2:測試結果斷言 
    Assert.assertEquals("123.38,41.8 population=822.8,area=12948", result);
}

在這段代碼中,getHeaderParams()方法包含4個使用@CookieParam注解定義的參數(shù),用于匹配Cookie的字段,見關注點1;在測試方法testContexts中,客戶端Builder實例填充了相應的cookie鍵值對信息,其斷言是對cookie字段值的驗證,見關注點2。

@Context注解

JAX-RS2定義了@Context注解來解析上下文參數(shù),JAX-RS2中有多種元素可以通過@Context注解作為上下文參數(shù)使用,示例代碼如下。

public String getByAddress(
    @Context final Application application,
    @Context final Request request,
    @Context final javax.ws.rs.ext.Providers provider,
    @Context final UriInfo uriInfo,
    @Context final HttpHeaders headers){
在這段代碼中,分別定義了Application、Request、Providers、UriInfo和HttpHeaders等5種類型的上下文實例。從這些實例中可以獲取請求過程中的重要參數(shù)信息,示例代碼如下。
final MultivaluedMap<String, String> pathMap = uriInfo.getPathParameters();
final MultivaluedMap<String, String> queryMap = uriInfo.getQueryParameters();
final List<PathSegment> segmentList = uriInfo.getPathSegments();
final MultivaluedMap<String, String> headerMap = headers.getRequestHeaders();

在這段代碼中,UriInfo類是路徑信息的上下文,從中可以獲取路徑參數(shù)集合getPath-Parameters()和查詢參數(shù)集合getQueryParameters()。類似地,我們可以從HttpHeaders類中獲取頭信息集合getRequestHeaders()。這些業(yè)務邏輯處理中常用的輔助信息的獲取,要通過@Context注解定義方法的參數(shù)或者類的字段來實現(xiàn)。


處理響應

REST的響應處理結果應包括響應頭中HTTP狀態(tài)碼,響應實體中媒體參數(shù)類型和返回值類型,以及異常情況處理。JAX-RS2支持4中返回值類型的響應,分別是無返回值、返回Response類實例、返回GenericEntity類實例和返回自定義類的實例.

VOID(無返回值類型)

在返回值類型中是void的響應,其響應實體為空,HTTP狀態(tài)碼是204。例子代碼如下:

    @DELETE
    @Path("{s}")
    public void deleteTest(@PathParam("s") final String s){
        
        
    }

因為delete操作不需要返回值關于資源標書的信息,因此該方法沒有返回值.(疑問點,如果需要通知客戶端是否刪除成功了沒有呢??????)

RESPONSE(Response返回值類型)

在Response的響應中,響應實體為Response類的entity()方法定義的實體實例。如果該內容為空,則HTTP狀態(tài)碼是204,否則HTTP狀態(tài)碼為200 OK,示例代碼如下:

    @POST
    @Path("c")
    public Response getResponse(final String s){

        return Response.ok().entity("char[] : " + s ).build();
    }

在上述的代碼中,Response首先定義了HTTP的狀態(tài)碼為OK,然后填充實體信息,最后調用build()方法構建Response實例

GenericEntity(GenericEntity返回值類型)

通用實體類型作為返回值的情況并不是很常用。其形式是構造一個統(tǒng)一的實體實例并將其返回,實體實例作為第一個參數(shù),該實體類型作為第二個參數(shù),示例代碼如下:

    @POST
    @Path("b")
    public String getGenericEntity(final  byte[] bytes) {
       
        return "byte[] : "  + new String(bytes);
    }
    
    public GenericEntity<String> getGenericTest(final  byte[] bytes){
        
        //構建GenericEntity實例
        return new GenericEntity<>("byte[] : " + new String(bytes),String.class );
    }
自定義類型

JDK中的類(例如File,String等)都可以作為返回值類型,更常用的是返回自定義的POJO類型。示例代碼如下:

    @POST
    @Path("f")
    public File getFile(final File f) throws FileNotFoundException, IOException {
        BufferedReader br = new BufferedReader(new FileReader(f));
        String s;
        do {
            s = br.readLine();
        } while (s != null);
        return f;
    }
    
    @POST
    @Consumes({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})
    @Produces(MediaType.APPLICATION_XML)
    public User getEntity(User user){
        return user;
    }

    @POST
    @Consumes({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})
    @Produces(MediaType.APPLICATION_XML)
    public User getEntity(JAXBElement<User> user){
        User user1 = user.getValue();
        return user1;
    }
    

處理異常

處理狀態(tài)碼
狀態(tài)碼 含義
200 OK 服務器正常響應
201 Created 創(chuàng)建新實體,響應頭Location指定訪問該實體的URL
202 Accepted 服務器接受請求,處理尚未完成??捎糜诋惒教幚頇C制
204 No Content 服務器正常響應,但是響應實體為空
301 Moved Permanently 請求資源的地址發(fā)生永久變動,響應頭Location指定新的URL
302 Found 請求資源的額地址發(fā)生臨時變動
304 Not Modified 客戶端緩存資源依然有效
400 Bad Request 請求信息出現(xiàn)語法錯誤
401 Unauthorized 請求資源無法授權給未驗證錯誤
403 Frobidden 請求資源未授權當前用戶
404 Not Found 請求資源不存在
405 Method Not Allowed 請求方法不匹配
406 Not Acceptable 請求資源的媒體類型不匹配
500 Internale Server Error 服務器內部錯誤,意外終止響應
501 Not Implemented 服務器不支持當前請求

內容協(xié)商

@Produces注解

@Produces注解用于定義方法的響應實體的數(shù)據(jù)類型,可以定義一個或者多個,同事可以為每種類型定義質量因素(qualityfactor)。質量因素是取值范圍從0到1的小數(shù)值。如果不定義質量因素,那么該類型的質量因素默認為1

    @GET
    @Path("{id}")
    @Produces(MediaType.APPLICATION_XML)
    public User getJaxUser(@PathParam("id") final int userId) {
        return new User(userId);
    }

   
    @GET
    @Path("{id}")
    @Produces(MediaType.APPLICATION_JSON)
    public User getJsonUser(@PathParam("id") final int userId) {
        return new User(userId);
    }
    
    /**
    * 以下的代碼中 定義了xml和json兩種表述數(shù)據(jù)類型,xml的質量因素是0.5 json的質量因素是0.9
    **/
    @GET
    @Path("book/{id}")
    @Produces({"application/json;qs=0.9","application/xml;qs=0.6"})
    public User getUser(@PathParam("id") final int userId) {
        return new User(userId);
    }

如果客戶端的請求中,明確接收的數(shù)據(jù)類型是兩者之一,響應實體使用指定類型.如果沒有定義或者兩者都定義且JSON的質量因素大雨或者等于XML,則返回JSON,還有一種用例就是,兩者都定義但是json的質量因素小于XML,內容協(xié)商的結果按照客戶端的喜好選擇相應實體的數(shù)據(jù)類型(xml格式)

@Consumes注解

@Consumes注解用于定義方法的請求實體的數(shù)據(jù)類型,和@Produces不同的是,@Consumes注解的數(shù)據(jù)類型的定義只用于JAX-RS2匹配請求處理的方法,不做內容協(xié)商使用,如果匹配不到,服務器會返回HTTP狀態(tài)碼415(Unsupported Meia Type),示例代碼如下:

    @POST
    @Consumes({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})
    @Produces(MediaType.APPLICATION_XML)
    public User getEntity(User user){
        final Builder request = Target(path).request();

        final User result = request.post(Entity.entity(user,MediaType.APPLICATION_XML), User.class);
        
        return user;
    }
    

@Consumes媒體類型為XML格式和JSON格式,那么在客戶端的請求中,如果請求實體的數(shù)據(jù)類型定義是兩者之一,該方法會被選擇為處理請求的方法,否則查找是否有定義為相應數(shù)據(jù)類型的方法,如果沒有拋出javax.ws.rs.NotSupportedException異常,則使用該方法處理請求。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容