免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1642 | 回复: 0
打印 上一主题 下一主题

Java Web Service之客户端实现 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-09-01 17:56 |只看该作者 |倒序浏览
Java Web Service的客户端实现有三种
1. 生成的stub
2. 动态代理
3. 动态调用接口
其中生成stub是最常用的。stub是用JAX-RPC编译器根据WSDL文档生成的,其主要功能是将对endpoint接口的方法调用转化为SOAP 消息,并且负责将返回的SOAP响应转换为方法的返回值,把SOAP fault转化为方法的异常。JAX-RPC编译器产生的stub除了要实现endpoint接口外,还需要实现或继承 javax.xml.rpc.Stub接口或其实现的子类(Axis中是org.apache.axis.client.Stub)。 javax.xml.rpc.Stub接口主要定义了和网络通讯和认证相关的属性的设置和获取的机制。
Java Web Service的客户端实现有三种
1. 生成的stub
2. 动态代理
3. 动态调用接口
其中生成stub是最常用的。stub是用JAX-RPC编译器根据WSDL文档生成的,其主要功能是将对endpoint接口的方法调用转化为SOAP 消息,并且负责将返回的SOAP响应转换为方法的返回值,把SOAP fault转化为方法的异常。JAX-RPC编译器产生的stub除了要实现endpoint接口外,还需要实现或继承 javax.xml.rpc.Stub接口或其实现的子类(Axis中是org.apache.axis.client.Stub)。 javax.xml.rpc.Stub接口主要定义了和网络通讯和认证相关的属性的设置和获取的机制。其代码如下:
package javax.xml.rpc;
import java.util.Iterator;
public interface Stub {
    // Standard property: The Web service's Internet address.
    public static String ENDPOINT_ADDRESS_PROPERTY;
    // Standard property: Password for authentication.
    public static String PASSWORD_PROPERTY;
    // Standard property: User name for authentication.
    public static String USERNAME_PROPERTY;
    // Standard property: Boolean flag for maintaining an HTTP session.
    public static String SESSION_MAINTAIN_PROPERTY;
    // Given a property name, get its value.
    public Object _getProperty(java.lang.String name);
    // Get the names of all the properties the stub supports.
    public Iterator _getPropertyNames();
    // Configure a property on the stub.
    public void _setProperty(java.lang.String name, java.lang.Object value);
}

JAX-RPC编译器产生还可以产生一个和WSDL中service元素对应的Service接口,该接口组合了多个port,也就是多个Stub。该接口继承了javax.xml.rpc.Service。在J2EE环境中Service接口通常通过JNDI lookup得到。
在J2EE中使用生成的stub的典型用例如下:
代码:
package com.jwsbook.jaxrpc;
import javax.servlet.http.*;
import javax.servlet.*;
import javax.naming.InitialContext;
public class BookQuoteServlet_1 extends javax.servlet.http.HttpServlet {
  protected void doGet(HttpServletRequest req, HttpServletResponse resp)
  throws ServletException,java.io.IOException {
    try{
      String isbn = req.getParameter("isbn");
      InitialContext jndiContext = new InitialContext();
      BookQuoteService service = (BookQuoteService)
      jndiContext.lookup("java:comp/env/service/BookQuoteService");
      BookQuote bookQuote = service.getBookQuotePort();
      float price = bookQuote.getBookPrice( isbn );
      java.io.Writer outStream = resp.getWriter();
      outStream.write("The wholesale price for ISBN:"+isbn+
                    " = "+price+"");
    }catch(javax.naming.NamingException ne){
      throw new ServletException(ne);
    }catch(javax.xml.rpc.ServiceException se){
      throw new ServletException(se);
    }
  }
部署说明文件:

    service/BookQuoteService
    com.jwsbook.jaxrpc.BookQuoteService
    wsdl-file>BookQuote.wsdlwsdl-file>
    mh:BookQuoteService

一般都是通过JNDI查询到相应的Service接口,然后从Service接口中得到stub,最后调用web service的方法。部署文件中申明了名为"service/BookQuoteService"的Service接口,在代码里获取该接口的代码是 jndiContext.lookup("java:comp/env/service/BookQuoteService"),前缀"java: comp/env/"是所有J2EE资源在JNDI树种的parent Context。
在非J2EE环境中实现web service客户端
在非J2EE环境中也可以实现web service客户端,这时需要用到javax.xml.rpc.ServiceFactory(或其子类,在axis中是 org.apache.axis.client.ServiceFactory)的静态方法loadService得到service接口。接下来的调用代码和J2EE中的类似。
动态代理调用
动态代理调用是Java web service的另一种方式。对于使用该方式的客户端代码,和生成stub的方式相比较,其变化不是很大。它和生成stub的方式主要区别在于前者在编译时刻产生service接口和stub,后者则将这部分工作延迟到运行时刻。
动态代理调用的典型代码和部署说明文件:
package com.jwsbook.jaxrpc;
import javax.naming.InitialContext;
public class JaxRpcExample_2 {
  public static void main(String [] args) throws Exception{
    String isbn = args[0];
    InitialContext jndiContext = new InitialContext();
    javax.xml.rpc.Service service = (javax.xml.rpc.Service)
    jndiContext.lookup("java:comp/env/service/Service");
    BookQuote BookQuote_proxy = (BookQuote)
                                service.getPort(BookQuote.class);
    float price = BookQuote_proxy.getBookPrice( isbn );
    System.out.println("The price is = "+price);
  }
}


    service/Service
    javax.xml.rpc.Service
    wsdl-file>BookQuote.wsdlwsdl-file>
    mh:BookQuoteService

由于不需要在编译时刻产生service接口和stub,用JNDI lookup和部署说明时只使用了javax.xml.rpc.Service。得到service接口后通过getPort方法可以取得动态代理的 stub。getPort有两种版本,getPort(java.lang.Class endpointInterface)和getPort(javax.xml.namespace.QName portName,java.lang.Class endpointInterface),通常当WSDL中一个PortType有一种以上的绑定时,如果需要得到某个绑定的port接口就使用后者,否者使用前者。QName是该绑定的完全限定名称,有命名空间加上局部名构成。对应的QName对象的构造方法有构造函数法和静态valueOf法,实例如下:
// Use constructor method
QName portName =
          new QName("http://www.Monson-Haefel/jwsbook/BookQuote",
          "BookQuoteLiteralPort");
         
// Use static valueOf() method
String s = "{http://www.Monson-Haefel/jwsbook/BookQuote}BookQuoteLiteralPort";
QName qname2 = QName.valueOf(s);

valueOf方法接受的String参数以"{namespace}localName"的模式构成。
PortType有一种以上的绑定时还需要在JAX-RPC Mapping 文件中说明不指定QName版本的getPort方法对应的port绑定。示例:

java-wsdl-mapping
  xmlns="http://java.sun.com/xml/ns/j2ee"
  xmlns:mh="http://www.Monson-Haefel.com/jwsbook/BookQuote"...>
  ...
  
    com.jwsbook.jaxrpc.BookQuote
   
    wsdl-port-type>mh:BookQuotewsdl-port-type>
    wsdl-binding>mh:BookQuote_LiteralBindingwsdl-binding>
    ...
  
java-wsdl-mapping>

使用QName的动态代理调用实例:
package com.jwsbook.jaxrpc;
import javax.naming.InitialContext;
import javax.xml.namespace.QName;
public class JaxRpcExample_3 {
  public static void main(String [] args) throws Exception{
    String isbn = args[0];
    InitialContext jndiContext = new InitialContext();
    javax.xml.rpc.Service service = (javax.xml.rpc.Service)
    jndiContext.lookup("java:comp/env/service/Service");
    QName portName =
          new QName("http://www.Monson-Haefel/jwsbook/BookQuote",
          "BookQuoteLiteralPort");
    BookQuote BookQuote_proxy = (BookQuote)
                               service.getPort(portName, BookQuote.class);
    float price = BookQuote_proxy.getBookPrice( isbn );
    System.out.println("The price is = "+price);
  }
}

动态代理的底层实现是用java的反射机制和java.lang.reflect.Proxy完成的。
动态调用接口(DII)
动态调用接口的通常使用顺序:
1. 获得一个通用的service接口,比如通过JNDI lookup
2. 构造代表WSDL中port和operation的QName对象,作为service接口的createCall方法的参数,得到Call对象。
3. 准备operation所需的参数,如果是原子类型则需要将其包装成相应的对象类型。视operation是否有返回值调用invoke或invokeOneWay方法。
4. 如果operation定义了INOUT,OUT参数,则在invoke后调用getOutputValues,比如:java.util.List outputParams = call.getOutputValues();
完整的代码示例:
package com.jwsbook.jaxrpc;
import javax.naming.InitialContext;
import javax.xml.rpc.Service;
import javax.xml.rpc.Call;
import javax.xml.namespace.QName;
public class JaxRpcExample_4 {
  public static void main(String [] args) throws Exception{
    String isbn = args[0];
    InitialContext jndiContext = new InitialContext();
    javax.xml.rpc.Service service = (javax.xml.rpc.Service)
    jndiContext.lookup("java:comp/env/service/Service");
    QName portName =
     new QName("http://www.Monson-Haefel.com/jwsbook/BookQuote",
               "BookQuotePort");
    QName operationName =
     new QName("http://www.Monson-Haefel.com/jwsbook/BookQuote",
               "getBookPrice");
    Call call = service.createCall(portName,operationName);
    Object [] inputParams = new Object[]{isbn};
    Float price = (Float)call.invoke(inputParams);
    System.out.println("The price is = "+price.floatValue());
}
}



本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u1/52454/showart_1161478.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP