歡迎您光臨本站 註冊首頁

深入瞭解JAVA Jersey框架

←手機掃碼閱讀     sl_ivan @ 2020-06-08 , reply:0

Java Jersey的詳情概述

Jersey是一個RESTFUL請求服務JAVA框架,與常規的JAVA編程使用的struts框架類似,它主要用於處理業務邏輯層。

與springmvc 的區別:

1. jersey同樣提供DI,是由glassfish hk2實現,也就是說,如果想單獨使用jersey一套,需要另外學習Bean容器;

2. MVC出發點即是WEB,但jersey出發點確實RESTFull,體現點在與接口的設計方面,
 如MVC返回複雜結構需要使用ModelAndView,而jersey僅僅需要返回一個流或者文件句柄;

3. jersey提供一種子資源的概念,這也是RESTFull中提倡所有url都是資源;

4. jersey直接提供application.wadl資源url說明;

5. MVC提供Session等狀態管理,jersey沒有,這個源自RESTFull設計無狀態化;

6. Response方法支持更好返回結果,方便的返回Status,包括200,303,401,403;

7. 提供超級特別方便的方式訪問RESTFull;

jersey
 

1.X的版本是sun公司提供的獨立的jar包,在2.X版本中,已經將jersey融合到JavaSE中,在javax.ws.rs.*包中。

與Struts類似,它同樣可以和hibernate,spring框架整合。

由於Struts2+hibernate+spring整合在市場的佔有率太高,所以很少一部分人去關注Jersey。

所以網上有關於Jersey的介紹很少。但是它確實是一個非常不錯的框架。對於請求式服務,對於GET,DELETE請求,你甚至只需要給出一個URI即可完成操作。

舉個簡單的例子:如果你想獲得服務器數據庫中的所有數據;

那麼你可以在瀏覽器或者利用Ajax的GET方法,將路徑設置好;

例如:localhost:8080/Student(項目名稱)/studentinfo(項目服務總體前綴)/student(處理student對象的簽註)/getStudentInfo(最後前綴)。

你可以選擇GET獲取的數據的返回類型:JSON,XML,TEXT_HTML(String)..獲取之後,你可以通過JS將這些數據塞到html或者jsp頁面上。

Jersey是JAX-RS(JSR311)開源參考實現用於構建 RESTful Web service,它包含三個部分:

核心服務器(Core Server) :通過提供JSR 311中標準化的註釋和API標準化,可以用直觀的方式開發RESTful Web服務。

核心客戶端(Core Client) :Jersey客戶端API能夠幫助開發者與RESTful服務輕鬆通信;

集成(Integration) :Jersey還提供可以輕鬆繼承Spring、Guice、Apache Abdera的庫。

在本次開發中使用Jersey2.0,並且僅使用了核心服務器。

設置Jersey環境

Maven

  org.glassfish.jersey.containersjersey-container-servlet-core2.0javax.xml.wsjaxws-api2.1org.codehaus.jacksonjackson-core-asl1.9.12org.codehaus.jacksonjackson-mapper-asl1.9.12org.codehaus.jacksonjackson-jaxrs1.9.12

 

引入Jar文件方式
 

從Jersey開發包中將以下庫複製的WEB-INF下的庫目錄:

1  服務器:jersey-server.jar 、jersey-container-servlet-core.jar、jersey-container-servlet.jar、javax.ws.rs-api-2.0.jar

2  客戶端:jersey-client.jar

3  common:jersey-common.jar

4  json支持:在Jersey2.0中需要使用 Jackson1.9 才能支持json。

Hello World

以下將展示一個Hello World

第一步: 編寫一個名為HelloResource的資源,它接受Http Get請求並響應“Hello Jersey”

  @Path("/hello")  public class HelloResource {   @GET   @Produces(MediaType.TEXT_PLAIN)   public String sayHello() {    return "Hello Jersey";   }  }

 

第二步: 編寫JAX-RS application

  public class APIApplication extends ResourceConfig {    public APIApplication() {   //加載Resource   register(HelloResource.class);     //註冊數據轉換器   register(JacksonJsonProvider.class);     // Logging.   register(LoggingFilter.class);    }  }

 

第三步: 在web.xml文件中定義servelt調度程序,目的是將所有REST請求發送到Jersey容器。除了聲明Jersey Servlet外,還需定義一個初始化參數,指定JAX-RS application。

  JerseyServletorg.glassfish.jersey.servlet.ServletContainerjavax.ws.rs.Applicationcn.com.mink.resource.APIApplication1JerseyServlet/services/*

 

在命令終端中輸入以下命令,將會看到“Hello Jersey”。

curl http://host:port/services/hello

或者在瀏覽器中輸入以下URL,將會看到“Hello Jersey”

http://host:port/services/hello

使用

資源

Root Resource And Sub-Resource

資源是組成RESTful服務的關鍵部分,可以使用HTTP方法(如:GET、POST、PUT和DELETE)操作資源。在JAX-RX中,資源通過POJO實現,使用 @Path 註釋組成其標識符。資源可以有子資源,父資源是資源集合,子資源是成員資源。

在以下樣例代碼中,

Resources是"/services" URI組成是集合資源,UserResource是“/services/user” URI組成的成員資源;

  @Path("/services")  public class Resources {     @Path("/user")   public UserResource getUserResource() {    ...   }     @Path("/book")   public BookResource getBookResource() {    ...   }  }

 

UserResource是“/user” URI組成的集合資源,getUser是“/user/{username}” URI組成的資源方法

  @Path("/user")  public class UserResource {   @GET   @Path("{username"})   @Produces("application/json")   public User getUser(@PathParam("username") String userName) {    ...   }  }

 

HTTP Methods

HTTP方法映射到資源的CRUD(創建、讀取、更新和刪除)操作,基本模式如下:

HTTP GET :讀取/列出/檢索單個或資源集合。

HTTP POST :新建資源。

HTTP PUT :更新現有資源或資源集合。

HTTP DELETE :刪除資源或資源集合。

@Produces

@Produces 註釋用來指定將要返回給client端的數據標識類型(MIME)。@Produces 可以作為class註釋,也可以作為方法註釋,方法的 @Produces 註釋將會覆蓋class的註釋。

1  指定一個MIME類型

@Produces("application/json")

2  指定多個MIME類型

@Produces({"application/json","application/xml"})

@Consumes

@Consumes 與 @Produces 相反,用來指定可以接受client發送過來的MIME類型,同樣可以用於class或者method,也可以指定多個MIME類型,一般用於 @PUT ,@POST 。

參數(Parameter Annotations)

Parameter Annotations用於獲取client發送的數據。本文只介紹常用的註解,更多詳見 Jersey用戶手冊

@PathParam

使用 @PathParam 可以獲取URI中指定規則的參數,比如:

  @GET  @Path("{username"})  @Produces(MediaType.APPLICATION_JSON)  public User getUser(@PathParam("username") String userName) {    ...  }

 

當瀏覽器請求 http://localhost/user/jack 時,userName值為jack。

@QueryParam

@QueryParam 用於獲取GET請求中的查詢參數,如:

  @GET  @Path("/user")  @Produces("text/plain")  public User getUser(@QueryParam("name") String name,            @QueryParam("age") int age) {    ...  }

 

當瀏覽器請求 http://host:port/user?name=rose&age=25 時,name值為rose,age值為25。如果需要為參數設置默認值,可以使用 @DefaultValue ,如:

  @GET  @Path("/user")  @Produces("text/plain")  public User getUser(@QueryParam("name") String name,            @DefaultValue("26") @QueryParam("age") int age) {    ...  }

 

當瀏覽器請求 http://host:port/user?name=rose 時,name值為rose,age值為26。

@FormParam

@FormParam ,顧名思義,從POST請求的表單參數中獲取數據。如:

  @POST  @Consumes("application/x-www-form-urlencoded")  public void post(@FormParam("name") String name) {    // Store the message  }

 

@BeanParam

當請求參數很多時,比如客戶端提交一個修改用戶的PUT請求,請求中包含很多項用戶信息。這時可以用 @BeanParam 。

  @POST  @Consumes("application/x-www-form-urlencoded")  public void update(@BeanParam User user) {    // Store the user data  }

 

User Bean定義如下:

  @XmlRootElement(name = "user")  public class User {   @PathParam("userName)   private String userName;     @FormParam("name")   private String name;     @FormParam("telephone")   private String telephone;     @FormParam("email")   private String email;     public String getUserName() {    return userName;   }     public void setUserName(String userName) {    this.userName = userName;   }   ...  }

 

使用Map

在一個大型的server中,因為參數的多變,參數結構的調整都會因為以上幾種方式而遇到問題,這時可以考慮使用 @Context 註釋,並獲取UriInfo實例,如下:

  @GET  public String get(@Context UriInfo ui) {    MultivaluedMapqueryParams = ui.getQueryParameters();    MultivaluedMappathParams = ui.getPathParameters();  }

 

同樣還可以通過 @Context 註釋獲取 ServletConfig 、 ServletContext 、HttpServletRequest 、 HttpServletResponse 和 HttpHeaders 等,如下:

  @Path("/")  public class Resource {     @Context   HttpServletRequest req;     @Context   ServletConfig servletConfig;     @Context   ServletContext servletContext;     @GET   public String get(@Context HttpHeaders hh) {    MultivaluedMapheaderParams = hh.getRequestHeaders();    MappathParams = hh.getCookies();   }  }

 

Jersey返回Json和Xml

JAX-RS支持使用JAXB(Java API for XML Binding)將JavaBean綁定到XML或JSON,反之亦然。JavaBean必須使用 @XmlRootElement 標註,沒有@XmlElement 註釋的字段將包含一個名稱與之相同的XML元素,如下:

  @XmlRootElement  public class OptionResult {   @XmlElement(name = "code")   private String result;     private String errorMsg;     public String getResult() {    return result;   }     public void setResult(String result) {    this.result = result;   }     public String getErrorMsg() {    return errorMsg;   }     public void setErrorMsg(String errorMsg) {    this.errorMsg = errorMsg;   }  }

 

然後在REST服務中使用:

  @Path("/user")  public class UserResource {   @POST   @Produces("application/json")   public OptionResult create(@BeanParam User user) {    ...   }  }

 

最後,要註冊數據轉換器,該轉換器會自動將JavaBean轉換為json數據:

  public class APIApplication extends ResourceConfig {    public APIApplication() {   //加載Model   register(OptionResult.class);     //加載與OptionResult同一個packge的Model   //packages(OptionResult.class.getPackage().getName());     //加載Resource   register(UserResource.class);     //註冊數據轉換器   register(JacksonJsonProvider.class);     // Logging.   register(LoggingFilter.class);    }  }

 

說明 :返回XML數據的原理相同,僅僅是數據轉換器不同,只需要在APIApplication中同時註冊XML數據轉換器即可,詳見 Jersey用戶手冊

問題總結

Ajax請求(POST、PUT和DELETE)無法將數據提交到Jersey容器

問題闡述

在短信平臺的開發中,數據的CRUD全部使用Ajax技術完成,因此必須使用POST、PUT和DELETE請求。此三種請求的content-type均為“application/x-www-form-urlencoded”,使用UTF-8編碼會變成“application/x-www-form-urlencoded; UTF-8”。在使用Firefox的tamperdata擴展調試程序的過程中發現,當content-type為“application/x-www-form-urlencoded”時,Jersey容器能夠通過 @FormParam 註解獲取到提交的數據,而content-type為“application/x-www-form-urlencoded; UTF-8”時便獲取不到。

解決方案

最終我使用Java Filter和Jersey RequestFilter解決了問題。首先在Java Filter中使用UTF8將Request中的數據編碼,然後在Jersey RequestFilter中將request對象中的content-type修改為“application/x-www-form-urlencoded”。如:

  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {   HttpServletRequest req = (HttpServletRequest)request;   req.setCharacterEncoding("UTF-8");  }    public class RequestFilter implements ContainerRequestFilter {   @Override   public void filter(ContainerRequestContext context) throws IOException {    String headerString = context.getHeaderString("content-type");    if (headerString != null) {     //如果content-type以"application/x-www-form-urlencoded"開頭,則處理      if (headerString.startsWith(MediaType.APPLICATION_FORM_URLENCODED))      context.getHeaders().putSingle("content-type", MediaType.APPLICATION_FORM_URLENCODED);    }   }  }

 

最後在web.xml中註冊Java Filter(要註冊在Jersey容器之前),在APIApplication中註冊Jersey RequestFilter,如下:

  public class APIApplication extends ResourceConfig {    public APIApplication() {      register(RequestFilter.class);    }  }

 

說明 :在修復此問題後,在Github的Jersey源代碼倉庫中看到已經有人發現並修復了此問題,在下個Jersey正式版本中應該不會再出現這樣的問題,詳見 此Discussion


[sl_ivan ] 深入瞭解JAVA Jersey框架已經有566次圍觀

http://coctec.com/docs/java/show-post-237452.html