1. 程式人生 > >用Java實現RESTful Web Services框架的簡要步驟

用Java實現RESTful Web Services框架的簡要步驟

1、         REST和RESTful Web Services的簡要說明

REST(RepresentationalState Transfer),中文稱為表述性狀態轉移,是一種針對於網路應用開發的軟體架構風格,是滿足一定的架構約束條件的。REST包括的準則主要有:1)網路上所有事物都抽象成資源;2)每個資源對應唯一的URI;3)通過通用介面對資源操作;5)操作都是無狀態的;

RESTfulWeb Services,這是基於REST和HTTP實現的Web服務,在其實現的時候定義了URI,對資源的操作,以及支援的MIME型別等。

2、         JAX-RS和Jersey的簡要說明:

JAX-RS,或稱JSR311,是幫助實現RESTful WebServices的一組API,而Jersey則是其參考實現。

3、         開發環境配置:

Eclipse: 需要能進行Web Service開發的版本,例如《Eclipse IDE forJava EE Developers》,官網的下載地址附在部落格末尾;

Tomcat:Tomcat是作為Web應用程式的伺服器而使用的,為了在本次開發中能正確開發並除錯程式,需要在Eclipse上預先配置Tomcat,具體步驟給出了相關連結,不在博文內直接表述。Tomcat的下載版本也至於文末;

4、         Jersey開發包下載以及其它包下載:


為了開發RESTful Web服務,需要下載對應的Jersey庫檔案,同時在本程式中,由於需要採用JSON樣式,需要額外下載部分jar包;所有需要的jar包的截圖如下:

其中,Jersey相關庫檔案可從其官網下載,連結文末給出;其餘jar包也一起打包置於lib.rar中。

5、         具體步驟:

步驟一:新建Eclipse工程:“File->New->Other->DynamicWeb Project”,此處將工程命名為Jersey,之後的配置大約如下,具體需要注意Target runtime需要指定為對應的Tomcat版本,例如此處是7.0;


步驟二:將剛才下載的全部jar包複製到工程目錄下,WEB-INF資料夾下的lib中,如圖所示;


步驟三:新建包用於存放所有資源,此處命名為sample.hello.resources,並新建類HelloResource(此資源僅用於測試,之後可以刪除),程式碼如下:

package sample.hello.resources;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

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

其中,@Path即定義了資源的URI,@Get即HTTP的Get方法,@Produces聲明瞭相應內容的MIME型別;

步驟四:修改WEB-INF下的web.xml檔案,內容改為:

<?xml version="1.0" encoding="UTF-8"?>
Jerseyindex.htmlindex.htmindex.jspdefault.htmldefault.htmdefault.jspJersey REST Service
  com.sun.jersey.spi.container.servlet.ServletContainer
com.sun.jersey.config.property.packagessample.hello.resources1Jersey REST Service/rest/*

之後就可以嘗試啟動Tomcat,並在瀏覽器中輸入:http://your_domain:port/display-name/url-pattern/path_from_rest_class以訪問資源了,例到目前為止,要訪問HelloResource則需要進入http://localhost:8080/Jersey/rest/hello.成功的話,則瀏覽器返回‘Hello Jersey’.

步驟五:接下來,以所謂聯絡人(Contacts)為樣例程式進行開發,主要的資源包括了ContactResource和ContactsResource兩種,後者是前者的資源集合;資源定義分別如下:

public class ContactResource {
	@Context
	UriInfo uriInfo;
	@Context
	Request request;
	String contact;
	
	public ContactResource(UriInfo uriInfo, Request request, 
			String contact) {
		this.uriInfo = uriInfo;
		this.request = request;
		this.contact = contact;
	}
	
	@GET
	@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
	public Contact getContact() {
		Contact cont = ContactStore.getStore().get(contact);
		if(cont==null)
			throw new NotFoundException("No such Contact.");
		return cont;
	}
}    

ContactsResource:

@Path("/contacts")
public class ContactsResource {
	@Context
	UriInfo uriInfo;
	@Context
	Request request;

	@GET
	@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
	public List getContacts() {
		List contacts = >new ArrayList();
		contacts.addAll( ContactStore.getStore().values() );
		return contacts;
	}

@Path("{contact}")
	public ContactResource getContact(
			@PathParam("contact") String contact) {
		return new ContactResource(uriInfo, request, contact);
	}
}           

這樣就定義完樣例程式的資源了。在具體實現程式時應該根據需要定義資源的屬性和方法;

步驟六:上述僅僅實現了對資源的Get操作,即“檢索某一資源的表現形式”或“列出資源集合中的所有成員”,要實現POST(建立資源或子資源),PUT(更新資源),DELETE(刪除資源)操作,則需要在資源定義中宣告額外的方法。例如:

POST操作(建立一個Contact):

@POST
@Produces(MediaType.TEXT_HTML)
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public void newContact(
		@FormParam("id") String id,
		@FormParam("name") String name,
		@Context HttpServletResponse servletResponse
) throws IOException {
	Contact c = new Contact(id,name,new ArrayList
()); ContactStore.getStore().put(id, c); URI uri = uriInfo.getAbsolutePathBuilder().path(id).build(); Response.created(uri).build(); servletResponse.sendRedirect("../pages/new_contact.html"); }

PUT操作(更新一個Contact):

@PUT
@Consumes(MediaType.APPLICATION_XML)
public Response putContact(JAXBElement jaxbContact) {
	Contact c = jaxbContact.getValue();
	return putAndGetResponse(c);
}

private Response putAndGetResponse(Contact c) {
	Response res;
	if(ContactStore.getStore().containsKey(c.getId())) {
		res = Response.noContent().build();
	} else {
		res = Response.created(uriInfo.getAbsolutePath()).build();
	}
	ContactStore.getStore().put(c.getId(), c);
	return res;
}   

DELETE(刪除一個Contact):

@DELETE
public void deleteContact() {
	Contact c = ContactStore.getStore().remove(contact);
	if(c==null)
		throw new NotFoundException("No such Contact.");
}  

步驟七(只針對樣例程式):這一步驟是為了實現資源的定義而附加的操作,與具體的Web服務有關。就樣例程式而言,這一步是必須的,但是對於其它程式則不是。在定義完成資源之後需要額外增加四個類的定義:位於sample.hello.bean下的Address類的定義和Contact類的定義,位於sample.hello.storage下的ContactStore,以及位於sample.hello.util下的ParamUtil類的定義。程式碼分別如下:

Address.java:

package sample.hello.bean;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Address {
	private String city;
	private String street;
	
	public Address() {}
	
	public Address(String city, String street) {
		this.city = city;
		this.street = street;
	}

	public String getCity() {
		return city;
	}

	public void setCity(String city) {
		this.city = city;
	}

	public String getStreet() {
		return street;
	}

	public void setStreet(String street) {
		this.street = street;
	}
	
}

Contact.java:

package sample.hello.bean;

import java.util.List;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Contact {
	private String id;
	private String name;
	private List
addresses; public Contact() {} public Contact(String id, String name, List
addresses) { this.id = id; this.name = name; this.addresses = addresses; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @XmlElement(name="address") public List
getAddresses() { return addresses; } public void setAddresses(List
addresses) { this.addresses = addresses; } }

ContactStore.java:

package sample.hello.storage;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import sample.hello.bean.Address;
import sample.hello.bean.Contact;

public class ContactStore {
	private static Map store;
	private static ContactStore instance = null;
	
	private ContactStore() {
		store = new HashMap();
		initOneContact();
	}
	
	public static Map getStore() {
		if(instance==null) {
			instance = new ContactStore();
		}
		return store;
	}
	
	private static void initOneContact() {
		Address[] addrs = {
			new Address("Shanghai", "Long Hua Street"),
			new Address("Shanghai", "Dong Quan Street")
		};
		Contact cHuang = new Contact("huangyim", "Huang Yi Ming", Arrays.asList(addrs));
		store.put(cHuang.getId(), cHuang);
	}
}

ParamUtil.java:

package sample.hello.util;

import java.util.HashMap;
import java.util.Map;

public class ParamUtil {
	public static Map parse(String paramString) {
		Map params = new HashMap();
		String[] paramPairs = paramString.split("&");
		for(String param : paramPairs) {
			String[] key_value = param.split("=");
			params.put(key_value[0], key_value[1]);
		}
		return params;
	}
}

到此為止,樣例程式的資源定義就完成了。

步驟八(只針對樣例程式):此時啟動Tomcat並訪問ContactsResource資源,則可以看到一個Contact的JSON的樣式表現如下:

{"contact":{"address":[{"city":"Shanghai","street":"LongHua Street"},{"city":"Shanghai","street":"DongQuanStreet"}],"id":"huangyim","name":"HuangYi Ming"}}

步驟九(選做):通過Jersey Client可以與RESTful Web 服務通訊,這可以用於對服務進行單元測試(基於不同操作)。所需要完成的內容大概如下:

package sample.hello.client;

import java.util.Arrays;
import java.util.List;

import javax.ws.rs.core.MediaType;
import javax.xml.bind.JAXBElement;

import sample.hello.bean.Address;
import sample.hello.bean.Contact;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.GenericType;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.representation.Form;

public class ContactClient {
	public static void main(String[] args) {
		Client c = Client.create();
		WebResource r = c.resource("http://localhost:8080/Jersey/rest/contacts");
		
		System.out.println("===== Get huangyim =====");
		getOneContact(r, "huangyim");
		
		System.out.println("===== Create foo =====");
		postForm(r, "foo", "bar");
		
		Address[] addrs = {
			new Address("Shanghai", "Ke Yuan Street")
		};
		Contact cnt = new Contact("guoqing", "Guo Qing", Arrays.asList(addrs));
		
		System.out.println("===== Create guoqing =====");
		putOneContact(r, cnt);
		
		System.out.println("===== All Contacts =====");
		getContacts(r);
		
		System.out.println("===== Delete foo =====");
		deleteOneContact(r, "foo");
		
		System.out.println("===== All Contacts =====");
		getContacts(r);
	}
	
	public static void getContacts(WebResource r) {
		
		// 1, get response as plain text
		String jsonRes = r.accept(MediaType.APPLICATION_JSON).get(String.class);
		System.out.println(jsonRes);
		
		String xmlRes = r.accept(MediaType.APPLICATION_XML).get(String.class);
		System.out.println(xmlRes);
		
		// 2, get response and headers etc, wrapped in ClientResponse
		ClientResponse response = r.get(ClientResponse.class);
		System.out.println( response.getStatus() );
		System.out.println( response.getHeaders().get("Content-Type") );
		String entity = response.getEntity(String.class);
		System.out.println(entity);
		
		// 3, get JAXB response
		GenericType> genericType = new GenericType>() {};
		List contacts = r.accept(MediaType.APPLICATION_JSON).get(genericType);
		System.out.println("No. of Contacts: " + contacts.size());
		Contact contact = contacts.get(0);
		System.out.println(contact.getId() + ": " + contact.getName());
	}
	
	public static void getOneContact(WebResource r, String id) {
		GenericType> generic = new GenericType>() {};
		JAXBElement jaxbContact = r.path(id).accept(MediaType.APPLICATION_JSON).get(generic);
		Contact contact = jaxbContact.getValue();
		System.out.println(contact.getId() + ": " + contact.getName());
	}
	
	public static void postForm(WebResource r, String id, String name) {
		Form form = new Form();
		form.add("id", id);
		form.add("name", name);
		ClientResponse response = r.type(MediaType.APPLICATION_FORM_URLENCODED)
								   .post(ClientResponse.class, form);
		System.out.println(response.getEntity(String.class));
	}
	
	public static void putOneContact(WebResource r, Contact c) {
		ClientResponse response = r.path(c.getId()).accept(MediaType.APPLICATION_JSON)
								   .put(ClientResponse.class, c);
		System.out.println(response.getStatus());
	}
	
	public static void deleteOneContact(WebResource r, String id) {
		ClientResponse response = r.path(id).delete(ClientResponse.class);
		System.out.println(response.getStatus());
	}


}

以上便是用Java進行RESTful WebServices開發的全部內容。主要的工作在於對URI的定義和相關操作方法的定義。

附加連結:

1、 Eclipse 官網下載:http://www.eclipse.org/downloads/

2、 Tomcat官網下載:http://tomcat.apache.org/download-70.cgi

3、 在Eclipse上配置Tomcat: http://jingyan.baidu.com/article/ca2d939dd90183eb6d31ce79.html

4、  Jersey官網下載:https://jersey.java.net/download.html

5、 參考連結1:http://only81.iteye.com/blog/1689537

6、 參考連結2:http://hbluojiahui.blog.163.com/blog/static/310647672009823101440937/

7、 參考連結3:http://blog.csdn.net/zztfj/article/details/7608991