java JAX-RS快速開發RESTful服務
JAX-RS(Java API for RESTful Web Services)同樣也是JSR的一部分,詳細規範定義見 。從JAVA EE 6開始,已經內建了該技術,跟.NET中的RESTful WCF類似,只要在常規方法上使用一些簡單的註解,就可以對外暴露成RESTful 服務.
注:本文執行環境為Jboss EAP 6.x ,其它容器特別是tomcat,並未自帶JAX-RS依賴的jar包,如果採用tomcat,需要自己匯入這些相關依賴jar包。
一、最基礎的HelloWorld (無引數)
1 @Path("/") 2 public class MyService { 3 4 final String XMLNS_NAMESPACE = "http://yjmyzz.cnblogs.com/rest/service"; 5 final String ROOT_NODE = "root"; 6 7 @GET 8 @Path("/json/hello") 9 @Produces(MediaType.APPLICATION_JSON) 10 public JAXBElementgetHelloWorldJSON() { 11 JAXBElement result = new JAXBElement (new QName("", 12 ROOT_NODE), String.class, sayHelloWorld()); 13 return result; 14 } 15 。。。 16 }
1 private String sayHelloWorld() { 2 return "Hello JAX-RS!"; 3 }
解釋:
@GET 表示該服務可以直接在瀏覽器位址列裡訪問(對應HTTP請求中的GET方法)
@Path 這裡用了二次,第一次是在Class上,相當服務的基地址;第二次是在方法上,表示具體某個服務方法的URL.
此外web.xml中,還需要增加以下內容:
12 javax.ws.rs.core.Application 3/rest/* 4
@Produces 表示返回訊息的格式,配合MediaType.APPLICATION_JSON說明,本方法返回Json字串格式
以上幾項綜合起來,最終可以用類似 的地址來訪問,返回的結果為:
JAXBElement
如果需要返回XML格式,只需要把@Produces後面的MediaType.APPLICATION_JSON換成MediaType.APPLICATION_XML就行了,即:
1 @GET 2 @Path("/xml/hello") 3 @Produces(MediaType.APPLICATION_XML) 4 public JAXBElementgetHelloWorldXML() { 5 JAXBElement result = new JAXBElement (new QName( 6 XMLNS_NAMESPACE, ROOT_NODE), String.class, sayHelloWorld()); 7 return result; 8 }
效果如下:
二、帶一個基本型別引數的HelloWorld
1 @GET 2 @Path("/json/hi/{name}") 3 @Produces(MediaType.APPLICATION_JSON) 4 public JAXBElementgetHelloToNameJSON(@PathParam("name") String name) { 5 JAXBElement result = new JAXBElement (new QName("", 6 ROOT_NODE), String.class, sayHelloToName(name)); 7 return result; 8 } 9 10 @GET 11 @Path("/xml/hi/{name}") 12 @Produces(MediaType.APPLICATION_XML) 13 public JAXBElement getHelloToNameXML(@PathParam("name") String name) { 14 JAXBElement result = new JAXBElement (new QName( 15 XMLNS_NAMESPACE, ROOT_NODE), String.class, sayHelloToName(name)); 16 return result; 17 }
1 private String sayHelloToName(String name) { 2 return "Hello " + name + ",welcome to the world of JAX-RS!"; 3 }
對比一下剛才的程式碼,有二個變化:
2.1 @Path上多了一個{name}的部分,表示url中,將允許以 /json/hi/xxx 的訪問URL響應請求
2.2 方法引數前有一個 @PathParam("name") 的註解,表示如果按/json/hi/xxx的方式訪問,則url中xxx的部分,會被對映到name這個引數上(說得更通俗點,就是透過解析url最後的xxx部分直接把name傳進來)
執行效果如下:
三、返回結果為實體Bean
實際應用中,web服務返回的結果,除了基本型別,還有可能是實體Bean,先來定義一個User類
1 package yjmyzz.service.model; 2 3 import javax.xml.bind.annotation.XmlAttribute; 4 import javax.xml.bind.annotation.XmlElement; 5 import javax.xml.bind.annotation.XmlRootElement; 6 7 @XmlRootElement(name = "user") 8 public class User { 9 10 String username; 11 String password; 12 int pin; 13 14 @XmlElement 15 public String getUsername() { 16 return username; 17 } 18 19 public void setUsername(String username) { 20 this.username = username; 21 } 22 23 @XmlElement 24 public String getPassword() { 25 return password; 26 } 27 28 public void setPassword(String password) { 29 this.password = password; 30 } 31 32 @XmlAttribute 33 public int getPin() { 34 return pin; 35 } 36 37 public void setPin(int pin) { 38 this.pin = pin; 39 } 40 41 }
程式碼中加的一堆@XML開頭的註解,是為了在傳輸過程中,如果需要以XML格式傳輸,這些註解可以幫助完成 XML Obj的轉換(詳情可參見JAXB相關內容)
1 @GET 2 @Path("/xml/user") 3 @Produces(MediaType.APPLICATION_XML) 4 public User getUserInXML() { 5 return getUser("unknown"); 6 } 7 8 @GET 9 @Path("/json/user") 10 @Produces(MediaType.APPLICATION_JSON) 11 public User getUserInJSON() { 12 return getUser("unknown"); 13 }
注意:這裡我們沒有使用JAXBElement
1 private User getUser(String username) { 2 User user = new User(); 3 user.setUsername(username); 4 String pwd = new Long(Math.round(Math.random() * 100000)).toString(); 5 user.setPassword(pwd); 6 int pin = (int) (Math.random() * 1000); 7 user.setPin(pin); 8 return user; 9 }
執行結果如下:
當然,也可以給方法增加引數,先從最基本型別的String引數耍起:
1 @GET 2 @Path("/xml/userByName/{name}") 3 @Produces(MediaType.APPLICATION_XML) 4 public User getUserInXML(@PathParam("name") String username) { 5 return getUser(username); 6 } 7 8 @GET 9 @Path("/json/userByName/{name}") 10 @Produces(MediaType.APPLICATION_JSON) 11 public User getUserInJSON(@PathParam("name") String username) { 12 return getUser(username); 13 }
執行結果如下:
如果加上包裝器JAXBElement
1 @GET 2 @Path("/xml/userByName2/{name}") 3 @Produces(MediaType.APPLICATION_XML) 4 public JAXBElementgetUserInXML2(@PathParam("name") String username) { 5 JAXBElement result = new JAXBElement (new QName( 6 XMLNS_NAMESPACE, ROOT_NODE), User.class, getUser(username)); 7 return result; 8 } 9 10 @GET 11 @Path("/json/userByName2/{name}") 12 @Produces(MediaType.APPLICATION_JSON) 13 public JAXBElement getUserInJSON2(@PathParam("name") String username) { 14 JAXBElement result = new JAXBElement (new QName("", 15 ROOT_NODE), User.class, getUser(username)); 16 return result; 17 }
結果如下:
箇中差異,請自行體會
四、單個String引數的實體Bean注入
web服務中方法的傳入引數,不可能都是基礎型別,同樣也可以是實體Bean
1 @GET 2 @Path("/xml/product/{name}") 3 @Produces(MediaType.APPLICATION_XML) 4 public Product getProductXML(@PathParam("name") Product product) { 5 return getProductFromServer(product); 6 } 7 8 @GET 9 @Path("/xml/product2/{name}") 10 @Produces(MediaType.APPLICATION_XML) 11 public JAXBElementgetProductXML2( 12 @PathParam("name") Product product) { 13 JAXBElement result = new JAXBElement (new QName( 14 XMLNS_NAMESPACE, ROOT_NODE), Product.class, 15 getProductFromServer(product)); 16 return result; 17 }
這裡我們用到了一個新的Bean :Product類,程式碼如下:
1 package yjmyzz.service.model; 2 3 import javax.xml.bind.annotation.XmlElement; 4 import javax.xml.bind.annotation.XmlRootElement; 5 6 @XmlRootElement(name = "product") 7 public class Product { 8 9 public Product() { 10 System.out.println("construct: Product() is called!"); 11 } 12 13 public Product(String name) { 14 System.out.println("construct: Product(String name) is called!"); 15 this.productName = name; 16 } 17 18 @XmlElement 19 public String getProductName() { 20 return productName; 21 } 22 23 public void setProductName(String productName) { 24 this.productName = productName; 25 } 26 27 private String productName; 28 29 }
先提個問題:從@Path上看,我們希望用類似 /xml/product/xxx 來請求該web方法,但是方法中的引數是一個Bean例項,而url中的xxx部分只是一個字串,一個字串如何被對映成一個Bean例項呢?
關鍵在於Product中的建構函式:Product(String name) ,方法getProductXML(@PathParam("name") Product product) 被請求時,url中的xxx部分會先對映成引數name,然後name又會被傳入到建構函式Product(String name)中,於是一個嶄新的Product物件誕生了!(可以透過eclipse Console的輸出來印證Product(String name)是否被呼叫)
執行結果:
eclipse的控制檯裡,也可以看到構造器,確實被呼叫了
除了利用“帶引數的構造器”來實現“url引數->Bean例項”的注入,JAX-RS機制還允許使用Bean自身提供的static valueOf()方法來實現注入,再來看一下示例:
從Product派生一個子類Book:
1 package yjmyzz.service.model; 2 3 import java.util.Calendar; 4 import java.util.Date; 5 6 import javax.xml.bind.annotation.XmlElement; 7 import javax.xml.bind.annotation.XmlRootElement; 8 9 @XmlRootElement(name = "book") 10 public class Book extends Product { 11 12 private String isbn; 13 14 private String author; 15 16 private Date publishDate; 17 18 public Book() { 19 System.out.println("construct: Book() is called!"); 20 } 21 22 public static Book valueOf(String isbn) { 23 System.out.println("Book: valueOf(String isbn) is called!"); 24 25 Book book = new Book(); 26 book.setISBN(isbn); 27 book.setProductName("Java程式設計思想(第4版)"); 28 29 book.setAuthor("[美]埃克爾"); 30 31 Calendar calendar = Calendar.getInstance(); 32 calendar.set(2007, 6, 1); 33 book.setPublishDate(calendar.getTime()); 34 return book; 35 } 36 37 @XmlElement 38 public String getISBN() { 39 return isbn; 40 } 41 42 public void setISBN(String isbn) { 43 this.isbn = isbn; 44 } 45 46 @XmlElement 47 public String getAuthor() { 48 return author; 49 } 50 51 public void setAuthor(String author) { 52 this.author = author; 53 } 54 55 @XmlElement 56 public Date getPublishDate() { 57 return publishDate; 58 } 59 60 public void setPublishDate(Date publishDate) { 61 this.publishDate = publishDate; 62 } 63 64 }
再定義一個新方法:
1 @GET 2 @Path("/xml/book/{ISBN}") 3 @Produces(MediaType.APPLICATION_XML) 4 public Book getBookXML(@PathParam("ISBN") Book book) { 5 return getBookFromServer(book); 6 }
裡面有一個輔助方法,程式碼如下:
1 private Book getBookFromServer(Book book) { 2 book.setProductName(book.getProductName() + " from server!"); 3 return book; 4 }
執行效果如下:
eclipse的控制檯資訊如下:
五、POST方式的Bean例項引數注入
前面提到的都是GET方式的web服務方法,GET方式能傳輸的資料大小有限,對於較大的引數資料,直接POST的場景更常見,下面是一個示例:
1 @POST 2 @Path("/json/add-book") 3 @Produces(MediaType.APPLICATION_JSON) 4 @Consumes(MediaType.APPLICATION_JSON) 5 public Book addBookJSON(Book book) { 6 return getBookFromServer(book); 7 } 8 9 10 @POST 11 @Path("/xml/add-book") 12 @Produces(MediaType.APPLICATION_XML) 13 @Consumes(MediaType.APPLICATION_XML) 14 public Book addBookXML(Book book) { 15 return getBookFromServer(book); 16 }
解釋一下:
又遇到了一個新的註解:@Consumes(MediaType.APPLICATION_JSON) 它表示傳入的Book例項是json格式。
我們用jQuery以Ajax方式呼叫這個服務演示一下:
1 function testJsonAddBook(){ 2 $(document).ready(function(){ 3 $.ajax({ 4 type:"POST", 5 url:"rest/json/add-book", 6 dataType: "json", 7 contentType: 'application/json', 8 data:JSON.stringify({"productName":"Java程式設計思想(第4版)","isbn":"9787111213826","author":"[美]埃克爾","publishDate":1183270161125}), 9 success: function(data, textStatus, jqXHR){ 10 alert("以下是從伺服器返回的Book物件:nn" + JSON.stringify(data)); 11 }, 12 error: function(jqXHR, textStatus, errorThrown){ 13 alert('error: ' + textStatus); 14 } 15 }); 16 }) 17 } 18 19 20 function testXmlAddBook(){ 21 $(document).ready(function(){ 22 $.ajax({ 23 type:"POST", 24 url:"rest/xml/add-book", 25 dataType: "xml", 26 contentType: 'application/xml', 27 data:"", 28 success: function(data, textStatus, jqXHR){ 29 alert("以下是從伺服器返回的Book物件:nn" + data.documentElement.outerHTML); 30 }, 31 error: function(jqXHR, textStatus, errorThrown){ 32 alert('error: ' + textStatus); 33 } 34 }); 35 }) 36 } Java程式設計思想(第4版) from server! [美]埃克爾 9787111213826 2007-07-01T13:33:30.782+08:00
執行效果如下:
如果斷點除錯ajax,可以看到傳過來的json串已經對映成Bean例項了
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4686/viewspace-2800436/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 使用SCA和JAX-RS建立RESTful服務REST
- 用 Go 快速開發一個 RESTful API 服務GoRESTAPI
- Java開發中RestFul服務介面規範JavaREST
- 使用CXF開發RESTFul服務REST
- RESTful API開發實戰 使用REST JSON XML和JAX-RS構建微服務 大資料和Web服務應用RESTAPIJSONXML微服務大資料Web
- Flask RESTful Web服務的開發套路總結FlaskRESTWeb
- yii2 restful web服務快速入門RESTWeb
- 搭建 Restful Web 服務RESTWeb
- Jersey 開發RESTful(七)Jersey快速入門REST
- RESTFul Web Api 服務框架(一)RESTWebAPI框架
- 線上服務Java程序假死快速排查、分析Java
- API開發平臺,全面快速整合釋出API服務API
- spring boot構建restful服務Spring BootREST
- yii2 restful web服務路由RESTWeb路由
- Yii2.0 RESTful Web服務(3)RESTWeb
- Yii2.0 RESTful Web服務(4)RESTWeb
- 如何使用RestTemplate訪問restful服務REST
- 第19章 建立RESTful Web服務RESTWeb
- Android服務端開發之使用Eclipse搭建Java Web服務端Android服務端EclipseJavaWeb
- JAVA微服務快速開發平臺的功能特點Java微服務
- 介面開發-restfulREST
- 轉享:Ehcache 服務和RESTful Web ServicesRESTWeb
- PHP開發Web服務PHPWeb
- LeaRun快速開發平臺,快速開發.net/java專案Java
- 使用多種客戶端消費WCF RestFul服務(一)——服務端客戶端REST服務端
- yii2 restful web服務[格式響應]RESTWeb
- Flask 系列 - 基於 Flask 提供 RESTful Web 服務FlaskRESTWeb
- InfoQ: 建立RESTful服務,有GET和POST足矣?REST
- 使用java開發阿里雲OSS開放雲端儲存服務Java阿里
- 銀彈谷:低程式碼開發助力快速建立金融服務平臺
- Restlet - 基於JAX-RS的Restlet開發例項REST
- HarmonyOS 位置服務開發指南
- 家政服務app開發功能APP
- 安卓開發之服務Service安卓
- 服務端開發小感服務端
- 快速開啟服務或者IIS或者遠端桌面
- JNPF快速開發平臺-簡單快速高效開發java專案Java
- Docker下Java檔案上傳服務三部曲之二:服務端開發DockerJava服務端