在这里简单的说下CXF对REST的支持,先对REST概念说下。
REST 是一种软件架构模式,只是一种风格,不是像SOAP 那样本身承载着一种消息协议,也可以叫做REST 是基于HTTP协议的软件架构。
REST 中重要的两个概念就是资源定位和资源操作,而HTTP 协议恰好完整的提供了这两个要点,HTTP 协议中的URI 可以完成资源定位,GET、POST、OPTION等方法可以完成资源操作,因此REST 完全依赖HTTP 协议就可以完成Web 服务,而不像SOAP 协议那样只利用HTTP 的传输特性,定位与操作由SOAP 协议自身完成,也正是由于SOAP 消息的存在,使得SOAP 笨重。你也可以说REST 充分利用了HTTP 协议的特性,而不是像SOAP 那样只利用了其传输这一特性(事实上大多数人提到HTTP 协议就只会想到它能用于数据传输)。
REST 是一种软件架构理念,现在被移植到Web 服务上(因此不要提到REST 就马上想到WebService,JAX-RS 只是将REST 设计风格应用到Web 服务开发),那么在开发Web 服务上,偏于面向资源的服务适用于REST,偏于面向活动的服务。另外,REST 简单易用,效率高,SOAP 成熟度较高,安全性较好。REST 提供的网络服务叫做OpenAPI,它不仅把HTTP 作为传输协议,也作为处理数据的工具,可以说对HTTP 协议做了较好的诠释,充分体现了HTTP 技术的网络能力。目前Google、Amazon、淘宝都有基于REST 的OpenAPI 提供调用。
CXF的Rest使用的JAX-RS规范。JAX-RS: Java API for RESTful Web Services是一个Java编程语言的应用程序接口,支持按照 表象化状态转变 (REST)架构风格创建Web服务Web服务. JAX-RS使用了Java SE 5引入的Java 标注来简化Web服务客户端和服务端的开发和部署。
JAX-RS提供了一些标注将一个资源类,一个POJOJava类,封装为Web资源。标注包括:
(1)、@Path,标注资源类或方法的相对路径
(2)、@GET,@PUT,@POST,@DELETE,标注方法是用的HTTP请求的类型
(3)、@Produces,标注返回的MIME媒体类型,( 注解标注,这个注解可以包含一组字符串,默认值是*/*,它指定REST 服务的响应结果的MIME 类型,例如:application/xml、application/json、image/jpeg 等),你 也可以同时返回多种类型,但具体生成结果时使用哪种格式取决于ContentType。CXF 默认返回的是JSON 字符串。
(4)、@PathParam,@QueryParam,@HeaderParam,@CookieParam,@MatrixParam,@FormParam,分别标注方法的参数来自于HTTP请求的不同位置,例如@PathParam来自于URL的路径,@QueryParam来自于URL的查询参数,@HeaderParam来自于HTTP请求的头信息,@CookieParam来自于HTTP请求的Cookie。
下面是一个具体的例子
1. 假设我们有个服务 (都是从别处拿来的代码)
import javax.ws.rs.*;
import javax.ws.rs.core.Response;
@Path(value = "/student/{id}")
public interface StudentService
{
@GET
@Path(value = "/info")
Student getStudent(@PathParam("id") long id, @QueryParam("name")
String name);
@GET
@Path(value = "/info2")
UserResponse getStudent(@QueryParam("name") String name);
}
服务实现类:
import javax.ws.rs.core.Response;
import java.text.ParseException;
import java.text.SimpleDateFormat;
public class StudentServiceImpl implements StudentService
{
public Student getStudent(long id, String name)
{
Student s = new Student();
s.setId(id);
s.setName(name);
try
{
s.setBirthday(new SimpleDateFormat("yyyy-MM-dd").parse("1983-04-26"));
}
catch (ParseException e)
{
e.printStackTrace();
}
return s;
}
public Response getStudent1(String name)
{
Student s = new Student();
s.setId(1);
s.setName(name);
try
{
s.setBirthday(new SimpleDateFormat("yyyy-MM-dd").parse("1983-04-26"));
}
catch (ParseException e)
{
e.printStackTrace();
}
return Response.ok(s).build();
//return s;
}
public UserResponse getStudent(String name)
{
Student s = new Student();
s.setId(1);
s.setName(name);
try
{
s.setBirthday(new SimpleDateFormat("yyyy-MM-dd").parse("1983-04-26"));
}
catch (ParseException e)
{
e.printStackTrace();
}
return new UserResponse("ok", s);
}
返回数据包装类
import javax.xml.bind.annotation.*;
@XmlRootElement(name = "Response")
@XmlAccessorType(XmlAccessType.FIELD)
public class UserResponse
{
private String status;
private Student data;
public UserResponse()
{
}
public UserResponse(String status, Student data)
{
this.status = status;
this.data = data;
}
public String getStatus()
{
return status;
}
public void setStatus(String status)
{
this.status = status;
}
public Object getData()
{
return data;
}
public void setData(Student data)
{
this.data = data;
}
}
普通类
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.Date;
@XmlRootElement(name = "Student")
@XmlAccessorType(XmlAccessType.FIELD)
public class Student
{
private long id;
private String name;
private Date birthday;
public long getId()
{
return id;
}
public void setId(long id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public Date getBirthday()
{
return birthday;
}
public void setBirthday(Date birthday)
{
this.birthday = birthday;
}
}
Spring 服务声明
Spring中引入了两个新的名称空间jaxws、jaxrs,因为CXF 实现了Spring 的NamespaceHandler 接口,实现这个接口可以在Spring 中增加额外的配置。那么jaxws 自然是配置SOAP 方式的Web 服务,你可以看到有jaxws:server、jaxws:endpoint、jaxws:client 三个元素,jaxws:server 和jaxws:endpoint 是等效的,都用于发布Web 服务,出现jaxws:endpoint 的原因是JAX-WS 规范中使用EndPoint 发布Web 服务(前面使用过这种
方式),CXF 为了和JAX-WS 对应,提供了这个与jaxws:server 功能一样的配置元素;
jaxrs是REST 方式的Web 服务,有jaxrs:server、jaxrs:client 两个元素。
<import resource="classpath:META-INF/cxf/cxf.xml"/>
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/>
<import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
<import resource="classpath:META-INF/cxf/cxf-extension-jaxrs-binding.xml"/>
<bean id="rsStudentServiceImpl" class="ex3.StudentServiceImpl" />
<jaxrs:server id="test" address="/student" >
<jaxrs:serviceBeans>
<ref bean="rsStudentServiceImpl" />
</jaxrs:serviceBeans>
<!-- 这里设置了对应关系, 按理说默认就应该是这样, 你可以试试. 当然可以自定义 -->
<jaxrs:extensionMappings>
<entry key="json" value="application/json"/>
<entry key="xml" value="application/xml"/>
</jaxrs:extensionMappings>
</jaxrs:server>
web.xml 配置
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/webservice/*</url-pattern>
</servlet-mapping>
2. 访问方法有3种, 可以实现获取不同格式的内容.
http://localhost:8080/student/student/3/info2.json?name=abcss
http://localhost:8080/student/student/3/info2.xml?name=abcss
http://localhost:8080/student/student/3/info2?name=abcss&_type=xml
http://localhost:8080/student/student/3/info2?name=abcss&_type=json
还有一种办法就是在请求时设置Accept:
HttpGet get = new HttpGet(
"http://127.0.0.1:8080/student/student/3/info2?name=Fetion");
HttpClient httpclient = new DefaultHttpClient();
get.addHeader("ACCEPT", "application/xml");
HttpResponse response = httpclient.execute(get);
StatusLine st = response.getStatusLine();
InputStream ins = response.getEntity().getContent();
byte[] b = new byte[1024];
StringBuilder sb = new StringBuilder();
while (ins.read(b) != -1)
{
sb.append(new String(b, "UTF-8"));
}
System.out.println(sb.toString());