Web Service学习笔记之----JAX-RPC

一.Web  Service简介
1.定义
由两部分组成
·SOAP--Web  Service之间的基本通信协议。
·WSDL--Web  Service描述语言,它定义了Web  Service做什么,怎么做和查询的信息。
2.简单的Web  Service实现
包含四个基本步骤
·创建Web  Service的商业逻辑(通常是一些Java类)
·将这些Java类部署到一个SOAP服务器上
·生成客户访问代码
·部署客户应用
注意:WSDL等文件的生成通常是利用厂商提供的工具来完成
3.WSDL解析
WSDL描述语言一般包含三部分
·What部分--包括了type、message和portType元素
Type:定义了Web  Service使用的数据结构(使用XML  Schema定义)
Message:一个Message是SOAP的基本通信元素。每个Message可以有一个或多个Part,每个Part代表一个参数。
PortType:消息汇总为不同的操作并归入到一个被称为portType的实体中。一个portType代表一个接口(Web  Service支  持的操作集合),每个Web  Service可以有多个接口,它们都使用portType表示。每个操作又包含了input和  output部分。
·How部分--包含binding元素
binding元素将portType绑定到特定的通信协议上(如HTTP上的SOAP协议)
·Where部分--由service元素组成
它将portType,binding以及Web  Service实际的位置(URI)放在一起描述
4.客户端
通常Web  Service可以有三种类型的客户
·商业伙伴(Business  Partner)--包括分发商,零售商以及大型消费者)
此类客户通过SOAP、WSDL、ebXML、UDDI等XML技术与Web  Service连接
·瘦客户--包括Web浏览器、PDA以及无线设备
该类客户通常经由轻量协议(如HTTP)与Web  Service连接
·肥客户--包括Applet、各类应用以及现存系统
通常使用重量级协议(如IIOP)连接Web  Service

二.使用JAX-RPC开发Web  Service
1.JAX-RPC支持的数据类型
JAX-RPC除了支持Java的基本数据类型外还支持一些自定义对象,但这些对象有一些条件限制
·有缺省构造函数的对象
·没有实现java.rmi.Remote接口
·字段必须是JAX-RPC支持的类型
·公有字段不能声明为final或transient
·非公有字段必须有对应的setter和getter方法
2.使用JAX-RPC创建Web  Service
·基本步骤
A.  编写服务端接口并实现
一个服务的end-point有一些规定:必须实现java.rmi.Remot接口而且每个方法需要抛出RemoteException异常。
B.  编译、生成并且将所有服务需要的类和文件打包成WAR文件
C.  部署包含服务的WAR文件
·如何创建服务
A.  编译服务所需的类文件
B.  生成服务所需文件
可以使用wscompile工具生成model.gz文件,它包含了描述服务的内部数据结构命令如下
wscompile  -define  -d  build  -nd  build  -classpath  build  config.xml  
-model  build/model.gz
define标志告诉工具读取服务的  endpoint接口并且创建WSDL文件。-d和-nd标志告诉工具将输出文件写入指定的目录build。工具需要读以下的config.xml文件

http://java.sun.com/xml/ns/jax-rpc/ri/config”>
name=”HelloService”
targetNamespace=”urn:Star”
typeNamespace=”urn:Star”
packageName=”helloservice”>



该文件告诉wscompile创建model文件所需的信息
·服务名称:MyHelloService
·WSDL名字空间:urn:Star
·HelloService的所有类在包helloservice中
·服务的端点(endpoint)接口:helloservice.HelloIF
C.  将服务打包为WAR文件
WEB-INF/classes/hello/HelloIF.class
WEB-INF/classes/hello/HelloImpl.class
WEB-INF/jaxrpc-ri.xml
WEB-INF/model.gz
WEB-INF/web.xml
jaxrpc-ri.xml文件如下所述

http://java.sun.com/xml/ns/jax-rpc/ri/dd”
version=”1.0”
targetNamespaceBase=”urn:Star”
typeNamespaceBase=”urn:Star”
urlPatternBase=”webservice”>
displayName=”HelloWorld  Service”
description=”A  simple  web  service”
interface=”helloservice.HelloIF”
model=”/WEB-INF/model.gz”
implementation=”helloservice.HelloImpl”/>


D.  处理WAR文件
使用命令行
wsdeploy  -o  hello-jaxrpc.war  hello-jaxrpc-original.war
wsdeploy工具完成以下几个任务
·读  hello-jaxrpc-original.war作为输入
·从jaxrpc-ri.xml文件中获得信息
·为服务生成tie  classes
·生成名为HelloService.wsdl的WSDL文件
·将tie  classes和HelloService.wsdl文件打包到新的war文件中
E.  在服务器上部署服务
如果你使用的是TOMCAT,你可以将WAR文件拷贝到webapps目录下,然后可以在
<
http://localhost:8080/ [context]/[servicename>上看是否配置成功
·如何使用JAX-RPC创建Web  Service客户端
通常有三种类型的客户:Static  Stub、Dynamic  Proxy和Dynamic  Invocation  Interface(DII)
Static  Stub客户
·生成Stub
通过使用config-wsdl.xml和wscompile工具,可以生成stub
wscompile  -gen:client  -d  build  -classpath  build  config-wsdl.xml
config-wsdl.xml文件如下

packageName="staticstub"/>

wscompile工具读取服务器上的WSDL文件并生成stub
·编写静态客户代码
Stub  stub=(Stub)(new  HelloService_Impl().getHelloIFPort());
HelloIF  hello=(HelloIF)stub;
Hello.sayHello(“starchu”);
注意:HelloService_Impl类由wscompile生成
·编译代码
·运行客户端(需要包含saaj  API和JAX-RPC  API运行)
Dynamic  Proxy客户
·生成接口
通过使用config-wsdl.xml文件和wscompile工具,可以生成客户所需的接口
wscompile  -import  -d  build  -classpath  build  config-wsdl.xml
config-wsdl.xml和前面列出的文件内容相同。
·编写动态客户代码
ServiceFactory  factory=ServiceFactory.newInstance();
URL  wsdlUrl=new  URL(“”);
Service  service=factory.createService(wsdlUrl,
new  QName(“urn:Star”,”HelloService”));
HelloIF  hello=(HelloIF)service.getPort(
new  QName(“urn:Star”,”HelloIFPort”),HelloIF.class);
Hello.sayHello(“starchu”);
注意:这里不再需要静态客户代码的HelloService_Impl类
·编译代码
·运行客户端(需要包含saaj  API和JAX-RPC  API运行)
Dynamic  Invocation  Interface客户
这个方法为我们提供了更有弹性的客户调用方式,客户代码不在需要由wscompile工具生成的运行时类,当然这种代码更加复杂。具体步骤如下:
·创建ServiceFactory实例
ServiceFactory  factory=ServiceFactory.newInstance();

·创建Service(利用服务名的Qname)
Service  service=factory.createService(new  QName(“HelloService”));

·创建Call对象(使用端点接口的Qname)
Call  call=service.createCall(new  QName(“HelloIF”));

·设置端点的地址和一些Call对象属性
call.setTargetEndpointAddress(args[0]);
call.setProperty(Call.SOAPACTION_USE_PROPERTY,new  Boolean(true));
call.setProperty(Call.SOAPACTION_URI_PROPERTY,””);
call.setProperty(“javax.xml.rpc.encodingstyle.namespace.uri”,
http://schemas.xmlsoap.org/soap/encoding/” );

·设置远程调用的返回类型、操作名和参数
QName  stringType=new  Qname(“
http://www.w3.org/2001/XMLSchema”,”string” )
call.setReturnType(stringType);
call.setOperationName(new  Qname(“urn:Star”,”sayHello”));
call.addParameter(“String_1”,stringType,ParameterMode.IN);

·调用call的invoke方法
String  []  param={  “  starchu  “  };
String  retValue=call.invoke(param);

·编译代码并对Main方法设置<
http://localhost:8080/helloWS/hello参数 (服务器需有效>)

3.SOAP  Message  Handler的例子
通常使用JAX-RPC建立的Web  Service并不需要开发人员自己处理SOAP消息,但是JAX-RPC提供了一种机制可以使程序员获得这种处理能力,这就是所谓的消息处理器。总的来说,像日志和加解密功能可以通过SOAP消息处理器实现,除此之外,你根本不需要处理SOAP消息。
·基本Handler处理过程
SOAP请求
·客户端处理器在请求消息发送到服务器前被调用
·服务端处理器在请求消息分发到端点前被调用
SOAP应答
·服务端处理器在应答消息发送回客户前被调用
·客户端处理器在应答消息转换成Java方法返回前被调用
SOAP错误
处理过程与SOAP应答的方式一样
注意:处理器可以在任意端组成处理器链
A.Handler基本编程模型
服务端
·编写服务端点接口代码、实现服务并且实现服务端处理器类
·创建jaxrpc-ri.xml文件,以便wscompile使用,其中包含了Handler的信息
·创建web.xml文件
·编译所有代码
·将文件打包为WAR文件
·用wsdeploy工具将原始war文件替换为完整可部署的war文件
·在服务器上部署war文件
客户端
·编写客户程序以及客户端处理器代码
·创建config.xml文件以便wscompile使用,它包含了客户端处理器的信息
·编译代码
·运行wscompile生成服务端点接口和客户类
·编译所有代码,并运行客户应用

B.建立客户端处理器
处理器必须扩展javax.xml.rpc.handler.GenericHandler类并且提供至少两个方法的实现init和getHandlers。此外,你可以利用handleXXX方法处理请求、应答和错误SOAP消息。基本步骤如下
·编写客户端处理器代码
Public  class  ClientHandler  extends  GenericHandler{
Public  void  init(HandlerInfo  info){
This.info=info;
}
public  QName[]  getHeaders(){
return  info.getHeaders();
}
public  boolean  handleRequest(MessageContext  context){
SOAPMessageContext  smc=(SOAPMessageContext)context;
SOAPMessage  message=smc.getMessage();
file://You  can  use  SOAP  API  to  implement  your  own  logic
file://such  as  logging  and  encrypt
……
file://Set  a  logger  element  in  the  SOAPHeader
SOAPHeaderElement  loggerElement=
header.addHeaderElement(envelope.createName(“loginfo”,
“ns1”,”urn:Star:headprops”));
loggerElement.setMustUnderstand(true);
loggerElement.setValue(“10”);
file://Set  a  name  element  in  the  SOAP  Header
SOAPHeaderElement  nameElement=
Header.addHeaderElement(envelope.createName(“client”,
“ns1”,”urn:Star:headprops”));
nameElement.addTextNode(“Star  chu”);
}
}
·编辑config.xml文件

http://java.sun.com/xml/ns/jax-rpc/ri/config”?>
http://localhost:8080/handlerWS/handler?WSDL
packageName=”client”>







·编写静态客户
C.建立服务端处理器
·编写服务端处理器(与客户端结构类似)
Public  boolean  handleRequest(MessageContext  context){
SOAPMessageContext  smc=(SOAPMessageContext)context;
……
Iterator  it=header.examineAllHeaderElements();
While(it.hasNext()){
SOAPElement  element=(SOAPElement)it.next();
If(element  name  is  loginfo  and  must  understand  it){
element.getValue();
element.detach();
file://Invoke  only  when  the  setMustUnderstand(true)
}
}
}
detach方法用来移除元素,这个需求仅当一个元素设置了mustUnderstand属性在必要。
·编辑jaxrpc-ri.xml文件

http://java.sun.com/jax-rpc/config/ri/dd”
version=”1.0”
targetNamespaceBase=”urn:Star:wsdl”
typeNamespaceBase=”urn:Star:types”
urlPatternBase=”/handler”>
displayName=”Handler  Test”
description=”  …  …”
interface=”service.HandlerTest”
model=”/WEB-INF/model.gz”
implementation=”service.HandlerTestImpl”>


headers=”ns1:loginfo”
xmlns:ns1=”urn:Star:headerprops”>








urlPattern=”/handler”/>

在第一个处理器中,XML使用了属性  headers描述头信息。这是因为客户代码告诉服务端,logger头必须被理解,否则客户将收到SOAP错误消息
·生成WAR文件并部署到服务器上
4.源代码
·HelloIF.java(endpoint接口)
package  helloservice;

import  java.rmi.RemoteException;
import  java.rmi.Remote;

public  interface  HelloIF  extends  Remote{
public  String  sayHello(String  target)  throws  RemoteException;
}
·HelloImpl.java
package  helloservice;

public  class  HelloImpl  implements  HelloIF{
private  String  message="Hello";
public  String  sayHello(String  target){
return  message+target;
}
}
·StaticClient.java
package  staticstub;
import  javax.xml.rpc.Stub;
public  class  StaticClient{
private  static  String  endpointAddress;
public  static  void  main(String  []  args){
if(args.length!=1){
System.err.println("Usage  :  java  HelloClient  [endpoint  address]");
System.exit(-1);
}  
endpointAddress=args[0];
System.out.println("Connect  to  :"+endpointAddress);
try{
Stub  stub=createStub();
stub._setProperty(javax.xml.rpc.Stub.ENDPOINT_ADDRESS_PROPERTY,
endpointAddress);
HelloIF  hello=(HelloIF)stub;
System.out.println(hello.sayHello("  Starchu!"));  
}catch(Exception  e){System.err.println(e.toString());}
}
private  static  Stub  createStub(){
return  (Stub)(new  HelloService_Impl().getHelloIFPort());
}
}
·DynamicClient.java
package  dynamicproxy;
import  java.net.URL;
import  javax.xml.namespace.QName;
import  javax.xml.rpc.Service;
import  javax.xml.rpc.ServiceFactory;
import  javax.xml.rpc.JAXRPCException;
import  staticstub.HelloIF;

public  class  DynamicClient{
private  static  String  wsdl;  
private  static  String  namespaceUri="urn:Star:wsdl";  
private  static  String  serviceName="HandlerService";  
private  static  String  portName="HandlerTestPort";  

public  static  void  main(String  []  args){
if(args.length!=1){
System.err.println("Usage  :  java  DynamicClient  [server  Url]");
System.exit(-1);
}
System.out.println("Connect  to  :"+args[0]);
helloWsdl=args[0]+"?WSDL";
try{
URL  wsdlUrl=new  URL(wsdl);
ServiceFactory  serviceFactory=ServiceFactory.newInstance();
Service  service=
serviceFactory.createService(wsdlUrl,
new  QName(namespaceUri,serviceName));
HandlerTest  proxy=(HandlerTest)service.getPort(
new  QName(namespaceUri,portName),HandlerTest.class);
proxy.test();
}catch(Exception  e){
System.err.println(e.toString());
}
}
}
·DIIClient.java
package  dii;
import  javax.xml.rpc.*;
import  javax.xml.namespace.*;

public  class  DIIClient{
private  static  String  qnameService  =  "HelloService";
private  static  String  qnamePort  =  "HelloIF";
private  static  String  BODY_NAMESPACE_VALUE  ="urn:Star";
private  static  String  ENCODING_STYLE_PROPERTY  ="javax.xml.rpc.encodingstyle.namespace.uri";
private  static  String  NS_XSD  ="http://www.w3.org/2001/XMLSchema";
private  static  String  URI_ENCODING  ="http://schemas.xmlsoap.org/soap/encoding/";

public  static  void  main(String  []  args){
try{

ServiceFactory  factory=ServiceFactory.newInstance();
Service  service=factory.createService(new  QName(qnameService));
QName  port=new  QName(qnamePort);
Call  call=service.createCall(port);
call.setTargetEndpointAddress(args[0]);
call.setProperty(Call.SOAPACTION_USE_PROPERTY,new  Boolean(true));
call.setProperty(Call.SOAPACTION_URI_PROPERTY,"");
call.setProperty(ENCODING_STYLE_PROPERTY,URI_ENCODING);
QName  qnameTypeString=new  QName(NS_XSD,"string");
call.setReturnType(qnameTypeString);
call.setOperationName(new  QName(BODY_NAMESPACE_VALUE,"sayHello"));
call.addParameter("String_1",qnameTypeString,ParameterMode.IN);
String  []  params  =  {  "Starchu"  };
System.out.println((String)call.invoke(params));  
}catch(Exception  e){
System.err.println(e.toString());
}
}
}
·Ant文件build.xml





































webxml="${build}web.xml">
































  
classpathref="classpath"
fork="true">



















classpathref="classpath"
fork="true">













classpathref="classpath"
fork="true">






·属性文件(build.xml文件使用)
server=C:/Java/jwsdp-1.2/webapps
tomcat.home=C:/Java/jwsdp-1.2
endpoint=http://localhost:8080/helloWS/hello
server.port.url=http://localhost:8080/helloWS/hello

参考资料
1.  Developing  Web  Service  Series  <
http://www.theserverside.com/resources/article.jsp?l=Systinet-web-services-part-1 >   www.theserverside.com
2.  JWSDP-1.2  Tutorial  java.sun.com

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值