使用Jquery,Jackson JSON,JAX-RS,Apache Wink,Spring实现REST应用开发
简介
REST是英文RepresentationalStateTransfer的缩写,有中文翻译为“具象状态传输”。相较于基于SOAP和WSDL的Web服务,REST模式提供了更为简洁的实现方案。目前,越来越多的Web服务开始采用REST风格设计和实现。
REST中的一个重要概念是资源的存在性,每个资源都一个全局引用标识符,即URI。特别是数据和函数都被认为是可通过URI识别和访问的资源。为了操纵这些资源,网络组件,客户端和服务器通过一个标准的接口通信,如HTTP和一个组固定的动词—GET,PUT,POST和DELETE—交换这些资源。
JAX-RS为在Java中构建RESTfulWeb服务提供了标准化API,API提供了一组注解,以及相关的类和接口。对POJO应用注解允许你暴露Web资源,这个方法使得在Java中创建RESTfulWeb服务变得简单。
ApacheWink是一个简单而强大的RESTfulWeb服务创建框架。它由一个服务器端模块和一个客户端模块组成。ApacheWink的服务器端模块是JAX-RS1.0规范的一个完全实现。除了对基本协议的实现外,ApacheWink服务器端模块还提供了一系列便于开发RESTfulWeb服务的新特性。ApacheWink客户端模块提供了调用RESTfulWeb服务的相关功能,该模块基于JDKHttpURLConnection实现。
简单的说:REST是一种WebService的设计模式,本文提到的实现方式,是从浏览器客户端借用jQuery发送Ajax请求到server端的ApacheWink提供的JAX-RS服务(每个Resource是由spring负责实例化的)从而实现WebService。
好了,废话不多说了,现在贴出具体的代码样例。
开发环境:
JDK1.5以上
Jquery1.4以上
jackson-all-1.6.2.jar
jsr311-api.jar
wink-server-1.1.2-incubating.jar
Spring2.0以上
JaxRSResource.java
--该接口没有任何方法,只是为了让spring过滤所有实现该接口的Resource
package com.cuishen.jaxrs.demo; public interface JaxRSResource { }
WinkApplication.java
--继承自javax.ws.rs.core.Application,并重写getSingletons(),在该方法中调用spring的getBean()接口,并过滤出所有实现了JaxRSResource接口的bean,然后返回给Application
package com.cuishen.jaxrs.demo; import java.util.HashSet; import java.util.Set; import javax.ws.rs.core.Application; import com.cuishen.jaxrs.demo.factory.MyBeanFactory;; public class WinkApplication extends Application { public WinkApplication() { } @Override public Set<Object> getSingletons() { String beans[] = MyBeanFactory.getBeanNamesForType(JaxRSResource.class); Set<Object> result = new HashSet<Object>(); if (beans != null) { for (int i = 0; i < beans.length; i++) { String beanName = beans[i]; result.add(MyBeanFactory.getBean(beanName)); } } return result; } }
DemoResource.java
--具体的Resource实现,实现JaxRSResource接口,也是spring托管的一个bean
package com.cuishen.jaxrs.demo; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.ws.rs.*; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.codehaus.jackson.map.ObjectMapper; import com.cuishen.jaxrs.demo.bean.TestBean; @Path("/accountDemo") public class DemoResource implements JaxRSResource { private static final Log log = LogFactory.getLog(DemoResource.class); @POST @Path("/transactions/{id}") @Produces("application/json") public Map<String, String> getTransactions(@PathParam("id") String id) throws Exception { log.error("============================= successful getTransactions ================="); Map<String, String> map = new HashMap<String, String>(); map.put("id", id); return map; } @POST @Path("/transactions/") @Consumes("application/json") @Produces("application/json") public String getTransactions(HashMap<String, String> params) throws Exception { log.error("============================= successful getTransactions 2 ================="); List<TestBean> list = new ArrayList<TestBean>(); TestBean bean = new TestBean(); String id = (String) params.get("id"); bean.setId(id); bean.setName("xiao ming"); list.add(bean); bean = new TestBean(); bean.setId("222"); bean.setName("xiao zhang"); list.add(bean); ObjectMapper objectMapper = new ObjectMapper(); String listJson = objectMapper.writeValueAsString(list); return listJson; } @POST @Path("/demoData") @Consumes("application/x-www-form-urlencoded") @Produces("application/json") public String getDemoData(@FormParam("id") String id, @FormParam("name") String name) throws Exception { log.error("============================= successful getDemoData ================="); List<TestBean> list = new ArrayList<TestBean>(); TestBean bean = new TestBean(); bean.setId(id); bean.setName(name); list.add(bean); bean = new TestBean(); bean.setId("222"); bean.setName("xiao zhang"); list.add(bean); ObjectMapper objectMapper = new ObjectMapper(); String listJson = objectMapper.writeValueAsString(list); return listJson; } @POST @Path("/demoData") @Consumes("application/json") @Produces("application/json") public String getDemoData(HashMap<String, String> params) throws Exception { log.error("============================= successful getDemoData 2 ================="); List<TestBean> list = new ArrayList<TestBean>(); TestBean bean = new TestBean(); String id = (String) params.get("id"); bean.setId(id); String name = (String) params.get("name"); bean.setName(name); String birthday = (String) params.get("birthday"); bean.setBirthday(birthday); list.add(bean); bean = new TestBean(); bean.setId("222"); bean.setName("xiao zhang"); list.add(bean); ObjectMapper objectMapper = new ObjectMapper(); String listJson = objectMapper.writeValueAsString(list); return listJson; } }
TestBean.java
--Json序列化时要用到
package com.cuishen.jaxrs.demo.bean; import java.io.Serializable; //import org.codehaus.jackson.annotate.JsonProperty; public class TestBean implements Serializable { private static final long serialVersionUID = -8079868256837582676L; //@JsonProperty("id") private String id; //@JsonProperty("name") private String name; private String birthday; public String getBirthday() { return birthday; } public void setBirthday(String birthday) { this.birthday = birthday; } //@JsonProperty("id") public String getId() { return id; } //@JsonProperty("id") public void setId(String id) { this.id = id; } //@JsonProperty("name") public String getName() { return name; } //@JsonProperty("name") public void setName(String name) { this.name = name; } /** @Override public String toString() { return "TestBean{" + "id='" + id + '\'' + ",name='" + name + '\'' + '}'; }*/ }
MyBeanFactory.java
--这个大家都懂的,具体的实现自己看着办吧
package com.cuishen.jaxrs.demo.factory; public class MyBeanFactory { public static String[] getBeanNamesForType(Class clazz) { // do something to get bean names for bean type from spring IOC container return null; } public static Object getBean(String beanName) { // do something to get bean by beanName from spring IOC container return null; } }
spring-application-context-jaxrs-demo.xml
--这个怎么用大家也都懂的。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"> <bean name="jaxrs.demo.accountDemo" class="com.cuishen.jaxrs.demo.DemoResource"> </bean> </beans>
web.xml
--这个也不用说了吧
<servlet> <servlet-name>jaxrs</servlet-name> <servlet-class>org.apache.wink.server.internal.servlet.RestServlet </servlet-class> <init-param> <param-name>javax.ws.rs.Application</param-name> <param-value>com.cuishen.jaxrs.demo.WinkApplication</param-value> </init-param> <load-on-startup>10</load-on-startup> </servlet> <servlet-mapping> <servlet-name>jaxrs</servlet-name> <url-pattern>/REST/*</url-pattern> </servlet-mapping>
index.jsp
<form id="formDemo" name="formDemo" action="/DomainID/REST/accountDemo/demoData" method=post> <input type="text" value="333333" id="id" name="id"> <input type="text" value="ZhangSan" id="name" name="name"> <input type="text" value="1981" id="birthday" name="birthday"> </form> <script type="text/javascript"> function form2Json() { var formObj = $("#formDemo"); var JsonObj = "'{"; var a = formObj.serializeArray(); var index = 0; $.each(a, function() { index++; JsonObj += "\"" + this.name + "\":\"" + this.value + "\""; if(a.length != 1 && a.length != index) { JsonObj += ","; } }); JsonObj += "}'"; return eval(JsonObj); } function doit() { // sample one jQuery.ajax({url:'/DomainID/REST/accountDemo/transactions/111111', type:'POST', dataType:'json', success:function(data, status, xhr) { // here you can do whatever is necessary with the data. alert("sample one"); alert(data.id); }, error:function(xhr,error,exception) { // handle the error. alert(exception.toString()); } }); // sample two $.ajax({url:'/DomainID/REST/accountDemo/transactions', data:'{"id":222222}', type:'POST', dataType:'json', contentType:'application/json', success:function(data, status, xhr) { // here you can do whatever is necessary with the data. alert("sample two"); alert(data[0].id); alert(data[0].name); }, error:function(xhr,error,exception) { // handle the error. alert(exception.toString()); } }); // sample three $.ajax({url:$("#formDemo").attr('action'), type:'POST', data:$("#formDemo").serialize(), dataType:'json', contentType:'application/x-www-form-urlencoded', success:function(data, status, xhr) { // here you can do whatever is necessary with the data. alert("sample three"); alert(data[0].id); alert(data[0].name); }, Error:function(xhr,error,exception) { // handle the error. alert(exception.toString()); } }); // sample four $.ajax({url:$("#formDemo").attr('action'), type:'POST', data:form2Json(), dataType:'json', contentType:'application/json', success:function(data, status, xhr) { // here you can do whatever is necessary with the data. alert("sample four"); alert(data[0].id); alert(data[0].name); alert(data[0].birthday); }, Error:function(xhr,error,exception) { // handle the error. alert(exception.toString()); } }); } </SCRIPT> <input type="button" value="click me" onclick="doit()">
ok!代码演示完了,有几个注意点:
1.如果遇到404NotFound的错,肯定是Ajax请求找不到URL或者说那个resource里面的方法。
2.不仅方法名,参数要匹配,而且参数类型也要匹配。
3.resource里面,@Consumes("application/json")表示请求的数据类型是json,@Produces("application/json")表示返回的数据类型是json
4.js里面,contentType:'application/json'表示发出的请求要以json为数据格式,dataType:'json'表示接收的数据类型为json
5.POST和GET都可以,但是js和resource两边要一致。