日期:2014-05-17  浏览次数:21006 次

Arch-03-09-使用 Apache CXF 封装现有的 Service 为 REST

Rest 方法简洁得令人抓狂,必须得把现有的 service 封装成 REST 方式。 Apache CXF 是不二之选。

?

计划一下内容:

(1)了解 CXF;

(2)下载 CXF;

(3)集成现有环境;

(4)封装 PhotoService 试试;

(5)前端调用一下下。

?

一、了解CXF

引用http://www.iteye.com/topic/424737

?

?

http://www.iteye.com/topic/424737 写道
概要:

CXF 力求为服务构建必须的基础组件,CXF的目标如下:
1,支持不同的绑定,包括SOAP,REST 和 Corba。
2,支持WS相关标准,包括WS-Addressing, WS-Security, WS-ReliableMessaging, 和 WS-Policy。
3,支持多种传输协议。
4,可插入的数据绑定。
5,前端的清晰分离,像 JAX-WS 从核心代码中分离。
6,高性能。
7,可嵌入。

CXF架构主要由下面几部分组成。
1,总线(Bus):这是CXF架构的主干。
2,传送消息 & 拦截器(Interceptors):它们提供了在底层的消息和管道层之上的功能。
3,前端:前端提供了一个编程模型来创建服务(像 JAX-WS)。
4,服务:服务管理一个服务模型(类WSDL模型来描述服务)
5,绑定,绑定提供解析这些协议(像 SOAP,REST,Corba)的功能
6,传输,由目的地和管道组成的传输抽象模型,使CXF保持传输中立。

好!下面让我们看一看CXF的各个组成部分以及它们是如何一起工作的。


总线(Bus):
总线是CXF运行时共享资源的供应者,共享资源包括:WSDL管理者,绑定工厂管理者等。总线能够很容易地被扩展
来包含你自己定制的资源和服务,或者你可以替换默认资源(像你自己的(可能基于Tomcat)HTTP目的地工厂(基于Jetty))
这些可能都由依赖注入来完成:默认的总线实现基于Spring(把运行时组件连接起来)。
SpringBusFactory 在类路径的META-INF/cxf目录下 查找所有 bean 配置文件,然后以这些
配置文件构建一个application context,构建 application context 的 bean 配置文件包括:
1,META-INF/cxf/cxf.xml (只在 cxf-rt-core )
2,META-INF/cxf/cxf-extension.xml (像在 cxf-rt-bindings-soap)
3,META-INF/cxf/cxf-property-editors.xml (像在 cxf-rt-transports-http).

消息传递 & 拦截器
CXF 建立在一个通用的消息传递层(由消息,拦截器 和 拦截器链。拦截器是功能的基础单元)之上。

?

?二、下载

完成这件事最没有技术含量了。http://cxf.apache.org/download.html

?

三、集成现有环境

?

四、封装 PhotoService 试试

?

五、前端调用一下下

http://www.yoxigen.com/yoxview/

?

六、问题汇总

(1)JSONProvider 检查

?

    <!-- custom JSONProvider with serializeAsArray to force arrays when only one item exists in a collection -->
    <bean id="jsonProvider" class="org.apache.cxf.jaxrs.provider.JSONProvider">
        <property name="serializeAsArray" value="true"/>
        <property name="arrayKeys" ref="jsonKeys"/>
    </bean>
...
   <bean id="streamingServiceImpl" class="com.plusrun.apps.streaming.rest.impl.StreamingServiceImpl"
          parent="remoteSupport">
    </bean>

    <jaxrs:server id="streamingService"
                  address="/v2/rest/activity-stream">
        <jaxrs:serviceBeans>
            <ref bean="streamingServiceImpl"/>
        </jaxrs:serviceBeans>
        <jaxrs:providers>
            <ref bean="jsonProvider"/>
        </jaxrs:providers>
    </jaxrs:server>

?

?? ?可以在扩展?JSONProvider 的方法中检查钓鱼方法

?

?

  public void writeTo(Object obj, Class<?> cls, Type genericType, Annotation[] anns, MediaType m, MultivaluedMap<String, Object> headers, OutputStream os)
    throws IOException
  {
    if ("GET".equalsIgnoreCase(this.request.getMethod())) {
      os.write("不支持浏览器 GET 方法".getBytes());
      os.flush();
    }

    super.writeTo(obj, cls, genericType, anns, m, headers, os);
  }

?

?

(2)输出 Java List 对象的时候,如果结果集是一条记录时,输出到 XML 和 JSON 都不是数组;如果结果集是两条以上的时候,输出的 XML 就自动变成数组。NND 给前端造成极大的困惑,搞了两小时,才整明白,JAXB 输出 XML 时,对 LIST 支持不太好。

解决方法:定义 arrayKeys

?

?

    <util:list id="jsonKeys">
        <value>Users</value>
    </util:list>

    <util:list id="jsonTypes">
        <value>application/json</value>
        <value>application/jettison</value>
    </util:list>

    <bean id="jsonProvider" class="org.apache.cxf.jaxrs.provider.JSONProvider">
        <prop