• 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>

  • 相关阅读:
    BZOJ4346 : [POI2016]Nadajniki
    BZOJ4345 : [POI2016]Korale
    BZOJ4134 : ljw和lzr的hack比赛
    BZOJ4342 : CF348 Pilgrims
    BZOJ2310 : ParkII
    BZOJ3322 : [Scoi2013]摩托车交易
    BZOJ1444 : [Jsoi2009]有趣的游戏
    Xcode8中处理打印日志的配置
    iOS开发之记录用户登录状态
    热修复
  • 原文地址:https://www.cnblogs.com/vipzhou/p/4776510.html
Copyright © 2020-2023  润新知