Java 與 REST 的邂逅(一)淺談 Jersey 及 JAX-RS by popcorny | CodeData
top

Java 與 REST 的邂逅(一)淺談 Jersey 及 JAX-RS

分享:

簡介

在Web的世界中,Java從最早的Servlet/JSP,發展到JSTL/JSF,而third party也有action-based的Struts及Spring MVC,或component-based的GWT, ZK等,事實上Java的Web世界已經非常的成熟。然而這些架構主要設計是以Web Application為主要訴求,但是Web的世界中還有另外一個常見的應用是Web Services。

設計Web Services通常有兩條路可以走,一種是SOAP/WSDL等XML-Based的技術,定義是相對嚴謹的Web services;另外一種會是比較輕量級的以JSON為傳遞資料的格式,而通常也會設計成RESTful的Web Services。這兩種技術在Java Community中也分別被定義成標準,分別是JAX-WS(Java API for XML Web Services)-JSR224JAX-RS(Java API for RESTful Web Services)-JSR311,前者在Java EE 5時被納入,後者在Java EE 6被納入。

RESTful Service由於輕量、好測試有彈性的特性,越來越被大家所喜愛。本次系列文主要是介紹JAX-RS,並且以JAX-RS的RI(Refernce Implementation) Jersey當做環境。

何謂 REST?

REST是REpresentational State Transfer的縮寫,從這個縮寫實在很難看出這東西是什麼,然而他是一個設計理念,而這個概念也漸漸變成目前Web設計的主流。REST把所有WEB上的東西都以一個資源(Resource)去看待,並且所有資源都會有一個URI(Uniform Resource Identifier),這個概念就是們常見的網址,由於Web底層用的HTTP本身就是這樣的設計,所以這個概念應該大部分的人都知道。

進一步去看HTTP,稍微瞭解的人應該都知道HTTP有幾種Method,常見的有GET跟POST,而比較少見的有PUT跟DELETE。在當初設計HTTP時,有這樣的設計是希望GET代表取得資源,POST代表的是新增資源,而PUT跟DELETE就分別代表更新跟移除資源,這有沒有有點像資料庫設計講的 CRUD (Create,Read,Update,Delete)呢? 事實上就是如此,甚至還可以一對一的對應。但由於我們Web上層用的HTML只有定義到GET跟POST,導致我們都忘記有PUT跟DELETE的存在,另外還有HEAD/STATUS等Method,都分別定義來對資源做的動作。

那RESTful Web Services又是什麼呢? RESTful Web Services(或稱RESTful Web API)是以HTTP為基礎,必且有以下三個特色

  1. 所有的API或是以Resource的形式存在,例如 htttp://www.example.com/products/12345
  2. 這個服務可以接受與返回某個MIME-TYPE,最常見的是JSON格式,也可以回傳PNG/JPG/TXT等格式。
  3. 對資源的操作會支援各種請求方法 (例如GET, POST, PUT, DELETE)

實際案例

假設我們系統有個product類型的資源。那麼取得所有的products:

GET http://www.example.com/products

取得某個product id的product:

GET http://www.example.com/products/12345

新增一個product:

POST http://www.example.com/products
{
    {'name': 'foo'}, {'price': 1000}
}

更新一個proudct:

PUT http://www.example.com/products/12345
{
   {'inventory': 5}
}

Java 與 RESTful Web Service

有了RESTful基本概念,那要開始介紹的是Java對RESful Web Service的解決方案:JAX-RS。

JAX-RS跟所有Java EE的技術一樣,它只提供了技術標準,可以允許各家廠商有自己的實作,本系列用的Jersey即是實作之一。JAX-RS是架構在Java EE的Servlet之上,並且使用annotation來簡化資源位置跟參數的描述,大大的減少開發RESTful Web Services的複雜度。

假設我們有一個簡單的hello的resource,他的URI可能是:

http:///localhost:8080/hello/codedata

我們希望輸出是:

Hello, codedata

那這個簡單的應用的程式碼可能如下:

@Path("/hello")   
public class HelloRS {
    @GET
    @Path("/{name}")
    public String sayHello(@PathParam("name") String name) {
        return "Hello, " + name;
    }
}

看到上面簡潔的程式碼,應該開始對於JAX-RS的精簡感到興奮。如果有用過Servlet的朋友應該可以想想同樣的需求寫在Servlet,會有多少的code在做request跟response的操作,還有對參數的處理跟型別轉換。而這些複雜的動作,都可以透過JAX-RS的annotation的描述,對應到Java的class/method/parameter。而且不像Servlet必須繼承一個Servlet的Base class,在JAX-RS中都是以POJO的形式存在。另外在JAX-RS也用類似Spring的injection的方式,把外部一些物件inject到物件當中,減少Class跟Class之間的耦合度。

Jersey 的安裝步驟

筆者的環境是:

  • Eclipse 4.3 (Kepler) + M2E (Maven Plugin for Eclipse)
  • Maven 3.0.4
  • Tomcat 7.0.27
  • Jersey 2.2

1. 產生一個Maven webapp project

如果你是用mvn command:

mvn archetype:generate \
-DgroupId=tw.com.codedata.jersey \
-DartifactId=JerseyExample \
-DarchetypeArtifactId=maven-archetype-webapp

因為我是用Eclipse的M2E plugin,所以操作為「File -> New -> Other… 選Maven Project」:

mvn-project-1

找到Artifact Id = maven-archetype-webapp:

mvn-project-2

填入Project資訊:

mvn-project-3

2. 產生好Maven project後,因為maven產生的webapp project不會有src/main/java這個目錄,所以我們需要手動把這個目錄產生出來。這點千萬不要忘記

3. 增加Jersey的dependency

打開pom.xml:

<dependency>
     <groupId>org.glassfish.jersey.containers</groupId>
     <artifactId>jersey-container-servlet</artifactId>
     <version>2.2</version>
</dependency>

如果你跟我一樣是用M2E,請點project root按右鍵,Maven -> Add Dependency,填入dependency資訊:

mvn-dep

4. 如果你的container可以支援Servlet 3.0,那會建議使用Servlet 3.0,所以請把src/main/webapp/WEB-INF/web.xml的內容改成是Servlet 3.0的descriptor。

原本是:

<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
...
</web-app>

改成:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>Archetype Created Web Application</display-name>
</web-app>

5. 新增一個Jersey Application。此Application等同是註冊一個("/rest/*")的url mapping給Jersey,完全不需要去web.xml作額外設定。

package tw.com.codedata.jersey;

import javax.ws.rs.ApplicationPath;
import org.glassfish.jersey.server.ResourceConfig;

@ApplicationPath("rest")
public class MyApplication extends ResourceConfig{
    public MyApplication(){
        packages("tw.com.codedata.jersey");
    }
}

6. 產生我們第一個Helloworld的restful service。

這邊我們定義了兩個resource:

一個是/rest/hello,這個會印出"Hello world"
一個是/rest/hello/{name},這個會印出"Hello, {name}"

package tw.com.codedata.jersey;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;

@Path("/hello")
public class HelloRS {

    @GET
    public String sayHelloWorld() {
        return "Hello world";
    }   

    @GET
    @Path("/{name}")
    public String sayHello(@PathParam("name") String name) {
        return "Hello, " + name;
    }
}

7. 把你的webapp跑起來,結果如下。

jersey-result-1

 

jersey-result-2

JerseyExample是webapp name,rest是Jersey的root,hello是hello resource的root,當然這些都可透過設定的方式拿掉。

用Application的設定方法,只能限定在Servlet 3.0的webapp(由web.xml決定,也就是我們step3做的事情),如果你的webapp無法使用Servlet 3.0,或是想要在web.xml做設定,請參考
http://jersey.java.net/documentation/2.2/user-guide.html#deployment

本篇先簡單介紹RESTful service跟Jersey的建議安裝步驟。下一篇會開始介紹Jersey/JAX-RS的核心概念。

後續 >> Java 與 REST 的邂逅(二)JAX-RS 核心 Annotation

分享:
按讚!加入 CodeData Facebook 粉絲群

相關文章

留言

留言請先。還沒帳號註冊也可以使用FacebookGoogle+登錄留言

oreo072505/19

板主您好,

我依照你的方法建了一個webapp
我是用eclipse m2e plugin先建立一個maven project
再把他轉成Dynamic web project
然後再修改project properties裡的Deployment Assembly中的路徑
但實際去測的時候, 卻只有出現Tomcat的404頁面 "The requested resource is not available."

貌似沒有listen到url的pattern

以下是我的開發環境
* window7,
* Eclipse juno + JDK1.6 + apache Tomcat 7.0 + m2e wtp
* jersey-container-servlet 2.8 (以您描述的servlet3.0方法設定web.xml)

不知道是否跟project deployment的設定路徑有關(e.g. WEB-INF/)?
請問板主我可以檢查哪些設定呢?

感謝.

Guofan Xu11/25

谢谢博主分享 : )

kido18305/17

版主您好,
你的MIME-TYPE超連結連到的是MIME而非MIME-type

sanxx03/11

我剛開始接觸REST...但從你的例子,,,,看來看去...最後結果就是SPRING 的MVC...不太明白

Hung-Yi Chou08/01

版主您好,
您說您現在是透過gradle來做,但是目前網路上我好像找不到有關jersey + gradle的相關文件,可以請問您有甚麼推薦的網站嗎?

關於作者

學生時代熱愛 Java 技術,然而為五斗米閃到腰跑去 IC Design House 去寫 C。這幾年重新拾起 Java 技術,並且也同時開發 Web, iOS 以及Android App,繼續另外一個閃到腰的旅程 ...

熱門論壇文章

熱門技術文章