导读:
导读
本文是我对学习jwsdp-1.2时所做笔记的整理,其中主要是一些指导性的内容,并没有多少概念以及原理的介绍,读者可能觉得略显简单,如果想要学习基本概念可以参考网上有关Web Service的资料。本文例子所使用的开发环境是WindowXP+JWSDP-1.2。
一.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文件
<?xml version=”1.0” encoding=”UTF-8”?>
<configuration xmlns="”http://java.sun.com/xml/ns/jax-rpc/ri/config”"><br> <service>name=”HelloService” <br>targetNamespace=”urn:Star” <br>typeNamespace=”urn:Star” <br>packageName=”helloservice”> name=”HelloService” <br> targetNamespace=”urn:Star” <br> typeNamespace=”urn:Star” <br> packageName=”helloservice”> <br> <interface name="”helloservice.HelloIF”/"><br> </interface></service><br> </configuration>
该文件告诉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文件如下所述
<?xml version=”1.0” encoding=”UTF-8”?>
<webservices xmlns="”http://java.sun.com/xml/ns/jax-rpc/ri/dd”">version=”1.0” <br>targetNamespaceBase=”urn:Star” <br>typeNamespaceBase=”urn:Star” <br>urlPatternBase=”webservice”> version=”1.0” <br> targetNamespaceBase=”urn:Star” <br> typeNamespaceBase=”urn:Star” <br> urlPatternBase=”webservice”> <br> <endpoint name="”Hello”">displayName=”HelloWorld Service” <br>description=”A simple web service” <br>interface=”helloservice.HelloIF” <br>model=”/WEB-INF/model.gz” <br>implementation=”helloservice.HelloImpl”/> displayName=”HelloWorld Service” <br> description=”A simple web service” <br> interface=”helloservice.HelloIF” <br> model=”/WEB-INF/model.gz” <br> implementation=”helloservice.HelloImpl”/> <br> <endpointmapping endpointname="”Hello”" urlpattern="”/hello”/"><br> </endpointmapping></endpoint></webservices>
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:>上看是否配置成功 <br> ·如何使用JAX-RPC创建Web Service客户端 <br> 通常有三种类型的客户:Static Stub、Dynamic Proxy和Dynamic Invocation Interface(DII) <br> Static Stub客户 <br> ·生成Stub <br> 通过使用config-wsdl.xml和wscompile工具,可以生成stub <br> wscompile -gen:client -d build -classpath build config-wsdl.xml <br> config-wsdl.xml文件如下 <br> <?xml version="1.0" encoding="UTF-8"?><br> <configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config"><br> <wsdl location="http://localhost:8080/helloWS/hello?WSDL">packageName="staticstub"/> packageName="staticstub"/> <br> </wsdl></configuration><br> wscompile工具读取服务器上的WSDL文件并生成stub <br> ·编写静态客户代码 <br> Stub stub=(Stub)(new HelloService_Impl().getHelloIFPort()); <br> HelloIF hello=(HelloIF)stub; <br> Hello.sayHello(“starchu”); <br> 注意:HelloService_Impl类由wscompile生成 <br> ·编译代码 <br> ·运行客户端(需要包含saaj API和JAX-RPC API运行) <br> Dynamic Proxy客户 <br> ·生成接口 <br> 通过使用config-wsdl.xml文件和wscompile工具,可以生成客户所需的接口 <br> wscompile -import -d build -classpath build config-wsdl.xml <br> config-wsdl.xml和前面列出的文件内容相同。 <br> ·编写动态客户代码 <br> ServiceFactory factory=ServiceFactory.newInstance(); <br> URL wsdlUrl=new URL(“<your web service wsdl url>”); <br> Service service=factory.createService(wsdlUrl, <br> new QName(“urn:Star”,”HelloService”)); <br> HelloIF hello=(HelloIF)service.getPort( <br> new QName(“urn:Star”,”HelloIFPort”),HelloIF.class); <br> Hello.sayHello(“starchu”); <br> 注意:这里不再需要静态客户代码的HelloService_Impl类 <br> ·编译代码 <br> ·运行客户端(需要包含saaj API和JAX-RPC API运行) <br> Dynamic Invocation Interface客户 <br> 这个方法为我们提供了更有弹性的客户调用方式,客户代码不在需要由wscompile工具生成的运行时类,当然这种代码更加复杂。具体步骤如下: <br> ·创建ServiceFactory实例 <br> ServiceFactory factory=ServiceFactory.newInstance(); <br> ·创建Service(利用服务名的Qname) <br> Service service=factory.createService(new QName(“HelloService”)); <br> ·创建Call对象(使用端点接口的Qname) <br> Call call=service.createCall(new QName(“HelloIF”)); <br> ·设置端点的地址和一些Call对象属性 <br> call.setTargetEndpointAddress(args[0]); <br> call.setProperty(Call.SOAPACTION_USE_PROPERTY,new Boolean(true)); <br> call.setProperty(Call.SOAPACTION_URI_PROPERTY,””); <br> call.setProperty(“javax.xml.rpc.encodingstyle.namespace.uri”, <br> “http://schemas.xmlsoap.org/soap/encoding/”); <br> ·设置远程调用的返回类型、操作名和参数 <br> QName stringType=new Qname(“http://www.w3.org/2001/XMLSchema”,”string”) <br> call.setReturnType(stringType); <br> call.setOperationName(new Qname(“urn:Star”,”sayHello”)); <br> call.addParameter(“String_1”,stringType,ParameterMode.IN); <br> ·调用call的invoke方法 <br> String [] param={ “ starchu “ }; <br> String retValue=call.invoke(param); <br> ·编译代码并对Main方法设置<http:>) <br> 3.SOAP Message Handler的例子 <br> 通常使用JAX-RPC建立的Web Service并不需要开发人员自己处理SOAP消息,但是JAX-RPC提供了一种机制可以使程序员获得这种处理能力,这就是所谓的消息处理器。总的来说,像日志和加解密功能可以通过SOAP消息处理器实现,除此之外,你根本不需要处理SOAP消息。 <br> ·基本Handler处理过程 <br> SOAP请求 <br> ·客户端处理器在请求消息发送到服务器前被调用 <br> ·服务端处理器在请求消息分发到端点前被调用 <br> SOAP应答 <br> ·服务端处理器在应答消息发送回客户前被调用 <br> ·客户端处理器在应答消息转换成Java方法返回前被调用 <br> SOAP错误 <br> 处理过程与SOAP应答的方式一样 <br> 注意:处理器可以在任意端组成处理器链 <br> A.Handler基本编程模型 <br> 服务端 <br> ·编写服务端点接口代码、实现服务并且实现服务端处理器类 <br> ·创建jaxrpc-ri.xml文件,以便wscompile使用,其中包含了Handler的信息 <br> ·创建web.xml文件 <br> ·编译所有代码 <br> ·将文件打包为WAR文件 <br> ·用wsdeploy工具将原始war文件替换为完整可部署的war文件 <br> ·在服务器上部署war文件 <br> 客户端 <br> ·编写客户程序以及客户端处理器代码 <br> ·创建config.xml文件以便wscompile使用,它包含了客户端处理器的信息 <br> ·编译代码 <br> ·运行wscompile生成服务端点接口和客户类 <br> ·编译所有代码,并运行客户应用 <br> B.建立客户端处理器 <br> 处理器必须扩展javax.xml.rpc.handler.GenericHandler类并且提供至少两个方法的实现init和getHandlers。此外,你可以利用handleXXX方法处理请求、应答和错误SOAP消息。基本步骤如下 <br> ·编写客户端处理器代码 <br> Public class ClientHandler extends GenericHandler{ <br> Public void init(HandlerInfo info){ <br> This.info=info; <br> } <br> public QName[] getHeaders(){ <br> return info.getHeaders(); <br> } <br> public boolean handleRequest(MessageContext context){ <br> SOAPMessageContext smc=(SOAPMessageContext)context; <br> SOAPMessage message=smc.getMessage(); <br> file://You can use SOAP API to implement your own logic <br> file://such as logging and encrypt <br> …… <br> file://Set a logger element in the SOAPHeader <br> SOAPHeaderElement loggerElement= <br> header.addHeaderElement(envelope.createName(“loginfo”, <br> “ns1”,”urn:Star:headprops”)); <br> loggerElement.setMustUnderstand(true); <br> loggerElement.setValue(“10”); <br> file://Set a name element in the SOAP Header <br> SOAPHeaderElement nameElement= <br> Header.addHeaderElement(envelope.createName(“client”, <br> “ns1”,”urn:Star:headprops”)); <br> nameElement.addTextNode(“Star chu”); <br> } <br> } <br> ·编辑config.xml文件 <br> <?xml version=”1.0” encoding=”UTF-8”?><br> <configuration xmlns="”http://java.sun.com/xml/ns/jax-rpc/ri/config”?"><br> <wsdl location="”http://localhost:8080/handlerWS/handler?WSDL"> packageName=”client”> packageName=”client”> <br> <handlerchains><br> <chain runat="”client”"><br> <handler classname="”client.ClientHandler”"><br> <property name="”name”" value="”client" handler></property><br> </handler><br> </chain><br> </handlerchains></wsdl></configuration><br> ·编写静态客户 <br> C.建立服务端处理器 <br> ·编写服务端处理器(与客户端结构类似) <br> Public boolean handleRequest(MessageContext context){ <br> SOAPMessageContext smc=(SOAPMessageContext)context; <br> …… <br> Iterator it=header.examineAllHeaderElements(); <br> While(it.hasNext()){ <br> SOAPElement element=(SOAPElement)it.next(); <br> If(element name is loginfo and must understand it){ <br> element.getValue(); <br> element.detach(); <br> file://Invoke only when the setMustUnderstand(true) <br> } <br> } <br> } <br> detach方法用来移除元素,这个需求仅当一个元素设置了mustUnderstand属性在必要。 <br> ·编辑jaxrpc-ri.xml文件 <br> <?xml version=”1.0” encoding=”UTF-8”?><br> <webservices xmlns="”http://java.sun.com/jax-rpc/config/ri/dd”"> version=”1.0” <br>targetNamespaceBase=”urn:Star:wsdl” <br>typeNamespaceBase=”urn:Star:types” <br>urlPatternBase=”/handler”> version=”1.0” <br> targetNamespaceBase=”urn:Star:wsdl” <br> typeNamespaceBase=”urn:Star:types” <br> urlPatternBase=”/handler”> <br> <endpoint name="”HandlerTest”"> displayName=”Handler Test” <br>description=” … …” <br>interface=”service.HandlerTest” <br>model=”/WEB-INF/model.gz” <br>implementation=”service.HandlerTestImpl”> displayName=”Handler Test” <br> description=” … …” <br> interface=”service.HandlerTest” <br> model=”/WEB-INF/model.gz” <br> implementation=”service.HandlerTestImpl”> <br> <handlerchains><br> <chain runat="”server”"><br> <handler classname="”service.LoggerHandler”"> headers=”ns1:loginfo” <br>xmlns:ns1=”urn:Star:headerprops”> headers=”ns1:loginfo” <br> xmlns:ns1=”urn:Star:headerprops”> <br> <property name="”name”" value="”Logger”/"><br> </property></handler><br> <handler classname="”service.NameHandler”"><br> <propery name="”name”" value="”Name”/"><br> </propery></handler><br> </chain><br> </handlerchains><br> </endpoint><br> <endpointmapping endpointname="”HandlerTest”">urlPattern=”/handler”/> urlPattern=”/handler”/> <br> </endpointmapping></webservices><br> 在第一个处理器中,XML使用了属性 headers描述头信息。这是因为客户代码告诉服务端,logger头必须被理解,否则客户将收到SOAP错误消息 <br> ·生成WAR文件并部署到服务器上 <br> 4.源代码 <br> ·HelloIF.java(endpoint接口) <br> package helloservice; <br> import java.rmi.RemoteException; <br> import java.rmi.Remote; <br> public interface HelloIF extends Remote{ <br> public String sayHello(String target) throws RemoteException; <br> } <br> ·HelloImpl.java <br> package helloservice; <br> public class HelloImpl implements HelloIF{ <br> private String message="Hello"; <br> public String sayHello(String target){ <br> return message+target; <br> } <br> } <br> ·StaticClient.java <br> package staticstub; <br> import javax.xml.rpc.Stub; <br> public class StaticClient{ <br> private static String endpointAddress; <br> public static void main(String [] args){ <br> if(args.length!=1){ <br> System.err.println("Usage : java HelloClient [endpoint address]"); <br> System.exit(-1); <br> } <br> endpointAddress=args[0]; <br> System.out.println("Connect to :"+endpointAddress); <br> try{ <br> Stub stub=createStub(); <br> stub._setProperty(javax.xml.rpc.Stub.ENDPOINT_ADDRESS_PROPERTY, <br> endpointAddress); <br> HelloIF hello=(HelloIF)stub; <br> System.out.println(hello.sayHello(" Starchu!")); <br> }catch(Exception e){System.err.println(e.toString());} <br> } <br> private static Stub createStub(){ <br> return (Stub)(new HelloService_Impl().getHelloIFPort()); <br> } <br> } <br> ·DynamicClient.java <br> package dynamicproxy; <br> import java.net.URL; <br> import javax.xml.namespace.QName; <br> import javax.xml.rpc.Service; <br> import javax.xml.rpc.ServiceFactory; <br> import javax.xml.rpc.JAXRPCException; <br> import staticstub.HelloIF; <br> public class DynamicClient{ <br> private static String wsdl; <br> private static String namespaceUri="urn:Star:wsdl"; <br> private static String serviceName="HandlerService"; <br> private static String portName="HandlerTestPort"; <br> public static void main(String [] args){ <br> if(args.length!=1){ <br> System.err.println("Usage : java DynamicClient [server Url]"); <br> System.exit(-1); <br> } <br> System.out.println("Connect to :"+args[0]); <br> helloWsdl=args[0]+"?WSDL"; <br> try{ <br> URL wsdlUrl=new URL(wsdl); <br> ServiceFactory serviceFactory=ServiceFactory.newInstance(); <br> Service service= <br> serviceFactory.createService(wsdlUrl, <br> new QName(namespaceUri,serviceName)); <br> HandlerTest proxy=(HandlerTest)service.getPort( <br> new QName(namespaceUri,portName),HandlerTest.class); <br> proxy.test(); <br> }catch(Exception e){ <br> System.err.println(e.toString()); <br> } <br> } <br> } <br> ·DIIClient.java <br> package dii; <br> import javax.xml.rpc.*; <br> import javax.xml.namespace.*; <br> public class DIIClient{ <br> private static String qnameService = "HelloService"; <br> private static String qnamePort = "HelloIF"; <br> private static String BODY_NAMESPACE_VALUE ="urn:Star"; <br> private static String ENCODING_STYLE_PROPERTY ="javax.xml.rpc.encodingstyle.namespace.uri"; <br> private static String NS_XSD ="http://www.w3.org/2001/XMLSchema"; <br> private static String URI_ENCODING ="http://schemas.xmlsoap.org/soap/encoding/"; <br> public static void main(String [] args){ <br> try{ <br> <br> ServiceFactory factory=ServiceFactory.newInstance(); <br> Service service=factory.createService(new QName(qnameService)); <br> QName port=new QName(qnamePort); <br> Call call=service.createCall(port); <br> call.setTargetEndpointAddress(args[0]); <br> call.setProperty(Call.SOAPACTION_USE_PROPERTY,new Boolean(true)); <br> call.setProperty(Call.SOAPACTION_URI_PROPERTY,""); <br> call.setProperty(ENCODING_STYLE_PROPERTY,URI_ENCODING); <br> QName qnameTypeString=new QName(NS_XSD,"string"); <br> call.setReturnType(qnameTypeString); <br> call.setOperationName(new QName(BODY_NAMESPACE_VALUE,"sayHello")); <br> call.addParameter("String_1",qnameTypeString,ParameterMode.IN); <br> String [] params = { "Starchu" }; <br> System.out.println((String)call.invoke(params)); <br> }catch(Exception e){ <br> System.err.println(e.toString()); <br> } <br> } <br> } <br> ·Ant文件build.xml <br> <project name="helloWS" basedir="." default="deploy"><br> <property file="build.properties"></property><br> <property name="build" value="build"></property><br> <property name="dist" value="${build}\classes"></property><br> <property name="lib" value="${build}\lib"></property><br> <property name="src" value="src"></property><br> <property name="etc" value="${src}\etc"></property><br> <target name="clean"><br> <delete dir="${build}"></delete><br> </target><br> <target name="init"><br> <mkdir dir="${build}"></mkdir><br> <mkdir dir="${dist}"></mkdir><br> <mkdir dir="${lib}"></mkdir><br> </target><br> <path id="classpath"><br> <fileset dir="${tomcat.home}"><br> <include name="jaxrpc/**/*.jar"></include><br> <include name="jaxb/**/*.jar"></include><br> <include name="jaxp/**/*.jar"></include><br> <include name="saaj/**/*.jar"></include><br> <include name="jwsdp-shared/lib/**/*.jar"></include><br> </fileset><br> <pathelement path="${dist}"></pathelement><br> <pathelement location="${lib}"></pathelement><br> </path><br> <target name="compile-service" depends="init"><br> <javac srcdir="${src}" destdir="${dist}" includes="HelloService/**/*.java"></javac><br> </target><br> <target name="generate-sei-service" depends="compile-service"><br> <exec executable="wscompile.bat"><br> <arg line="-define -d ${build} -nd ${build} -classpath ${dist} ${etc}\config-interface.xml -model ${build}\model.gz"></arg><br> </exec><br> <copy todir="${build}"><br> <fileset dir="${etc}" includes="*.xml"></fileset><br> </copy><br> </target><br> <target name="package-service" depends="generate-sei-service"><br> <war warfile="${build}\${ant.project.name}-portable.war"> webxml="${build}\web.xml"> webxml="${build}\web.xml"> <br> <webinf dir="${build}" includes="*.xml,*.gz,*.wsdl" excludes="web.xml"></webinf><br> <classes dir="${dist}" includes="**/*.class" defaultexcludes="no"></classes><br> </war><br> </target><br> <target name="process-war" depends="package-service"><br> <exec executable="wsdeploy.bat"><br> <arg line="-o ${ant.project.name}.war ${build}\${ant.project.name}-portable.war"></arg><br> </exec><br> </target><br> <target name="deploy"><br> <copy file="${ant.project.name}.war" todir="${server}"></copy><br> </target><br> <br> <target name="undeploy"><br> <delete file="${server}\${ant.project.name}.war"></delete><br> </target><br> <!-- Generating Static Client --> <br> <target name="generate-stubs" depends="init"><br> <exec executable="wscompile.bat"><br> <arg line="-gen:client -d ${dist} -classpath ${dist} ${etc}\config-wsdl.xml"></arg><br> </exec><br> </target><br> <target name="compile-client" depends="generate-stubs"><br> <javac srcdir="${src}" destdir="${dist}" includes="StaticStub/**/*.java"><br> <classpath refid="classpath"></classpath><br> </javac><br> </target><br> <br> <target name="package-client" depends="compile-client"><br> <jar destfile="${lib}\client.jar" basedir="${dist}" excludes="HelloService/**/*.class"></jar><br> </target><br> <target name="run-client" depends="package-client"><br> <java classname="staticstub.HelloClient"> classpathref="classpath" <br>fork="true"> classpathref="classpath" <br> fork="true"> <br> <sysproperty key="endpoint" value="${endpoint}"></sysproperty><br> <arg value="${server.port.url}"></arg><br> </java><br> </target><br> <!-- Generating Dynamic Client --> <br> <target name="generate-interface" depends="init"><br> <exec executable="wscompile.bat"><br> <arg line="-import -d ${dist} -classpath ${dist} ${etc}\config-wsdl.xml"></arg><br> </exec><br> </target><br> <target name="compile-dynamic-client" depends="generate-interface"><br> <javac srcdir="${src}" destdir="${dist}" includes="DynamicProxy/**/*.java"><br> <classpath refid="classpath"></classpath><br> </javac><br> </target><br> <br> <target name="package-dynamic-client" depends="compile-dynamic-client"><br> <jar destfile="${lib}\client.jar" basedir="${dist}" includes="**/HelloIF.class,**/DynamicClient.class"></jar><br> </target><br> <target name="run-dynamic-client" depends="package-dynamic-client"><br> <java classname="dynamicproxy.DynamicClient"> classpathref="classpath" <br>fork="true"> classpathref="classpath" <br> fork="true"> <br> <sysproperty key="endpoint" value="${endpoint}"></sysproperty><br> <arg value="${server.port.url}"></arg><br> </java><br> </target><br> <!-- Generating Dynamic Invocation Interface --> <br> <target name="compile-dii"><br> <javac srcdir="${src}" destdir="${dist}" includes="DII/**/*.java"><br> <classpath refid="classpath"></classpath><br> </javac><br> </target><br> <target name="run-dii" depends="compile-dii"><br> <java classname="dii.DIIClient"> classpathref="classpath" <br>fork="true"> classpathref="classpath" <br> fork="true"> <br> <sysproperty key="endpoint" value="${endpoint}"></sysproperty><br> <arg value="${server.port.url}"></arg><br> </java><br> </target><br> </project><br> ·属性文件(build.xml文件使用) <br> server=C:/Java/jwsdp-1.2/webapps <br> tomcat.home=C:/Java/jwsdp-1.2 <br> endpoint=http://localhost:8080/helloWS/hello <br> server.port.url=http://localhost:8080/helloWS/hello <br> 参考资料 <br> 1. Developing Web Service Series <http:> www.theserverside.com <br> 2. JWSDP-1.2 Tutorial java.sun.com <br> <br> 导读本文是我对学习jwsdp-1.2时所做笔记的整理,其中主要是一些指导性的内容,并没有多少概念以及原理的介绍,读者可能觉得略显简单,如果想要学习基本概念可以参考网上有关Web Service的资料。本文例子所使用的开发环境是WindowXP+JWSDP-1.2。一.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 Service1.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文件<?xml version=”1.0” encoding=”UTF-8”?>该文件告诉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文件如下所述<?xml version=”1.0” encoding=”UTF-8”?> 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目录下,然后可以在上看是否配置成功·如何使用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文件如下 <?xml version="1.0" encoding="UTF-8"?> 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(“<your web service wsdl 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:>)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文件 <?xml version=”1.0” encoding=”UTF-8”?> ·编写静态客户 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文件 <?xml version=”1.0” encoding=”UTF-8”?>在第一个处理器中,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 <!-- Generating Static Client --> <!-- Generating Dynamic Client --> <!-- Generating Dynamic Invocation Interface --> ·属性文件(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.com2. JWSDP-1.2 Tutorial java.sun.com <br><br>本文转自 <br><a href="http://www.cn-java.com/www1/?action-viewnews-itemid-2727">http://www.cn-java.com/www1/?action-viewnews-itemid-2727</a></http:></http:></your></http:></http:></your></http:>