加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

Axis 开发webservice

发布时间:2020-12-17 01:03:38 所属栏目:安全 来源:网络整理
导读:? Apache Axis用户指南(3) 本部分是 apache axis 用户指南的第三部分。在 Axis 中使用 WSDL 文件。 10. 使用 WSDL Web Service Description Language 是由 IBM 和 Microsoft 完成的规范,并且被很多其他的组织所支持。 WSDK 用于结构化的描述 Web Services
?

Apache Axis用户指南(3)



本部分是 apache axis 用户指南的第三部分。在 Axis 中使用 WSDL 文件。
10. 使用 WSDL
Web Service Description Language 是由 IBM Microsoft 完成的规范,并且被很多其他的组织所支持。 WSDK 用于结构化的描述 Web Services Web 服务的 WSDL 是由程序来使用的,它包含了服务的接口,服务使用的数据类型以及服务的位置。更多的内容,可以参考 W3C WSDL 规范。
Axis 通过以下三宗方式来支持 WSDL
¨????????? Axis 中发布一个服务后,用户可以通过标准的 web 浏览器来访问服务的 URL ,在后面添加一个 ?WSDL ,这样就可以获得自动生成的服务的 WSDL 文件。
¨????????? 提供了一个 WSDL2Java 工具,用于根据 WSDL 文件生成 Java 代理类和框架类。
¨????????? 提供了一个 Java2WSDL 工具,用于根据 Java 类构建 WSDL 文件。
?WSDL:获取服务的WSDL文件
当通过 Axis 成功发布一个服务后,这个服务和唯一的一个 URL 相关联。对于 JWS 文件来说, URL 就是 JWS 文件本身的路径;对于非 JWS 服务来说,一般情况下 URL 的格式如下:
http://<host>[:port]/axis/services/<service-name>
如果可以通过浏览器访问服务的 URL ,那么就会看到一个提示消息,提示终端节点是一个 Axis 服务,那么你应该通过 SOAP 来访问。提示信息如下:
<service-name>
?
Hi there,this is an AXIS service!
Perhaps there will be a form for invoking the service here...
然而,如果在 URL 后面添加一个 ”?wsdl” ,那么 Axis 会自动生成一个服务的 WSDL 文件,并在浏览器中以 XML 格式显示,如下图所示:

WSDL2Java:根据WSDL文件创建StubsSkeletons和数据类型
客户端绑定
Axis WSDL-to-Java 工具的类为 org.apache.axis.wsdl.WSDL2Java ,基本调用方式如下:
java org.apache.axis.wsdl.WSDL2Java (WSDL-file-URL)
这会为客户端生成必要的绑定,这个过程中 Axis 遵守 JAX-RPC 规范。假设执行以下命令:
cm %AXIS_HOME%/samples/addr
java org.apache.axis.wsdl.WSDL2Java AddressBook.wsdl
这会在 %AXIS_HOME%/samples/addr/AddressFetcher2 目录生成很多类。他们之所以在这里生成,是由于这是 WSDL 中声明的 targetNamespace ,并且是映射到 Java 的包名。名称空间会在下面进行说明:

类型
根据 WSDL 类型生成的 Java 类根据 WSDL 的类型进行命名。一般来说 ( 不是绝对的 ), 这个 java 类会是一个 bean 。例如下面的 WSDL 类型:
<xsd:complexType name="phone">
<xsd:all>
??? <xsd:element name="areaCode" type="xsd:int"/>
??? <xsd:element name="exchange" type="xsd:string"/>
??? <xsd:element name="number" type="xsd:string"/>
</xsd:all>
</xsd:complexType>
WSDL2Java 会生成如下的 Java 类:
public class Phone implements java.io.Serializable {
??? public Phone() {...}
??? public int getAreaCode() {...}
??? public void setAreaCode(int areaCode) {...}
??? public java.lang.String getExchange() {...}
??? public void setExchange(java.lang.String exchange) {...}
??? public java.lang.String getNumber() {...}
??? public void setNumber(java.lang.String number) {...}
??? public boolean equals(Object obj) {...}
??? public int hashCode() {...}
}
XML-->Java 的映射:元数据
上面例子中的 XML 类型名为 phone ,而生成的 Java 类名为 Phone ,第一个字母为大写,以适应 Java 编码规范。这种映射经常发生,因为对于 XML 的名称或者标志符的限制要比 Java 少得多。例如,如果 phone 的子元素的名字为 new ,那么由于 new Java 中的保留字,所以不能生成这样的成员属性。为了支持这种类型的映射,同时支持 XML 属性的序列化与反序列化,通过类型元数据系统来关联 Java 数据类和描述符。
WSDL2Java 工具生成了一个数据 bean ,例如上面的 Phone 类,它会观察是否 schema 中包含一些没有直接映射到 Java 的成员变量的属性或者名字。如果有的话,就会生成一个静态的代码片断并为这个类提供一个类型描述符。类型描述符是一个变量描述符的集合,每一个变量描述符将 Java 的变量映射到 XML 元素或者属性。
// Type metadata
private static TypeDesc typeDesc;
static {
???????? typeDesc = new TypeDesc(AttributeBean.class);
???????? FieldDesc field;
???????? // An attribute with a specified QName
???????? field = new AttributeDesc();
???????? field.setFieldName("name");
???????? field.setXmlName(new QName("foo","nameAttr"));
???????? typeDesc.addFieldDesc(field);
???????? // An attribute with a default QName
???????? field = new AttributeDesc();
???????? field.setFieldName("male");
???????? typeDesc.addFieldDesc(field);
???????? // An element with a specified QName
???????? field = new ElementDesc();
???????? field.setFieldName("age");
???????? field.setXmlName(new QName("foo","ageElement"));
???????? typeDesc.addFieldDesc(field);
}
Holders
这种类型作为输入输出或者输出参数使用。 Java 没有输入输出 / 输出参数的概念。为了实现这种行为, JAX-RPC 指定使用 holder 类。一个 Holder 类似一个简单的 java 类,包含了它的一个类型。例如上面例子中的 Phone 类的 holder 类如下:
package samples.addr.holders;
public final class PhoneHolder implements javax.xml.rpc.holders.Holder {
??? public samples.addr.Phone value;
??? public PhoneHolder()
??? {
??? }
??? public PhoneHolder(samples.addr.Phone value) {
??????? this.value = value;
??? }
}
holder 类只有在类型被作为输入输出或者输出参数的时候才被生成。 Holder 类实在类名后面加上后缀 Holder 来命名,并且生成到包名为 holders 下面。
PortTypes
服务定义接口 (Service Definition Interface,SDI) 是继承了 WSDL portType 的接口,可以通过这个接口访问服务操作。例如下面的 WSDL
<message name="empty">
<message name="AddEntryRequest">
?<part name="name" type="xsd:string"/>
?<part name="address" type="typens:address"/>
</message>
<portType name="AddressBook">
?<operation name="addEntry">
??? <input message="tns:AddEntryRequest"/>
??? <output message="tns:empty"/>
?</operation>
</portType>
WSDL2Java 会生成如下的接口:
public?interface?AddressBook?extends java.rmi.Remote {
??? public void?addEntry(String name,Address address) throws java.rmi.RemoteException;
}
SDI 接口的名字就是 portType 得名字。为了构造 SDI WSDL2Java 需要从 portType binding 种同时获取信息。
JAX-RPC 规范对这部分的说明是:
"The name of the Java interface is mapped from the name attribute of the wsdl:portType element. ... If the mapping to a service definition interface uses elements of the wsdl:binding ...,then the name of the service definition interface is mapped from the name of the wsdl:binding element."
这个规范是 JAX-RPC ,这意味着只适用于 portType 是一个 RPC 接口。如果绑定的信息不是 RPC ,那么将使用绑定的名称。
可以有一个 portType—pt 和两个绑定 bRPC bDoc ,这样的话就不能为两个绑定使用一个接口,此时需要使用两个接口,一个叫 pt ,另一个叫 bDoc ,同时还要生成两个 stubs ,一个叫 bRPCStub( 实现了 pt) ,另一个叫 bDocStub( 实现了 bDoc)
document/literal 改变了接口的形式。
绑定
Stub 类实现了 SDI Stub 的名字是绑定的名字 +Stub 。它包含将方法调用转换成 SOAP 调用的代码,通过使用 Axis Service Call 对象。它作为远程服务的代理,使调用时就像调用本地对象一样。也就是说,不需要处理 endpoing URL ,名称空间或者参数数组,这些需要通过 Service Call 对象动态调用。 Stub 隐藏了所有这些的具体实现。
根据下面的 WSDL 片段:
<binding name="AddressBookSOAPBinding" type="tns:AddressBook">
?...
</binding>
WSDL2Java 会生成如下的 Stub
public class AddressBookSOAPBindingStub extends org.apache.axis.client.Stub
??????????????????????????????? ????????implements AddressBook {
??? public AddressBookSOAPBindingStub() throws org.apache.axis.AxisFault
??? {...}
??? public AddressBookSOAPBindingStub(URL endpointURL,
????????????????????????????????????? javax.xml.rpc.Service service)
??????? throws org.apache.axis.AxisFault
??? {...}
??? public AddressBookSOAPBindingStub(javax.xml.rpc.Service service)
??????? throws org.apache.axis.AxisFault
??? {...}
??? public void addEntry(String name,Address address) throws RemoteException
??? {...}
}
Services 服务
正常来讲,客户端应用程序不会直接实例化一个 stub ,而是实例化一个 service locator ,然后调用一个方法来返回 stub 。这个 locator 是根据 WSDL 中的服务元素来指定的。 WSDL2Java 根据 service 元素生成两个独享,例如:
<service name="AddressBookService">
?<port name="AddressBook" binding="tns:AddressBookSOAPBinding">
??? <soap:address location="http://localhost:8080/axis/services/AddressBook"/>
?</port>
</service>
WSDL2Java 会生成如下接口和类:
public interface AddressBookService extends javax.xml.rpc.Service {
??? public String getAddressBookAddress();
??? public AddressBook getAddressBook() throws javax.xml.rpc.ServiceException;
??? public AddressBook getAddressBook(URL portAddress) throws javax.xml.rpc.ServiceException;
}
实现了 AddressBookServie 的类:
public class AddressBookServiceLocator extends org.apache.axis.client.Service
???????????????????????? ??????????????implements AddressBookService {
??? ...
}
Service 接口定义了 WSDL 中定义的每个接口的 get 方法。 locator 实现了 service 接口,也就是说它实现了 get 方法。它用来获取 Stub 实例。 Service 类会默认的创建一个指向 endpoint URL Stub ,但是当请求 PortType 的时候,可能需要指定一个不同的 URL
一个典型的 stub 类的应用如下:
public class Tester
{
??? public static void main(String [] args) throws Exception {
??????? // Make a service
??????? AddressBookService service = new?AddressBookServiceLocator();
?
??????? // Now use the service to get a stub which implements the SDI.
??????? AddressBook port = service.getAddressBook();
?
??????? // Make the actual call
????????Address?address = new Address(...);
??????? port.addEntry("Russell Butek",address);
??? }
}
服务器端的绑定
就像在客户端有一个 Web Service Java stub 一样,一个 Java? 框架的 skeleton 在服务器端使用。为了生成 Skeleton 类,需要使用 WSDL2Java —server-side –skeletonDeploy true 选项。例如,仍旧使用 AddressBook.wsdl 文件:
java org.apache.axis.wsdl.WSDL2Java --server-side --skeletonDeploy true AddressBook.wsdl
可以看到 WSDL2Java 生成了所有在之前生成的 client 端的类,但是又声称了一些新的文件:

如果不指定 —skeletonDeploy true 选项,那么不会生成 skeleton ,而是生成的 deploy.wsdd 文件指示实现类已经直接部署了。在这种情况下, deploy.wsdd 文件包含了额外的元数据来描述实现类的操作和参数。通过下面的方法可以直接部署服务:
java org.apache.axis.wsdl.WSDL2Java --server-side AddressBook.wsdl
下面是在服务器端生成的文件:

绑定
Skeleton 描述
Skeleton 类是介于 Axis engine 和实际的服务实现之间的类。它的名字就是绑定的名字 +Skeleton 。例如对于 AddressBook 绑定, WSDL2Java 会生成如下的 Skeleton
public class AddressBookSOAPBindingSkeleton implements AddressBook,
?????????????????????????????????????????????????????? org.apache.axis.wsdl.Skeleton {
??? private AddressBook impl;
???? public AddressBookSOAPBindingSkeleton() {
??????? this.impl = new AddressBookSOAPBindingImpl();
??? }
???? public AddressBookSOAPBindingSkeleton(AddressBook impl) {
??????? this.impl = impl;
??? }
???? public void addEntry(java.lang.String name,Address address)
??????? throws java.rmi.RemoteException
??? {
??? ????impl.addEntry(name,address);
??? }
}
实际的 Skeleton 类可能内容还有很多,这里只拷贝了基本的框架。
skeleton 类包含一个 AddressBook 服务的实现。这个实现要么通过构造器传递给 skeleton ,要么是一个生成的实现的实例。当 Axis engine 调用 skeleton addEntry 的方法时,它只需要简单的将调用分配给实际的实现的 addEntry 方法。
实现模板描述
WSDL 还根据绑定生成了一个实现模板:
public class AddressBookSOAPBindingImpl implements AddressBook {
?
??? public void addEntry(String name,Address address)
??????? throws java.rmi.RemoteException {
??? }
}
这个类实际上只是一个实现的测试,并没有做任何事,它预想服务的编程人员来根据这个模板完成具体的实现。
服务
这个工具同时生成了 deploy.wsdd undeploy.wsdd 文件,可以供 AdminClient 食用。这些文件只有当填充了实现类的具体方法后,编译类文件,然后将类文件放到 Axis engine 可以访问的位置后,才可以调用 AdminClient 方法来发布服务。
11.Java2WSDL
????????? 这个工具笔者就不介绍了
笔者认为使用 WSDL2Java 工具生成的代码中冗余的代码太多,并且编码规范有一些 ApacheAxis-Specific ,所以觉得还是自己手写代码比较好一些。
一旦写完了 Java 代码,可以通过 Web 浏览器访问,获取 WSDL 文件,没有必要使用 Java2WSDL 了。
12. 公开的 Axis 接口
???????? Axis 公开的接口相对稳定,可以使用,即使 Axis 重构的话,这部分也应该不会修改。或者做一些兼容性的修改。
可以实现的一些 Apache Axis 的接口如下:
JAX-RPC 的一些接口,这些接口是针对 JAX-RPC 规范 1.0 的,会根据新的规范进行修改。
Axis 接口:这些相对不稳定。
12. 重要的类
org.apache.axis.MessageContext
Axis 所知道的关于请求 / 响应的所有的信息都是通过 MessageContext 来获取的。 Axis 将下面的内容存储在 MessageContext 中:
AxisEngine 的引用
请求和响应的消息 (org.apache.axis.Message 对象可以通过 Getter Setter 方法存取 )
无状态以及服务范围的信息 ( 服务是否维持 session 信息 )
当前处理状态
认证信息 ( 用户名和密码,可以由 servlet 服务器提供或者其他方式 )
丰富的属性。几乎所有关于属性的信息都可以通过 MessageContext.getProperty() 方法获取。只需要知道属性的名称,通常是一个常量,定义在例如 org.apache.axis.transport.http.HTTPConstants 这样的类中。例如,可以获取 Axis Servlet ServletContext ,通过 (HttpServlet)msgC.getProperty(HTTPConstants.MC_HTTP_SERVLET).getServletContext()
在服务中,当前的 MessageContext 总是可以通过静态的方法 MessageContext.getCurrentContext() 获取。
org.apache.axis.Message
org.apache.axis.Message 对象是 Axis SOAP 消息的一种表示。请求和响应消息可以从 MessageContext 中获取 ( 如上所述 ) Message 包括:
MIME ( 如果 message 本身包含 MIME 信息 )
附件 ( 如果 message 本身包含附件 )
SOAPPart( 快速获取 SOAPPart SOAPEnvelope) ,可以通过 SOAPPart 访问 SOAP 的任意信息 (<soap:Envelope> 标签内的任意信息 )
org.apache.axis.SOAPEnvelope
一个 MessageContext 有两个 Message ,每个都包含一个 SOAPPart SOAPPart 包含 SOAPEnvelope SOAPEnvelope 包含 SOAP 信封的所有内容。可以从 SOAPEnvelope 中获取 SOAP Header SAOP Body
更多内容,参考具体的 API

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读