
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)-JSR224跟JAX-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為基礎,必且有以下三個特色
實際案例假設我們系統有個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 的安裝步驟筆者的環境是:
1. 產生一個Maven webapp project 如果你是用mvn command: mvn archetype:generate \ -DgroupId=tw.com.codedata.jersey \ -DartifactId=JerseyExample \ -DarchetypeArtifactId=maven-archetype-webapp 因為我是用Eclipse的M2E plugin,所以操作為「 找到Artifact Id = maven-archetype-webapp: 填入Project資訊: 2. 產生好Maven project後,因為maven產生的webapp project不會有 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按右鍵, 4. 如果你的container可以支援Servlet 3.0,那會建議使用Servlet 3.0,所以請把 原本是: <!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等同是註冊一個( 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: 一個是 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跑起來,結果如下。
JerseyExample是webapp name,rest是Jersey的root,hello是hello resource的root,當然這些都可透過設定的方式拿掉。 用Application的設定方法,只能限定在Servlet 3.0的webapp(由 本篇先簡單介紹RESTful service跟Jersey的建議安裝步驟。下一篇會開始介紹Jersey/JAX-RS的核心概念。 |
oreo0725
05/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 Xu
11/25
谢谢博主分享 : )
kido183
05/17
版主您好,
你的MIME-TYPE超連結連到的是MIME而非MIME-type
sanxx
03/11
我剛開始接觸REST...但從你的例子,,,,看來看去...最後結果就是SPRING 的MVC...不太明白
Hung-Yi Chou
08/01
版主您好,
您說您現在是透過gradle來做,但是目前網路上我好像找不到有關jersey + gradle的相關文件,可以請問您有甚麼推薦的網站嗎?