• webservice随记


    WebService:跨平台、系统、跨语言间相互调用


    CXF:
    Axis(Apache)-> Axis2(Apache)
    XFire -> CXF(Celtrix + XFire)(Apache)


    XFire —— WebService框架
    Celtrix —— ESB框架,Enterprise Service Bus,即企业服务总线


    SOA(面向服务的架构)
    service1、service2、service3 。。。所有组件都是“即插即用”的,每个组件提供一种服务


    IBM提倡面向SOA架构,希望以"组装电脑"的方式来开发软件


    1、提供各种服务的组件(WebService)
    2、企业服务总线(ESB)


    CXF号称是SOA框架
    CXF内置一个Jetty Web服务器,优于Tomcat


    -----------------------------------------------------------------------------
    使用CXF开发WebService服务端:
    /*************每个WebService组件需要2个部分,接口和实现类*************/
    1、开发一个WebService业务接口
    该接口必须使用@WebService修饰
    2、开发一个WebService实现类
    该实现类也要用@WebService修饰 -> @WebService(endpointInterface="org.cxf.ws.HelloWorld",serviceName="HelloWorldWs")


    最终web页面里面生成的如下:
    -----------------------------------------------------------------------------------------------------------
    This XML file does not appear to have any style information associated with it. The document tree is shown below.
    <!--
    Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.4-b01. 
    -->
    <!--
    Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.4-b01. 
    -->
    <definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://impl.ws.cxf.org/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://impl.ws.cxf.org/" name="HelloWorldWs">
    <import namespace="http://ws.cxf.org/" location="http://127.0.0.1/helloWorldWs?wsdl=1"/>
    <binding xmlns:ns1="http://ws.cxf.org/" name="HelloWorldWsPortBinding" type="ns1:HelloWorld">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
    <operation name="sayHi">
    <soap:operation soapAction=""/>
    <input>
    <soap:body use="literal"/>
    </input>
    <output>
    <soap:body use="literal"/>
    </output>
    </operation>
    </binding>
    <service name="HelloWorldWs">
    <port name="HelloWorldWsPort" binding="tns:HelloWorldWsPortBinding">
    <soap:address location="http://127.0.0.1/helloWorldWs"/>
    </port>
    </service>
    </definitions>
    -------------------------------------------------------------------------------------------------------------
    3、发布WebService
    使用endpoint类的静态方法来发布Web Service


    -----------------------------------------------------------------------------------
    使用CXF开发web客户端
    1、调用CXF提供的wsdl2java工具,根据wsdl文档生成相应的java代码——cmd中使用命令:wsdl http://127.0.0.1/helloWorldWs?wsdl
    wsdl = web service definition language即web服务描述语言


    任何语言实现了web service,都需要暴露一个wsdl文档


    2、找到wsdl2java所生成的类中,一个继承了service接口的类
    该类的实例可当成工厂来使用


    3、调用service子类实例的getXxxPort方法,返回一个远程Web Service的代理


    形参、返回值
    1、当形参、返回值的类型都是String基本数据类型的时候,CXF可以轻松处理
    2、当形参、返回值类型是JavaBean式的集合类、List集合、数组等时,CXF可以处理?
    CXF也可以很好地处理
    3、还有一些像Map、非JavaBean式的复合类,CXF是处理不了的


    Web Service三个技术基础:
    1、WSDL   Web Service Definition Language


    --------------------------------------------------------------------------
    xml里面的两个重要属性:
    targetNamespace,相当于java里的package
    xmlns命名空间,相当于java里面的import


    WSDL文档:
    1、web service接口
    <types>...</types>
    <message name="sayHi">...</message>
    <message name="sayHiResponse">...</message>
    <message name="getCatsByUser">...</message>
    <message name="getCatsByUserResponse">...</message>
    <portType name="HelloWorld">...</portType>
    types元素,该元素内容就是Schema文档
    2N个message元素(N为服务端下的方法数量)
    portType元素,包含N个operation子元素(每个operation定义一个WS操作——方法)


    (mainOccurs="0",表示出现0到1次,maxOccurs="unbounded",表示未定、无数次)


    2、web service实现
    binding元素,包含2N个operation元素
    service元素,包含port子元素——指定指定Web Service绑定的地址


    --------------------------------------------------------------------------


    2、SOAP  Simple Object Access Protocol简单对象访问协议
    3、UDDI


    ---------------------------------------------------------------------------
    <xs:complexType name="sayHi">
    <xs:sequence>
    <xs:element name="arg0" type="xs:string" minOccurs="0"/>
    </xs:sequence>
    </xs:complexType>
    <xs:complexType name="sayHiResponse">
    <xs:sequence>
    <xs:element name="return" type="xs:string" minOccurs="0"/>
    </xs:sequence>
    </xs:complexType>
    <xs:complexType name="getCatsByUser">
    <xs:sequence>
    <xs:element name="arg0" type="tns:user" minOccurs="0"/>
    </xs:sequence>
    </xs:complexType>
    <xs:complexType name="user">
    <xs:sequence>
    <xs:element name="address" type="xs:string" minOccurs="0"/>
    <xs:element name="id" type="xs:int" minOccurs="0"/>
    <xs:element name="name" type="xs:string" minOccurs="0"/>
    <xs:element name="pass" type="xs:string" minOccurs="0"/>
    </xs:sequence>
    </xs:complexType>
    <xs:complexType name="getCatsByUserResponse">
    <xs:sequence>
    <xs:element name="return" type="tns:cat" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
    </xs:complexType>
    <xs:complexType name="cat">
    <xs:sequence>
    <xs:element name="color" type="xs:string" minOccurs="0"/>
    <xs:element name="id" type="xs:int" minOccurs="0"/>
    <xs:element name="name" type="xs:string" minOccurs="0"/>
    </xs:sequence>
    </xs:complexType>
    ---------------------------------------------------------------------------------------
    一次Web Service调用——其实并不是方法调用,而是发送SOAP消息(即XML文档片段),CXF调用的本质:
    1、客户端把需要调用的参数,转换为xml文档片段(SOAP消息,input消息)
    ——该片段必须符合wsdl定义的格式
    2、客户端通过网络,把xml文档片段传给远程服务端
    3、服务器接收到xml文档片段
    4、服务端解析xml片段,提取其中数据,并把数据转换为调用web service所需要的参数或对象
    5、服务端执行方法
    6、服务端把执行方法得到的返回值又转换生成为xml文档片段(SOAP消息,output消息)
    7、服务端通过网络把xml片段传给客户端
    8、客户端接收到xml文档片段
    9、客户端解析xml片段,提取其中数据,并把数据转换为调用web service的返回值


    从上面的调用本质来看,要一个语言支持web service,唯一的要求是:
    该语言必须支持xml文档的解析、生成、支持网络传输。
    所以web service支持跨平台、跨语言(本质:以xml文档为基础的数据交换)
    所有的运行是在server端,client端只是发送、解析、封装、转换数据
    ---------------------------------------------------------------------------------------
    简单来讲,wsdl描述了web service包含了如下3个方面:
    ** WHAT:该web service包含什么操作
    ** HOW:该web service应该怎么调用
    ** WHERE:该web service的服务地址(调用地址)


    /******************************************************************************
    只要得到Web Service的wsdl文档,接下来程序就可以调用Web Service
    ******************************************************************************/


    CXF开发中,遇到系统无法自动处理的类型时,需要特殊处理:
    处理思路是要提供一个转换器,该转换器负责把CXF搞不定的类型转换为CXF搞的定的类型
    1、使用@XmlJavaTypeAdapter修饰无法处理的类型
    使用该Annotation时,value值指定一个转换器类
    该转换器就是完成类型之间的转换
    2、实现自己的转换器,实现转换器时需要开发一个CXF可以搞定的类型


    WebService的三个技术基础:
    1、WSDL
    Web Service接口:
    1、types(标准的Schema)
    2、2N的message
    3、portType:N个operation
    Web Service实现:
    1、binding元素:N个更详细的operation
    2、service:指定web service的服务地址
    2、SOAP
    根元素:Envolope:
    Header元素+Body元素
    默认情况下,Header元素不是强制出现的,可以在Header中放置用户名、密码等信息。
    如果使用正确的话,Body元素内容应该遵守WSDL所要求的格式,如果调用错误,Body元素内容就是Fault子元素。


    Web Service急需解决的问题?如何收钱?——如何进行权限控制
    解决思路:
    服务端要求客户端发来的input消息里面必须携带用户名、密码信息,如果没有或者不正确,则拒绝访问
    (如果不用CXF等框架,则SOAP消息的生成、解析等都要通过程序来控制,无论是添加用户名、密码或者提取用户名、密码等信息都可由程序代码来完成)
    如果使用CXF框架,则SOAP消息的生成、解析等都是通过CXF框架来完成。


    为了让程序猿能够访问并修改CXF框架所生成的xml(SOAP消息),CXF提供了拦截器。


    服务端添加拦截器:
    1、获取服务端Endpoint的publish的方法返回值
    2、调用该方法的getInInterceptors()、getOutInterceptors()方法来获取In、Out拦截器列表,接下来再添加拦截器即可



    客户端添加拦截器:
    1、调用ClientProxy的getClient(hw)方法,该方法以远程web service的代理为参数,返回值为Client对象
    2、调用client对象的client.getInInterceptors().add(e)、client.getOutInterceptors().add(e)方法添加拦截器


    HelloWorldWs factory = new HelloWorldWs();
    HelloWorld hw = factory.getHelloWorldWsPort();//此处返回的只是远程web service的代理
    Client client = ClientProxy.getClient(hw);
    client.getInInterceptors().add(e);
    client.getOutInterceptors().add(e);


    自定义拦截器:
    ->需要实现Interceptor接口,实际一般直接继承AbstractPhaseInterceptor抽象类


    public Class AuthInterceptor extends AbstractPhaseInterceptor<SoapMessage>{


    public AuthInterceptor(){
    //显示调用父类的有参构造器,一旦显示调用父类构造器之后,程序将不会隐世调用父类无参构造器
    super(Phase.PRE_INVOKE); //该拦截器将会在"调用之前"拦截SOAP消息
    }


    //需要实现handleMessage方法,其形参即为被拦截到的Soap消息msg
    //一旦程序获得了Soap消息,剩下的事情就可以解析Soap消息或者修改SOAP消息
    @Override
    public void handleMessage(SoapMessage msg) throws Fault{
    System.out.println(msg);
    }



    CXF与Spring整合方式一(暴露本地web service接口)
    在传统的javaEE的基础上,添加一层Web Service层。
    此时的JavaEE应用就可以向外暴露web service,这样就允许任何平台、任何语言来调用这个javaEE


    在传统SSH项目基础上添加web service步骤(注意要让struts2放行所有的web service请求):
    1、复制CXF的jar包,spring的jar包
    2、在Web.xml文件中配置CXF的核心控制器


    <!-- 下面的配置表明所有来自/webservice/*请求,都交给CXFServlet处理 -->
    <servlet>
    <servlet-name>cxf</servlet-name>
    <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
    </servlet>
    <servlet-mapping>
    <servlet-name>cxf</servlet-name>
    <url-pattern>/webservice/*</url-pattern>
    </servlet-mapping>
    3、在spring配置文件中,导入CXF提供Schema + xml配置文件


    xmlns:jaxws="http://cxf.apache.org/jaxws"


    xsi:schemaLocation="... http://cxf.apache.org/jaxws 
    http://cxf.apache.org/schemas/jaxws.xsd"


    ps:web应用的类加载路径有两类:
    1、WEB-INF/classes目录
    2、WEB-INF/lib目录


    <import resource="classpath:META-INF/cxf/cxf.xml" />
    <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
    <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />


    4、在spring配置文件中使用jaxws:endpoint元素来暴露web service

    <!-- implementor指定webservice的服务提供者,支持两种形式:
    A、直接给定服务提供者的类名即接口实现类
    B、设置为容器中的一个bean(依赖注入),要在bean的id前加一个#号
    -->


    A: 
    <bean id="userService" class="org.UserService"></bean>
    <jaxws:endpoint
    implementor="org.xxx.Class"
    address="/webservice">
    </jaxws:endpoint>


    B:
    <bean id="userService" class="org.UserService"></bean>
    <bean id="HelloWorldWs" class="org.java.HelloWorldWs" 
    p:us-ref="userService" />


    </bean>
    <jaxws:endpoint
    implementor="#HelloWorldWs"
    address="/webservice">
    </jaxws:endpoint>


    5、添加服务端拦截器
    在jaxws:endpoint里面添加jaxws:inInterceptors拦截器


    <jaxws:endpoint id="helloWorld"
    implementor="#HelloWorldWs"
    address="/webservice">


    <jaxws:inInterceptors>  
    <bean class="SomeInterceptors" />
    <ref bean="AnotherInterceptors" />
    </jaxws:inInterceptors>


    </jaxws:endpoint>


    CXF与spring整合方式二(调用远程web service)
    直接调用远程web service代理对象的方法进行操作
    1、让我们的action以来远程web service的接口
    2、复制CXF的jar包,spring的jar包,struts的jar包,以及整合包
    3、在spring配置文件中,导入CXF提供Schema + xml配置文件
    4、在spring配置文件中使用jaxws:client元素来配置远程web service代理
    5、添加客户端拦截器
    在jaxws:client里面添加jaxws:inInterceptors拦截器


    <jaxws:client id="xxx" serviceClass="xxx" address="xxx" >


    </jaxws-client>

  • 相关阅读:
    hihoCoder #1062 : 最近公共祖先·一
    hihoCoder #1050 : 树中的最长路
    hihoCoder #1049 : 后序遍历
    108 Convert Sorted Array to Binary Search Tree 将有序数组转换为二叉搜索树
    107 Binary Tree Level Order Traversal II 二叉树的层次遍历 II
    106 Construct Binary Tree from Inorder and Postorder Traversal 从中序与后序遍历序列构造二叉树
    105 Construct Binary Tree from Preorder and Inorder Traversal 从前序与中序遍历序列构造二叉树
    104 Maximum Depth of Binary Tree 二叉树的最大深度
    102 Binary Tree Level Order Traversal 二叉树的层次遍历
    101 Symmetric Tree 判断一颗二叉树是否是镜像二叉树
  • 原文地址:https://www.cnblogs.com/vipzhou/p/4776510.html
Copyright © 2020-2023  润新知