天天看點

REST+Jersey學習筆記(二)--根資源及注解

Jersey的依賴

一個使用 Jersey 的應用,依賴于 Jersey 的子產品,但是如果使用了第三方子產品,那麼 Jersey可能反過來依賴第三方子產品。Jersey 是插件化的元件結構,是以不同的應用可能依賴不同的

子產品。

基于 Servlet 的 GlassFish 應用

使用 GlassFish 應用服務,不需要打包任何東西,所有的一切都已經包含在其中了。隻需要在應用中聲明依賴使用 JAX-RS API 即可。

JAX-RS應用,資源和子資源

Root Resource Classes 根資源類

Root Resource Classes 是帶有 @PATH 注解的,包含至少一個 @PATH 注解的方法或者方法帶有 @GET、@PUT、 @POST、 @DELETE 資源方法訓示器的 POJO。資源方法是帶有資源方法訓示器(resource method designator)注解的方法。

使用 Java對象内的注解建立一個 Jersey 的 RESTful 服務。

為了項目更加清晰,建立net.huadong.idev.tpl.privilege.lhy.entity包,在該包下面建立一個對象 Cadets:

package net.huadong.idev.tpl.privilege.lhy.entity;

import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Date;

import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.xml.bind.annotation.XmlRootElement;

/**
 * Cadets實體類
 * @author liuhuiyan
 *
 */
@Entity
@Table(name = "CADETS_TEST_TABLE", catalog = "", schema = "IDEV7")
@XmlRootElement
@NamedQueries({
    @NamedQuery(name = "Cadets.findAll", query = "SELECT c FROM Cadets c")
    , @NamedQuery(name = "Cadets.findByCadetName", query = "SELECT c FROM Cadets c WHERE c.cadetName = :cadetName")
    , @NamedQuery(name = "Cadets.findByCadetBirth", query = "SELECT c FROM Cadets c WHERE c.cadetBirth = :cadetBirth")
    , @NamedQuery(name = "Cadets.findByCadetAge", query = "SELECT c FROM Cadets c WHERE c.cadetAge = :cadetAge")
    , @NamedQuery(name = "Cadets.findByCadetDate", query = "SELECT c FROM Cadets c WHERE c.cadetDate = :cadetDate")
    , @NamedQuery(name = "Cadets.findByCadetSchool", query = "SELECT c FROM Cadets c WHERE c.cadetSchool = :cadetSchool")
    , @NamedQuery(name = "Cadets.findByCadetSal", query = "SELECT c FROM Cadets c WHERE c.cadetSal = :cadetSal")
    , @NamedQuery(name = "Cadets.findByCadetDept", query = "SELECT c FROM Cadets c WHERE c.cadetDept = :cadetDept")
    , @NamedQuery(name = "Cadets.findByCadetId", query = "SELECT c FROM Cadets c WHERE c.cadetId = :cadetId")})
public class Cadets implements Serializable {

    private static final long serialVersionUID = L;
    @Basic(optional = false)
    @Column(name = "CADET_NAME", nullable = false, length = )
    private String cadetName;
    @Basic(optional = false)
    @Lob
    @Column(name = "CADET_SEX", nullable = false)
    private String cadetSex;
    @Basic(optional = false)
    @Column(name = "CADET_BIRTH", nullable = false)
    @Temporal(TemporalType.TIMESTAMP)
    private Date cadetBirth;
    @Basic(optional = false)
    @Column(name = "CADET_AGE", nullable = false)
    private BigInteger cadetAge;
    @Column(name = "CADET_DATE")
    @Temporal(TemporalType.TIMESTAMP)
    private Date cadetDate;
    @Basic(optional = false)
    @Column(name = "CADET_SCHOOL", nullable = false, length = )
    private String cadetSchool;
    @Basic(optional = false)
    @Column(name = "CADET_SAL", nullable = false)
    private BigInteger cadetSal;
    @Basic(optional = false)
    @Column(name = "CADET_DEPT", nullable = false, length = )
    private String cadetDept;
    @Id
    @Basic(optional = false)
    @Column(name = "CADET_ID", nullable = false, length = )
    private String cadetId;

    public Cadets() {
    }

    public Cadets(String cadetId) {
        this.cadetId = cadetId;
    }

    public Cadets(String cadetId, String cadetName, String cadetSex, Date cadetBirth, BigInteger cadetAge, String cadetSchool, BigInteger cadetSal, String cadetDept) {
        this.cadetId = cadetId;
        this.cadetName = cadetName;
        this.cadetSex = cadetSex;
        this.cadetBirth = cadetBirth;
        this.cadetAge = cadetAge;
        this.cadetSchool = cadetSchool;
        this.cadetSal = cadetSal;
        this.cadetDept = cadetDept;
    }

    public String getCadetName() {
        return cadetName;
    }

    public void setCadetName(String cadetName) {
        this.cadetName = cadetName;
    }

    public Object getCadetSex() {
        return cadetSex;
    }

    public void setCadetSex(String cadetSex) {
        this.cadetSex = cadetSex;
    }

    public Date getCadetBirth() {
        return cadetBirth;
    }

    public void setCadetBirth(Date cadetBirth) {
        this.cadetBirth = cadetBirth;
    }

    public BigInteger getCadetAge() {
        return cadetAge;
    }

    public void setCadetAge(BigInteger cadetAge) {
        this.cadetAge = cadetAge;
    }

    public Date getCadetDate() {
        return cadetDate;
    }

    public void setCadetDate(Date cadetDate) {
        this.cadetDate = cadetDate;
    }

    public String getCadetSchool() {
        return cadetSchool;
    }

    public void setCadetSchool(String cadetSchool) {
        this.cadetSchool = cadetSchool;
    }

    public BigInteger getCadetSal() {
        return cadetSal;
    }

    public void setCadetSal(BigInteger cadetSal) {
        this.cadetSal = cadetSal;
    }

    public String getCadetDept() {
        return cadetDept;
    }

    public void setCadetDept(String cadetDept) {
        this.cadetDept = cadetDept;
    }

    public String getCadetId() {
        return cadetId;
    }

    public void setCadetId(String cadetId) {
        this.cadetId = cadetId;
    }

    @Override
    public int hashCode() {
        int hash = ;
        hash += (cadetId != null ? cadetId.hashCode() : );
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Cadets)) {
            return false;
        }
        Cadets other = (Cadets) object;
        if ((this.cadetId == null && other.cadetId != null) || (this.cadetId != null && !this.cadetId.equals(other.cadetId))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "javaapplication4.Cadets[ cadetId=" + cadetId + " ]";
    }

}
           

拓展:POJO

POJO(Plain Ordinary Java Object)簡單的Java對象,友善使用資料庫中的資料表,可以友善的将POJO類當做對象來進行使用,也可以友善的調用其get,set方法。
  • POJO中有一些屬性及其getter setter方法的類
  • 沒有業務邏輯
  • 不允許有業務方法,也不能攜帶有connection之類的方法

POJO對象也被稱為Data對象,應用于表現現實中的對象。

JSON 處理

我們想把這個Cadets對象傳回給用戶端,在net.huadong.idev.tpl.privilege.lhy.resources 資源下,寫了:

package net.huadong.idev.tpl.privilege.lhy.resources;

@Path("login/lhy")
public class CadetsResource extends HdAbstractResource<CadetsFacade> {

    // 初始化上下文環境,獲得系統的相關資訊
    @Context
    private UriInfo context;

    /* 構造函數 */
    public CadetsResource() {
        super(Constants.HD_PRIVILEGE_EJB_URI, CadetsFacade.class);
    }

    @POST
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("find")
    public Response ezuiFind(HdEzuiQueryParams params) {
        return super.find(params);
    }
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("save")
    public Response ezuiSave(HdEzuiSaveDatagridData<Cadets> menu) {
        List<Cadets> insertRows = menu.getInsertedRows();
        for (Cadets entity : insertRows) {

        }
        List<Cadets> updateRows = menu.getUpdatedRows();
        for (Cadets entity : updateRows) {

        }
        return super.save(menu, SecurityUtils.getSubject().getPrincipal().toString());
    }
    /**
     * 重新整理參數緩存
     * @return 
     */
    @GET
    @Path("flush")
    public Response flushCache() {
        SysParamsHelper.flush();
        return Response.ok().build();
    }

}
           

JAX-RS 裡面的幾個注解

- @Path

URI的相對路徑。
           

上面設定的是本地的 URI的@Path(“login/lhy”) 。

URI 的路徑模版是由 URIs 和嵌入 URI 文法的變量組成

變量在運作時将會被比對到的 URI的那部分多代替。比如:

@Path("/users/{username}")
           

按照這個例子,一個使用者就能會友善的填寫他的名字,那麼 Jersey 伺服器也會按照這個UIR 路徑模闆響應到這個請求。

例如:使用者輸入了名字“lhy”,那麼伺服器就會響應

http://example.com/users/lhy
           

指定的URI路徑參數

為了接收到使用者名變量,@PathParam 用在接收請求的方法的參數上,例如:

@Path("/users/{username}")
public class UserResource {
    @GET
    @Produces("text/xml")
    public String getUser(@PathParam("username") String userName) {
...
}
}
           
它規定比對正規表達式式要精确到大小寫的,如果填寫的話會覆寫預設的表達式 [^/]+?

例如

@Path("users/{username: [a-zA-Z][a-zA-Z_0-9]*}")
           

這個正規表達式比對由大小寫字元、橫杠和數字組成的字元串,如果正則校驗不通過,則傳回 404 (沒有找到資源)。

  • 一個 @Path的内容是否以”/”開頭都沒有差別
  • 同樣是否以”/”結尾也沒有什麼差別

@GET, @PUT, @POST, @DELETE(HTTP 方法)

  • @GET
  • @PUT
  • @POST
  • @DELETE
  • @HEAD

是JAX-RS 定義的注解,非常類似與 HTTP的方法名。

@Produces

@Produces是定義傳回值給用戶端的 MIME 媒體類型。
           

CadetsResource

裡面,将會傳回一個對應于

MediaType.APPLICATION_XML

的 MIME 媒體類型,意思是以

JSON

形式将對象傳回給用戶端。

  • @Produces 既可以應用在類上,也可以作用于方法 上。
  • 方法水準層面的@Produces 會覆寫類層面的@Produces

如果一個資源類是能夠生産多個 MIME 媒體類型,資源的方法的響應将會對應對于用戶端來說最可接受的媒體類型。

HTTP 請求頭部宣布接受什麼是最容易被接受的

@Produces 可以定義多個傳回類型,比如:

@GET
@Produces({"application/xml", "application/json"})
public String doGetAsXmlOrJson() {
...
}
           
  • 無論

    application/xml

    或者

    application/json

    哪個比對上了,都會執行

    doGetAsXmlOrJson

  • 如果兩個都比對了,那麼會選擇首先比對的那個

@Consumes

用來指定表示可由資源消耗的 MIME 媒體類型。
           
  • @Consumes既可以應用在類的水準上
  • 也可以作用與方法的水準,聲明可以不止一種類型

Parameter Annotations (@*Param) 參數注解

資源方法中,帶有基于參數注解的參數可以從請求中擷取資訊。
           
  • 查詢參數
    • @PathParam 來擷取 URL 請求中的路徑參數
    • @QueryParam 用于從請求 URL 的查詢元件中提取查詢參數
@Path("smooth")
@GET
public Response smooth(
@DefaultValue("2") @QueryParam("step") int step,
@DefaultValue("true") @QueryParam("min-m") boolean hasMin,
@DefaultValue("true") @QueryParam("max-m") boolean hasMax,
@DefaultValue("true") @QueryParam("last-m") boolean hasLast,
@DefaultValue("blue") @QueryParam("min-color") ColorParam minColor,
@DefaultValue("green") @QueryParam("max-color") ColorParam maxColor,
@DefaultValue("red") @QueryParam("last-color") ColorParam lastColor) {
...
}
           
  • 如果

    @DefaultValue

    不與

    @QueryParam

    聯合使用,查詢參數在請求中如果不存在,

    List

    Set

    或者

    SortedSet

    類型将會是空值集合,對象類型将為空,Java 的定義預設為原始類型
  • @PathParam

    和其他參數注解
    • @MatrixParam

      @HeaderParam

      @CookieParam

      @FormParam

      遵循與

      @QueryParam

      一樣的規則
      • @MatrixParam

        從 URL 路徑提取資訊。
      • @HeaderParam

        從 HTTP 頭部提取資訊。
      • @CookieParam

        從關聯在 HTTP 頭部的 cookies 裡提取資訊

HTML表格處理

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

}
           

從查詢參數或者路徑擷取 Map

@GET
public String get(@Context UriInfo ui) {
MultivaluedMap<String, String> queryParams = ui.getQueryParameters();
MultivaluedMap<String, String> pathParams = ui.getPathParameters();
}
           

header 和 cookie 參數用法

  • 從頭部參數擷取 Map
    @Context 一般可以用于獲得一個Java類型關聯請求或響應的上下文。
               
@GET
public String get(@Context HttpHeaders hh) {
MultivaluedMap<String, String> headerParams = hh.getRequestHeaders();
Map<String, Cookie> pathParams = hh.getCookies();
}
           
  • form 表單參數 擷取 Map
    因為 form 表單參數(不像其他消息的一部分)是實體,就是說,不需要@Context注解。
               
@POST
@Consumes("application/x-www-form-urlencoded")
public void post(MultivaluedMap<String, String> formParams) {
// 
}