- 浏览: 1225 次
- 性别:
- 来自: 广州
最近访客 更多访客>>
文章分类
最新评论
-
啦登2010:
顶。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 ...
Java 远程通信技术——Axis实战 -
leslies2:
<div class="quote_title ...
Java 远程通信技术——Axis实战 -
leslies2:
<div class="quote_title ...
Java 远程通信技术——Axis实战 -
我爱java:
哇哦~~好棒好棒
Java 远程通信技术——Axis实战 -
yuezhiwen5:
支持楼主~~~~
Java 远程通信技术——Axis实战
前言
在 Internet
网络覆盖全球的今天,网络通信已经是当今软件开发过程中离不开的话题。在常用的Windows、Liunx、Unix
系统当中,大部分的网络数据传输都是使用 TCP/IP、UDP/IP 作为底层传输协议的,而 HTTP 协议就是基于 TCP/IP
协议而运行的超文本传送协议。
在 JAVA 高级开发语言中,陆续出现
RMI、CORBA、JAX-RPC、JAX-WS、Axis、XFire、HTTP Invoker、Hessian、Burlap、JMX
等远程通信架构去实现系统之间数据传送。在 “远程通信技术” 的一系列文章中,本人将对上述复杂的 JAVA 远程通信技术作出归纳。
首先,在本篇文章中先对有着10多年历史的 Axis 进行介绍。
目录
1.1 Web服务的起源
Web 服务是现今实现网络服务概念的趋势,它把基础架构建立于标准化的XML语言之上,能够使用一种与平台无关的方式对数据进行编码,其中 SOAP 与 WSDL 都遵从此标准化的 XML 编码规则。
SOAP
(Simple Object Access Protocol,简单对象访问协议)是一种轻量的、简单的、基于 XML
的协议,用于描述在服务过程中服务器端与客户端之间所交换的消息。 SOAP 可以和现存的许多因特网协议和格式结合使用,包括超文本传输协议(
HTTP),简单邮件传输协议(SMTP),多用途网际邮件扩充协议(MIME)。
WSDL (Web Service Definition Language,Web服务描述语言)是一种基于 XML的协议,用于定义服务端与客户端之间的契约,描述Web服务的公共接口,列出 Web服务进行交互时需要绑定的协议和信息格式。
Web 服务采用 WSDL 语言描述该服务支持的操作和信息,运行时再将实际的数据以 SOAP 方式在服务端与客户端进行信息传递。
由
于软件开发平台众多,当中存在不同的开发风格,当服务器端与客户端使用不同的开发工具时,数据转换成为复杂且关键的问题。而 SOAP 与 WSDL
的主要特性之一在于它们都是可扩展的,且与开发平台无关。为了建立统一的 XML 协议, 微软、IBM、Sun、Oracle、BEA
等多家软件开发商联合起来,组成了一个名为WS-I(Web Service Interoperability)组织,由该组织制定
WS-ReliableMessage、WS-Discovery、WS-Federation、WS-Coordination、WS-
AtomicTransaction、WS-BusinessActivity 、WS-Enumeration、WS-Eventing
、WS-Management 等一系列用于数据交换的规范。
1.2 JAX-RPC、JAX-WS 简介
JAX-RPC
( Java API for XML-based RPC ) 是 Java 库中基于 XML 远程服务的一组标准 API,它通过 WSDL
方式对所提供的服务进行描述,并以 RPC 的风格把 SOAP 信息进行公开,是 Java 库中最早对 Web 服务提供支持的一组API。
JAX-RPC
1.0 从其名称可以看出,最初的目的只是为了支持使用(Remote Procedure Call,RPC) 的 XML 远程过程调用操作,它以
BP 1.0 (WS-I’s Basic Profile 1.0)为基础,依赖于SAAJ 1.2(SOAP with Attachments
API for Java)为规范,虽然支持 SOAP 协议,但对 Web 服务功能有一定的局限性。于是在 2003 年底,开发团队对
JAX-RPC 1.0 进行大幅修订,由 Sun 公司组织了一个专家组开始进行 JAX-RPC 2.0 规范的开发。
JAX-RPC
2.0 是基于 JAVA 5 而开发的,它依赖于 Annotation 等新特性,在JAX-RPC
的基础上提供还增加了如异步回调,面向消息等新增技术。JAX-RPC 2.0 以 BP 1.1(WS-I’s Basic Profile 1.1 )
为基础,依赖于SAAJ 1.3(SOAP with Attachments API for Java)为规范,能使用 SOAP
1.1、SOAP 1.2 进行信息公开。它是 JAX-RPC 1.1 架构发展的成果,在开发完成后,JAX-RPC 2.0 被正式改名成为
JAX-WS ( Java API for XML-Web Services ) 。
1.3 Axis 概述
Axis
全称 Apache EXtensible Interaction System ( 阿帕奇可扩展交互系统 ) , 它是一个 SOAP
引擎,提供创建 Web 服务的基本框架。Axis 1.x 是基于 JAX-RPC 而实现一个工具包,它可以使用 HTTP、JMS、SMTP
等多种传输方式支持 SOAP 。
Axis 2.x 是新一代的 Axis 引擎,它支持 JAX-WS、JAX-PRC 等
API,并且在Axis 1.x 的基础上增加了灵活数据绑定、异步调用等新增功能,可使用 SOAP 1.1 、SOAP 1.2
协议。在服务请求上,Axis 2.x 支持三种请求-响应模式:In-Only、Robust-In和In-Out,也可支持使用 REST
风格的开发方式。
基本的 Axis Web 服务由四部分组成:Axis Servlet 、Axis 部署描述、 远程服务接口、服务实现类。
Axis
Servlet 是 Axis 的核心,它负责 WSDL 基础服务信息的公开,并把 SOAP 请求转化为 Java
方法的调用,最后把返回值转化为 SOAP 。Axis Servlet 隐藏了构建 Web 服务的大量代码,使用开发人员不用直接与 SOAP
打交道便可轻松完成 Web 服务的开发。
Axis 部署描述是一个XML文档,它用于管理 Web 服务的发布,决定哪些服务类需要通过 SOAP 对外公开 。
远程服务接口并非必要的,但在很多的 Web 服务开发过程中都会使用远程服务接口用于对外暴露服务类的方法,在服务器端通过服务实现类去继承实现服务接口。
由于 Axis 1.x 与 Axis 2.x 有各自的特色,下面将分开来介绍。
二、Axis 1.x 实例
2.1 Axis 1.x 的下载与安装
Axis 1.x 可于官网 http://axis.apache.org/axis/
下载,完成下载后建立 Web Project 作为测试项目 ,把 lib 文件夹下的 jar 文件拷贝,引入到测试项目当中。
在
web.xml 文件下加入 AxisServlet 配置后,系统就会对以后缀为 *.jws 及路径为 /services/*
的请求进行监听,遇到此类请求时将把信息交由 org.apache.axis.transport.http.AxisServlet 进行处理。
<web-app> <display-name>Apache-Axis</display-name> <listener> <listener-class> org.apache.axis.transport.http.AxisHTTPSessionListener </listener-class> </listener> <servlet> <display-name>Apache-Axis Servlet</display-name> <servlet-name>AxisServlet</servlet-name> <servlet-class> org.apache.axis.transport.http.AxisServlet </servlet-class> </servlet> <!-- 服务管理 --> <servlet> <display-name>Axis Admin Servlet</display-name> <servlet-name>AdminServlet</servlet-name> <servlet-class> org.apache.axis.transport.http.AdminServlet </servlet-class> <load-on-startup>100</load-on-startup> </servlet> <!-- 对输入输出的SOAP信息进行检测 --> <servlet> <display-name>SOAPMonitorService</display-name> <servlet-name>SOAPMonitorService</servlet-name> <servlet-class> org.apache.axis.monitor.SOAPMonitorService </servlet-class> <init-param> <param-name>SOAPMonitorPort</param-name> <param-value>5001</param-value> </init-param> <load-on-startup>100</load-on-startup> </servlet> <servlet-mapping> <servlet-name>AxisServlet</servlet-name> <url-pattern>/servlet/AxisServlet</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>AxisServlet</servlet-name> <url-pattern>*.jws</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>AxisServlet</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>SOAPMonitorService</servlet-name> <url-pattern>/SOAPMonitor</url-pattern> </servlet-mapping> </web-app>
而 SOAPMonitorService 并非必要配置,但加入SOAPMonitorService 配置,可以便于对服务运行时所传输的SOAP信息进行监听,在服务的requestFlow或responseFlow 中加入 SOAPMonitorHandler , 系统就可显示服务请求和回发时的 SOAP 信息。
<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <handler name="soapmonitor" type="java:org.apache.axis.handlers.SOAPMonitorHandler"> <parameter name="wsdlURL" value="/axis/SOAPMonitorService-impl.wsdl"/> <parameter name="namespace" value="http://tempuri.org/wsdl/2001/12/SOAPMonitorService-impl.wsdl"/> <parameter name="serviceName" value="SOAPMonitorService"/> <parameter name="portName" value="Demo"/> </handler> <service name="SOAPMonitorService" provider="java:RPC"> <parameter name="allowedMethods" value="publishMessage"/> <parameter name="className" value="org.apache.axis.monitor.SOAPMonitorService"/> <parameter name="scope" value="Application"/> </service> <service name="myService" provider="java:RPC"> <requestFlow> <handler type="soapmonitor"/> </requestFlow> <responseFlow> <handler type="soapmonitor"/> </responseFlow> <parameter name="allowedMethods" value="*"/> <parameter name="className" value="axis.server.myService"/> </service> </deployment>
2.2 调用服务的三种方式
下
面从最简单的 HelloWorld 开始,介绍 Axis 的使用方法。首先在 WEB-INF 文件夹下建立 server-config.wsdd
文件,在 Axis 1.x 当中,此文件正是用于管理服务发布的默认配置文件。首先 service 用于定义对外暴露的服务,其中 name
属性用于定义服务的名称。像下面例子,当 name 为 PersonService 时,对外暴露的服务路径则对应为 http://localhost:8080/axis.server/services/PersonService
。
而
parameter 用于定义服务的相关属性,className 表示此服务的实现类,而 allowedMethods
表示所公开的服务方法,“*" 则默认为公开此类中的所有 public 公共方法。而 scope
则是用于定义服务对象生成的方式,它包括三个选项:request、session、application 。
request 是默认选择,表示为每个请求生成一个服务对象;
session 表示对同一个客户代理对象所发送的请求使用同一个服务对象,并把服务信息放在同一个上下文当中。当使用有状态服务时,使用此 session 更为合适,在下节将再作进一步介绍;
application 类似于使用单体模式,表示所示的请求均使用同一个服务对象,当使用无状态服务时使用 application 能有效提高运行效率。
最后在 transport 中定义一个 requestFlow 处理类 org.apache.axis.handlers.http.URLMapper
,表示在系统接受到 http 请求时,将会调用 URLMapper 类来处理路径映射等问题
<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <!--在浏览器暴露服务 PersonService--> <service name="PersonService" provider="java:RPC"> <!--绑定服务实现类型 PersonServiceImpl--> <parameter name="className" value="axis.serviceImpls.PersonServiceImpl" /> <parameter name="allowedMethods" value="*" /> <parameter name="scope" value="application" /> </service> <!--当接收到 http 请求时交由 URLMapper 进行处理--> <transport name="http"> <requestFlow> <handler type="java:org.apache.axis.handlers.http.URLMapper"/> </requestFlow> </transport> </deployment>
PersonService 服务代码如下,此时运行服务,输入路径 http://localhost:8080/axis.server/services/PersonService?wsdl ,浏览器上将显示此服务的 wsdl 信息。
public interface IPersonService { String HelloWorld(String name); } public class PersonServiceImpl implements IPersonService { @Override public String HelloWorld(string name){ return "Hello "+name; } }
客户端的生成工具有多种,其中一种是使用 Axis 1.x 中的自带生成器 WSDL2Java ,此生成器可以根据 wsdl 文件生成客户端。
首先在环境变量中把 Axis_Home 绑定到 Axis 1.x 的根目录,在 path 加入设置 ".;%Axis_Home%\lib ", 然后输入
Java org.apache.axis.wsdl.WSDL2Java http://localhost:8080/axis.server/services/PersonService?wsdl
-p axis.client.person
此
时系统将在 axis.client.person 包内生成客户端代码类
PersonServiceImpl、PersonServiceImplService、
PersonServiceImplServiceLocator、PersonServiceSoapBindingStub。
PersonServiceImplServiceLocator 用于实现 PersonServiceImplService 接口,它绑定了服务的名称,地址,端口等详细资料。
PersonServiceImpl 用于定义服务的接口,而 PersonServiceSoapBindingStub 则是此服务代理,它通过 SOAP 协议把操作请求发送到服务器,并把返回信息转化为 Java 对象。
public static void main(String[] args) throws RemoteException, MalformedURLException, ServiceException { // TODO Auto-generated method stub HelloWorld(); } private static void HelloWorld() throws RemoteException, MalformedURLException{ PersonServiceImpl personService=new PersonServiceSoapBindingStub( new URL("http://localhost:8080/axis.server/services/PersonService"), new PersonServiceImplServiceLocator()); System.out.println(personService.helloWorld("Leslie")); }
通
过系统自动生成的代理类就能简单地调用远程服务,这是因为在代理类中已经完成了大量关于PersonService
服务的配置,但本人觉得想要深入地了解 Axis
的开发,就应该了解其内部的结构。所以在下面例子当中将介绍如何使用Axis的内部机制直接调用Web服务。
在
org.apache.axis.client 中存在着服务的基础类 Service ,通过 Service
可用于管理服务的绑定地址,端点,获取服务的 WSDL 等详细信息。另外 Call
类用于管理每个服务请求动作,它可以设置每个请求的方法,最后通过call.invoke(Object[])调用服务,并获取完成后的返回值。
public static void main(String[] args) throws RemoteException, MalformedURLException, ServiceException { HelloWorld(); } private static void HelloWorld() throws ServiceException,RemoteException{ //生成服务对象Service Service service=new Service(); Call call=(Call) service.createCall(); //设置Endpoint地址 call.setTargetEndpointAddress( "http://localhost:8080/axis.server/services/PersonService"); //绑定请求方法名称 call.setOperationName("HelloWorld"); //通过call.invoke调用服务,获取返回值 String data=(String)call.invoke(new Object[]{"Leslie"}); System.out.println(data); }
如 果觉得使用 Call 实现请求较为麻烦,Service 中还提供一个 getPort 方法,通过此方法还可直接实现服务接口 PersonServiceImpl。另外,Axis 还为准备了一个 ServiceFactory 工厂,通过 ServiceFactory 可以直接获取 Service 对象。
public static void main(String[] args) throws RemoteException, MalformedURLException, ServiceException { // TODO Auto-generated method stub HelloWorld(); } private static void HelloWorld() throws ServiceException, RemoteException, MalformedURLException { String wsdl="http://localhost:8080/axis.server/services/PersonService?wsdl"; String uri="http://localhost:8080/axis.server/services/PersonService"; String serviceName="PersonServiceImplService"; //使用serviceFacotry直接生成服务 ServiceFactory factory=ServiceFactory.newInstance(); Service service=(Service) factory.createService( new URL(wsdl),new QName(uri,serviceName)); //使用service.getPort方法实现服务接口 PersonServiceImpl personService=(PersonServiceImpl)service .getPort(PersonServiceImpl.class); String data=personService.helloWorld("Leslie"); System.out.println(data); }
2.3 以自定义对象传输数据
若 需要以自定义对象作为数据传输的载体,则需要为自定义对象继承 Serializable 接口。另外可以留意一下服务的 wsdl , 因为 Axis 并没有默认使用List , Map 等类型, 在 List,Map 等作为参数时,wsdl 都会把返回类型设置为 ArrayOf_xsd_anyType,所以建议使用简单数组作为返回值。
public class PersonEntity implements Serializable { private Integer id; private String name; private Integer age; private String address; public PersonEntity(Integer id,String name,Integer age,String address){ this.id=id; this.name=name; this.age=age; this.address=address; } public Integer getId(){ return id; } public void setId(Integer id){ this.id=id; } .......... } public interface IPersonService { PersonEntity GetPerson(int id); PersonEntity[] GetList(); List GetList(String name); } public class PersonServiceImpl implements IPersonService { @Override public PersonEntity[] GetList(){ PersonEntity[] list=new PersonEntity[2]; PersonEntity person1=new PersonEntity(1,"Leslie",32,"tianhe"); PersonEntity person2=new PersonEntity(2,"Elva",31,"henan"); list[0]=person1; list[1]=person2; return list; } @Override public List GetList(String name){ List list=new ArrayList(); PersonEntity person1=new PersonEntity(1,name+" Lee",32,"tianhe"); PersonEntity person2=new PersonEntity(2,name+" Chen",31,"henan"); list.add(person1); list.add(person2); return list; } @Override public PersonEntity GetPerson(int id){ return new PersonEntity(id,"Leslie",32,"tianhe"); } }
在 server-config.wsdd 中使用 beanMapping 加入自定义对象绑定,以 languageSpecificType 绑定类名,qname 可由用户设置,但必须与 xmln 特性相对应。
......... <service name="PersonService" provider="java:RPC"> <parameter name="className" value="axis.serviceImpls.PersonServiceImpl" /> <parameter name="allowedMethods" value="*" /> <parameter name="scope" value="application" /> <beanMapping qname="myNS:PersonEntity" xmlns:myNS="urn:PersonEntity" languageSpecificType="java:axis.entity.PersonEntity" /> </service> .........
以 WSDL2Java 生成客户端代码后,可以留意 PersonEntity 对象已经自动实现了 Serializable 接口,增加了 getDeserializer、getSerializer 等序列化与反序列化方法。此时直接使用代理类,会自动地完成对象序列化的过程,可以节省了不少时间。
public static void main(String[] args) throws RemoteException, MalformedURLException, ServiceException { GetList(); GetPerson(); } private static void GetPerson() throws RemoteException, MalformedURLException{ PersonServiceImpl personService=new PersonServiceSoapBindingStub( new URL("http://localhost:8080/axis.server/services/PersonService"), new PersonServiceImplServiceLocator()); PersonEntity person=personService.getPerson(1); DisplayPersonProperty(person); } private static void GetList() throws ServiceException, RemoteException, MalformedURLException{ PersonServiceImpl personService=new PersonServiceSoapBindingStub( new URL("http://localhost:8080/axis.server/services/PersonService"), new PersonServiceImplServiceLocator()); Object[] objs=personService.getList("Leslie"); for(Object person:objs) DisplayPersonProperty((PersonEntity)person); } //显示对象属性 private static void DisplayPersonProperty(PersonEntity person){ System.out.println("Id:"+person.getId()+" Name:"+person.getName()+" Age:"+ person.getAge()+" Address:"+person.getAddress()); }
但 需要注意,如果使用 Service 类去调用服务的时候,需要使用 Call.registerTypeMapping 注册一个类型,把接收到的信息转换为 PersonEntity 类型。在注册类型时 namespaceURI 参数值需要与服务端 server-config.wsdd 中的值保持一致。
public static void main(String[] args) throws RemoteException, MalformedURLException, ServiceException { // TODO Auto-generated method stub GetArray(); GetList(); } private static void GetArray() throws ServiceException, RemoteException{ Service service=new Service(); Call call=(Call)service.createCall(); call.setTargetEndpointAddress( "http://localhost:8080/axis.server/services/PersonService"); //注册返回类型,namespaceURI 必须与服务端注册值一致 QName qName2=new QName("urn:PersonEntity","PersonEntity"); call.registerTypeMapping(PersonEntity.class, qName2, new BeanSerializerFactory(PersonEntity.class,qName2), new BeanDeserializerFactory(PersonEntity.class,qName2)); //绑定请求方法 call.setOperation("GetList"); //设置返回类型 call.setReturnClass(PersonEntity[].class); PersonEntity[] list=(PersonEntity[]) call.invoke(new Object[]{}); for(PersonEntity person:list) DisplayPersonProperty(person); } private static void GetList() throws ServiceException, RemoteException{ Service service=new Service(); Call call=(Call)service.createCall(); call.setTargetEndpointAddress( "http://localhost:8080/axis.server/services/PersonService"); //注册返回类型,namespaceURI 必须与服务端注册值一致 QName qName2=new QName("urn:PersonEntity","PersonEntity"); call.registerTypeMapping(PersonEntity.class, qName2, new BeanSerializerFactory(PersonEntity.class,qName2), new BeanDeserializerFactory(PersonEntity.class,qName2)); //绑定请求方法 call.setOperationName(new javax.xml.namespace.QName( "http://serviceImpls.axis", "GetList")); //输入参数 Object[] list=(Object[]) call.invoke(new Object[]{"Leslie"}); for(Object person:list) DisplayPersonProperty((PersonEntity)person); } private static void DisplayPersonProperty(PersonEntity person){ System.out.println("Id:"+person.getId()+" Name:"+person.getName()+" Age:"+ person.getAge()+" Address:"+person.getAddress()); }
三、Web服务会话管理
记得在第二节曾经为大家介绍服务对象的生成方式,当 scope 设置 session 时,系统会对同一个客户代理对象所发送的请求使用同一个服务对象,并把服务信息放在同一个上下文当中。利用 session 可以把用户名、用户密码、订单号此类信息在方法中传播,也可以确保不同的客户信息分别保存在不同的上下文之上。session 数据的保存时间可以通过 session.setTimeout 方法设置。
public interface ILoginService { public Boolean Login(String name,String password); public String GetUserName(); } public class LoginServiceImpl implements ILoginService { @Override public Boolean Login(String name, String password) { // TODO Auto-generated method stub MessageContext context=MessageContext.getCurrentContext(); Session session=context.getSession(); if(session!=null) context.getSession().set("User",name); return true; } @Override public String GetUserName(){ MessageContext context=MessageContext.getCurrentContext(); Session session=context.getSession(); return session.get("User").toString(); } }
在 server-config.wsdd 中,把 scope 设置为 session 模式
....... <service name="LoginService" provider="java:RPC" style="wrapped"> <parameter name="className" value="axis.serviceImpls.LoginServiceImpl" /> <parameter name="allowedMethods" value="*" /> <parameter name="scope" value="session" /> </service> .......
在客户端调用时,需要把 maintainSession 设置为 true,此时可以把 userName , password 等信息存到上下文当中。
public static void main(String[] args) throws RemoteException, MalformedURLException, ServiceException { // TODO Auto-generated method stub Login(); } private static void Login() throws MalformedURLException, RemoteException{ LoginServiceImpl service1=getService(); LoginServiceImpl service2=getService(); service1.login("Leslie", "12345678"); service2.login("Jack", "12345678"); System.out.println("UserName: "+service1.getUserName()); System.out.println("UserName: "+service2.getUserName()); } private static LoginServiceImpl getService() throws AxisFault, MalformedURLException{ LoginServiceImplServiceLocator locator=new LoginServiceImplServiceLocator(); locator.setMaintainSession(true); LoginServiceImpl loginService=new LoginServiceSoapBindingStub( new URL("http://localhost:8080/axis.server/services/LoginService"), locator); return loginService; }
测试结果
四、自定义 Handler
Axis 的 Handler 与 Servlet 中的 Filter 有点相似,用于过滤服务,检测管理 Web 服务信息的接收发送过程。开发 Handler 需要实现 org.apache.axis.Handler 接口,接口包含了下面多个方法:
为了简化 Handler 的开发,Axis 在org.apache.axis.handlers 命名空间内就为客户提供了
BasicHandler、ErrorHandler、LogHandler、SimpleSessionHandler、
SimpleAuthenticationHandler、SimpleAuthorizationHandler 等 Handler 用于管理
Axis 的错误处理,日志记录,身份认证,权限管理等工作。BasicHandler 是实现 Handler 接口的基础类,用户可以继承
BasicHandler 类, 开发自定义的 Handler 对特定的服务分别在服务请求request 、信息回送 response
时进行处理。init、invoke 是 BasicHandler 最常用的方法, init 方法会在对象初始化时执行,而对服务的管理操作可以在
invoke 方法中定义。invoke 方法包括了 messageContext 参数 , 利用 messageContext
,可以获取到服务的 SOAP ,HttpServletRequest 、HttpServletResponse、URL 等相关信息。
下面的例子就是利用自定义的 LoginHandler 对 LoginService 服务请求进行监听。
首先修改 server-config.wsdd 文件,在 LoginService 服务的 requestFlow 中加入 LoginHandler 。
....... <service name="LoginService" provider="java:RPC" style="wrapped"> <parameter name="className" value="axis.serviceImpls.LoginServiceImpl" /> <parameter name="allowedMethods" value="*" /> <parameter name="scope" value="session" /> <requestFlow> <handler type="java:axis.handler.LoginHandler"/> </requestFlow> </service> ......
建立 LoginService,在对 LoginService 服务接收到 SOAP 请求时,系统可以通过 LoginHandler 监听请求信息,获取相关的方法名,输入参数等信息。通过 messageContext.getProperty(HTTPConstants.MC_HTTP_SERVLETREQUEST) 方法,可以获取到 HttpServletRequest 对象。
public interface ILoginService { public Boolean Login(String name,String password); } public class LoginServiceImpl implements ILoginService { @Override public Boolean Login(String name, String password) { // TODO Auto-generated method stub UserService service=new UserService(); User user=service.getUser(name); if(user!=null) return user.password==password; else return false; } } public class LoginHandler extends BasicHandler{ private MessageContext context; public void invoke(MessageContext context){ this.context=context; GetServletRequest(); GetSOAP(); } //获取HtppServletRequest对象 private void GetServletRequest(){ HttpServletRequest request = (HttpServletRequest)context .getProperty(HTTPConstants.MC_HTTP_SERVLETREQUEST); String remoteAddress=request.getRemoteAddr(); String method=request.getMethod(); StringBuffer URL=request.getRequestURL(); String message=String.format("Client Address:%s\nMethod:%s\n" + "RequestURL:%s\n", remoteAddress,method,URL); System.out.println(message); } //获取SOAPBody信息 private void GetSOAP(){ String soap=null; try { soap=context.getCurrentMessage().getSOAPBody().toString(); } catch (SOAPException e) { // TODO Auto-generated catch block e.printStackTrace(); } if(soap!=null){ String[] data= soap.split(">"); for(String line:data) System.out.println(line+">"); } } }
客户端
public static void main(String[] args) throws RemoteException, MalformedURLException, ServiceException { LoginServiceImpl service1=getService(); service1.login("Leslie", "12345678"); } private static LoginServiceImpl getService() throws AxisFault, MalformedURLException{ LoginServiceImplServiceLocator locator=new LoginServiceImplServiceLocator(); locator.setMaintainSession(true); LoginServiceImpl loginService=new LoginServiceSoapBindingStub( new URL("http://localhost:8080/axis.server/services/LoginService"), locator); return loginService; }
只要在 service 的 requestFlow 对 Handler 进行绑定,在客户端发送请求后, Handler 就能对服务请求进行监听。
同样地,在 service 的 responseFlow 输入流中对 Handler 进行绑定,就可以对回发的 SOAP 信息进行监听。
下面例子是利用自定义 LoginHandler 对用户的登录回发信息进行监察,计算成功登录的在线人数 。
首先修改 server-config.wsdd 文件,在 LoginService 服务的 responseFlow 中加入 LoginHandler 。
<service name="LoginService" provider="java:RPC" style="wrapped"> <parameter name="className" value="axis.serviceImpls.LoginServiceImpl" /> <parameter name="allowedMethods" value="*" /> <parameter name="scope" value="session" /> <responseFlow> <handler type="java:axis.handler.LoginHandler"/> </responseFlow> </service>
在自定义 Handler 中可以通过 Message.getSOAPEnvelope , Message.getSOAPHead
,Message.getSOAPBody 等多个方法对 Web 服务的回发信息进行监测。若登录成功,系统检测到 LoginReturn 值为
true 时,则修改成功登录人数数量。
除此以外,开发人员还可在 SOAP 的 head、body 等多处地方额外添加回发信息。下面的例子将记录成功登陆的人数,并把此信息记录在头文件中返还到客户端。
public interface ILoginService { public Boolean login(String name,String password); } public class LoginServiceImpl implements ILoginService { @Override public Boolean login(String name, String password) { UserService userService=new UserService(); User user=userSerivice.getUser(name); if(user!=null) return user.password==password; else return false; } } public class LoginHandler extends BasicHandler{ private MessageContext context; public void invoke(MessageContext context){ this.context=context; try { if(success()) logged(); addElement(); getSOAP(); } catch (AxisFault e) { e.printStackTrace(); } catch (SOAPException e) { e.printStackTrace(); } } //记录登录人数 private void logged(){ Handler handler=context.getService(); //判断服务是否为LoginService if(handler.getName().equals("LoginService")){ if(this.getOption("loggedCount")==null) this.setOption("loggedCount", 0); Integer count=Integer.parseInt( this.getOption("loggedCount").toString()); count++; this.setOption("loggedCount", count); System.out.println("logged count: "+count+" "+ new Date().toString()+"\n"); } } //获取LoginService服务返回值 //若登录成功则返回true,失败则返回false private Boolean success() throws SOAPException{ SOAPBody soap=context.getCurrentMessage().getSOAPBody(); Node node=soap.getElementsByTagName("LoginReturn").item(0); return node.toString().contains("true"); } //在回发的SOAP中加入已登录人数的信息 private void addElement() throws SOAPException { SOAPEnvelope soap=context.getCurrentMessage().getSOAPEnvelope(); SOAPElement element=soap.getHeader().addChildElement("loggedOnline"); element.addTextNode(this.getOption("loggedCount").toString()); } //显示SOAP信息 private void getSOAP() throws AxisFault{ SOAPEnvelope soap=context.getCurrentMessage().getSOAPEnvelope(); if(soap!=null){ String[] data= soap.toString().split(">"); for(String line:data) System.out.println(line+">"); } } }
客户端
public static void main(String[] args) throws RemoteException, MalformedURLException, ServiceException { LoginServiceImpl service1=getService(); service1.login("Leslie", "12345678"); } private static LoginServiceImpl getService() throws AxisFault, MalformedURLException{ LoginServiceImplServiceLocator locator=new LoginServiceImplServiceLocator(); locator.setMaintainSession(true); LoginServiceImpl loginService=new LoginServiceSoapBindingStub( new URL("http://localhost:8080/axis.server/services/LoginService"), locator); return loginService; }
运行结果
五、新一代 SOAP 引擎 Axis 2.x
5.1 Axis 2.x 核心结构
Axis 1.x 建立在 JAX-RPC 基础之上的, 但事实证明这并非一个好方法,因为 JAX-RPC 限制了 Axis
代码的功能,而且造成了性能问题使系统缺乏灵活性。Axis 2.x 在设计时已经考虑到灵活性操作的问题,它同时实现了对 JAXB 2.x、
Java XML 数据绑定标准,并以 JAX-WS 技术替代了 JAVA-PRC 作为 Java Web 服务标准。
Axis 2.x
是纯 SOAP 处理引擎,它的核心功能是处理传输消息,并将其交付给目标应用程序。像 JAX-WS 此类 Web 服务标准不会进入 Axis
2.x 核心部分当中,而只作为 Axis 2.x 服务传递组件。 AXIOM(Axis2 Object Model,Axis 2 对象模型)才是
Axis2 的基础,任何 SOAP 消息在 Axis2 中都可看作为
AXIOM。它把延迟构建和轻型的可定制对象模型结合了起来,尽可能地减轻对系统资源特别是 CPU 和内存的压力。
关于 Axis 2.x 的消息处理过程与 AXIOM 对象模型将在下节再作进一步介绍。
5.2 Axis 2.x 安装部署
Axis 2.x 可以在 http://axis.apache.org/axis2/java/core/index.html
下载,当中包括Binary Distribution、WAR 等多个版本,使用WAR 版本更方便把 Web 服务部署到 Tomcat、WebLogic 等服务管理器上,在开发阶段,使用 Binary Dirstribution 等版本更便于服务的调试。
完成下载后在环境变量中把 Axis2_Home 绑定到 Axis 2.x 的根目录,在 path 加入设置 ".;%Axis2_Home%\bin "。
Axis
1.x 当中只是包括了几个工具包,而 Axis 2.x 更像是一个框架,在 Axis 2.x 项目的“\WebRoot\WEB-INF\”
文件夹内包含了 Axis 2.x 多个储存库,在 “ conf ” 文件夹内的 “ axis2.xml ” 文件是 Axis 2.x
全局描述符,所有的系统级配置都是通过 “ axis2.xml ” 文件完成的。在 “ services” 文件夹是用于存放后缀名为 “
*.aar ” 的服务模块的,在 “ modules ” 文件夹内用于存放后缀名为 “ *.mar ” 的自定义模块的,在 “ pojo ”
文件夹内用于存放传统的 POJO 对象服务文件。 而服务描述符 “services.xml” 文件 与模块描述符
“module.xml”文件则存放于“ \WebRoot\META-INF ” 文件夹当中。
5.3 将传统的 POJO 对象作为服务对象部署
Axis 2.x 为用户提供了最简约的服务部署方式,能把简单的一个 POJO 对象作为服务发布。
首先在一个缺省包里建立一个 POJO 对象,再把被编译后的 Example.class 文件加入到 “\WebRoot\WEB-INF\pojo\” 文件夹内,此时 Example 即会被默认为POJO 服务。
public class Example { public String HelloWorld(String name){ return "Hello "+name; } }
运行程序后,你就可以 http://leslie-laptop:8080/axis2-1.6.2/services/Example?wsdl 上看到 Example 服务的 wsdl 信息。
5.4 以存档文件部署服务
使用 POJO 对象部署服务固然简单,但由于在安全性事务、消息监听等方面缺乏支持,所以 Axis 2.x 更多时候是使用存档文件方式部署服务的。首先在项目内建立服务接口 PersonService 和 服务类PersonServiceImpl。
public class PersonEntity implements Serializable { private Integer id; private String name; private Integer age; private String address; public PersonEntity(Integer id,String name,Integer age,String address){ this.id=id; this.name=name; this.age=age; this.address=address; } public Integer getId(){ return id; } public void setId(Integer id){ this.id=id; } ........ } public interface PersonService { PersonEntity getPerson(int id); PersonEntity[] getList(); List<PersonEntity> getListByName(String name); } public class PersonServiceImpl implements PersonService { @Override public PersonEntity[] getList(){ PersonEntity[] list=new PersonEntity[2]; PersonEntity person1=new PersonEntity(1,"Leslie",32,"tianhe"); PersonEntity person2=new PersonEntity(2,"Elva",31,"henan"); list[0]=person1; list[1]=person2; return list; } @Override public List<PersonEntity> getListByName(String name){ List<PersonEntity> list=new LinkedList<PersonEntity>(); PersonEntity person1=new PersonEntity(1,name+" Lee",32,"tianhe"); PersonEntity person2=new PersonEntity(2,name+" Chen",31,"henan"); list.add(person1); list.add(person2); return list; } @Override public PersonEntity getPerson(int id){ return new PersonEntity(id,"Leslie",32,"tianhe"); } }
在 “ \WebRoot\META-INF ” 文件夹内加入配置文件 services.xml 。当中 ServiceClass 的 parameter 用于绑定服务实现类,而 operation 用于绑定要暴露的服务方法。
Axis 2.x 支持三种信息交换模式,包括 In-Only,Robust-In,In-Out 。In-Only 消息交换模式只接收 SOAP 请求,而无需返还信息;Robust-In 消息交换模式发送SOAP 请求,只有在出错的情况下才返回应答; In-Out 消息交换模式总是对 SOAP 请求返还信息。在服务的
messageReceive 设置中有 RPCMessageReceiver、RawXMLINOutMessageReceiver、RawXMLINOnlyMessageReceiver
等多个选项
可以针对不同 Web 服务方法设置不同的信息交换模式。
<service name="PersonService"> <description>This is a sample Web Service.</description> <!--ServiceClass指定实现服务的类。 --> <parameter name="ServiceClass" locked="false"> axis2.serviceImpl.PersonServiceImpl </parameter> <!-- operation 与Java Class中方法名对应。 --> <operation name="getPerson"> <messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/> </operation> <operation name="getList"> <messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/> </operation> <operation name="getListByName"> <messageReceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/> </operation> </service>
完成配置后,把 “META-INF\services.xml ” 文件(包含文件夹 META-INF)和服务类 PersonEntity.class、PersonService.class、PersonServiceImpl 复制到自定义文件夹 “axis2serivces” 当中。打开命令提示符,进入 axix2services 文件夹输入命令 “ jar cvf axisService.aar . ” (注意:“.” 代表生成包含文件夹所有文件)。最后把 “ axisService.aar ” 文件加入到 “\WebRoot\WEB-INF\services” 文件夹当中,启动 Axis2.x 项目,打开 http://leslie-laptop:8080/axis2-1.6.2/services/PersonService?wsdl 就可看到 PersonService 服务的 wsdl 信息。在 wsdl 中可以看到 axis2 支持 SOAP 1.1、 SOAP 1.2 等多种传输格式。
Axis 2.x 支持多种客户端生成工具,包括原有 WSDL2Java 工具
WSDL2Java -uri http://localhost/axis2-1.6.2/services/PersonSerivce.wsdl
-p 包名 -o 文件夹
还有支持 JAX-WS 的 WsImport 工具
Wsimport -p 包名 -keep -extension http://localhost/axis2-1.6.2/services/PersonSerivce.wsdl
也可使用 MyEclipse 自带的 JAX-WS 客户端生成工具完成。
生成客户端后可以进行测试
public static void main(String[] args) throws MalformedURLException { // TODO Auto-generated method stub getList(); } private static void getList() throws MalformedURLException{ PersonService personService=new PersonService(); PersonServicePortType personServicePortType=personService .getPersonServiceHttpSoap12Endpoint(); List<PersonEntity> personList=personServicePortType.getList(); for(PersonEntity person:personList) displayPersonProperty(person); } private static void displayPersonProperty(PersonEntity person){ System.out.println("Id:"+person.getId().getValue()+" Name:" +person.getName().getValue()+" Age:"+ person.getAge().getValue() +" Address:"+person.getAddress().getValue()); }
测试结果
六、AXIOM 对象模型
6.1 AXIOM 的特点
AXIOM(Axis Object Model, Axis 对象模型)是 Axis 2.x 对 XML 信息处理的核心部分,它把延迟构建和可定制对象模型技术结合起来,极大地提高了 SOAP 信息构建的灵活度。对应 Axis 1.x 的 SAX ( Simple API for XML)推式(Push)解析器,Axis 2.x 使用更具灵活性的 StAX(
Streaming
API for XML )
拉式(Pull)解析器,可尽量减轻对系统资源的压力。在使用推方式(Push)的情况下,系统会先定义数据的处理程序,然后在数据录入时对处理程序进行
回调。然而回调操作只能对录入的数据进行如读取、修改等某些操作,除非引发异常,否则无法左右 XML 文档的录入。而 AXIOM
所使用的拉式(Pull)解析器,实际上是一个高效的迭代器,它使用 XML
树形结构方式,支持延时构建,可以根据需要对文档中的不同部分进行遍历。在大型的 XML 文件中,使用拉式解析器更具吸引力,它可以仅对部分 XML
数据进行处理,剩下的留给解析器完成操作。
在 Web服务开发过程中,大部分的开发人员都是以对象的形式进行信息传递,并使用
WSDL2Java 等工具构建服务代理以实现 XML 数据与对象之间的转换。然而使用此方式限制了Web 服务框架中的数据绑定的灵活程度,利用
AXIOM 的特性更便于 XML 与 Java 对象之间转换,大部分的 JAVA 对象都可以利用 AXIOM 转换成 SOAP 信息。
6.2 AXIOM 的使用方式
AXIOM 建立于 StAX 拉式解析器的基础上,它为开发人员准备了完善的 API ,其中最常用到的是 OMFactory
工厂,它提供了createOMNamespace、createOMElement、createOMAttribute、
createOMDocument、createOMText 等多个方法用于建立 XML 文档信息。在 BeanUtil 类中还包括了
getPullParser、getOMElement、processObject 等多个静态方法用于处理自定义对象与XML之间的转换。
下
面以POCO服务作为一个例子,演示一下 AXIOM 对象绑定方式。在客户端 Web服务分为 SOAP
请求数据绑定与返回信息处理两个阶段,在服务请求阶段系统会把设定的服务地址、传输方式绑定到 ServiceClient 请求对象当中,然后利用
serviceClient.sendReceive 的方法把已定义的 OMElement 对象信息加入到 SOAP
当中发送到服务端。当接收到返回信息后,再把 OMElement 信息转换为对象显示。
public static void main(String[] args) throws AxisFault { excute(); } public static void excute() throws AxisFault{ //设置 endpoint 地址 EndpointReference targetEndpoint=new EndpointReference( "http://leslie-laptop:8080/axis2-1.6.2/services/PersonService"); Options options=new Options(); options.setTo(targetEndpoint); //设置传输方式 //可使用 TRANSPORT_JMS;TRANSPORT_HTTP;TRANSPORT_MAIL;TRANSPORT_TCP; options.setTransportInProtocol(Constants.TRANSPORT_HTTP); //把设置的地址、传输方式绑定到Service请求当中 ServiceClient sender=new ServiceClient(); sender.setOptions(options); //设置请求的 SOAP 信息 OMElement requestOMElement=getPersonRequest(1); OMElement responseOMElement=sender.sendReceive(requestOMElement); //对返回的SOAP进行处理,显示返回值 PersonEntity person=convertToPerson(responseOMElement); displayPersonProperty(person); } private static OMElement getPersonRequest(Integer id){ //新建OMFactory工厂 OMFactory factory=OMAbstractFactory.getOMFactory(); //加入OMNamespace、OMElement、OMText 等数据 OMNamespace omNs=factory.createOMNamespace( "http://ws.apache.org/axis2","myNS"); OMElement value=factory.createOMElement("id",omNs); value.addChild(factory.createOMText(value,id.toString())); //加入请求方法名 OMElement method=factory.createOMElement("getPerson",omNs); method.addChild(value); return method; } //把返回OMElement对象转换成 person对象 private static PersonEntity convertToPerson(OMElement element) throws AxisFault{ PersonEntity person =null; OMElement omElement = element.getFirstElement().getFirstElement(); String localName=omElement.getLocalName().toLowerCase(); if (localName.equals("personentity")) { person = (PersonEntity) BeanUtil.processObject(omElement, PersonEntity.class, null, true, new DefaultObjectSupplier(), null); } return person; } private static void displayPersonProperty(PersonEntity person){ System.out.println("Id:"+person.getId()+" Name:"+person.getName() +" Age:"+ person.getAge() +" Address:"+person.getAddress()); }
发送的 SOAP 请求
在服务端,系统会从发送的SOAP信息中获取请求的 id 值,并通过 BeanUtil.getPullParser 等方法把 personEntity 对象转换成 SOAP 信息返还到客户端。
public class PersonService { public OMElement getPerson(OMElement element){ //获取请求条件 Id Integer id=Integer.valueOf(element.getText()); //模拟返回数据 PersonEntity person=new PersonEntity(id,"Leslie",32,"tianhe"); //把person对象转换为OMElement javax.xml.stream.XMLStreamReader reader=BeanUtil.getPullParser(person); StreamWrapper parser=new StreamWrapper(reader); OMXMLParserWrapper stAXOMBuilder=OMXMLBuilderFactory .createStAXOMBuilder(OMAbstractFactory.getOMFactory(), parser); return stAXOMBuilder.getDocumentElement(); } }
返还的 SOAP 信息
6.3 突显 AXIOM 的优势
在面向对象的 Web服务开发模式下,系统都会利用集成工具进行XML信息与对象的自动化转换。数据的搜索与查找都会在JAVA对象中进行,在信息交换密度频繁的系统当中,这将占用大量内存空间,对系统造成压力。所以,在返回信息中直接对 XML 数据进行拦截、分类、筛选是常用的方法。Axis 2.x 使用更具灵活性的 StAX 拉式解析器,它可以使用虚拟文档的方式构建 XML 树。每个节点都可被视为一个容器 OMContainer,它可以使用 OMContainer.getChildren 方法获取子节点,再以 Iterator 迭代器的方式对节点进行遍历。此外系统还提供了 OMNode.getNextOMSibling、OMNode.getPreviousOMSibling 等多个方法,以进行节点之间的跳转。这意味着它可以跳过其他的子节点,直接找到需要的节点再进行遍历。在数据量较大的系统当中使用此种遍历方式更能突显出 StAX 拉式(Pull)解析器的优势。
以下的例子主要为了展示使用 StAX 拉式解析器进行遍历的方式,BookService 服务主要是根据客户所输入的出版社信息进行查找,然后把该出版社的书本进行按类分配,返还到客户端。下面是服务端的代码:
public class BookEntity { private Integer id; private String title; private String author; private String publishing; private String introduction; private String type; public BookEntity(Integer id,String title,String author ,String type,String publishing,String introduction){ this.id=id; this.title=title; this.author=author; this.type=type; this.publishing=publishing; this.introduction=introduction; } public Integer getId(){ return id; } public void setId(Integer id){ this.id=id; } ........ } public interface BookService { OMElement getList(OMElement element); } public class BookServiceImpl implements BookService{ @Override public OMElement getList(OMElement element) { //获取请求信息 publishing 出版社名称 OMElement child=(OMElement)element.getChildren().next(); String publishing=child.getText(); // 构建 OMFactory 工厂 OMFactory factory=OMAbstractFactory.getOMFactory(); OMNamespace omNamespace=factory.createOMNamespace( "http://serviceImpl.axis2","ns"); //获取计算机类书本子节computerElement List<BookEntity> computerTypeList=getBooks( publishing,"computer"); OMElement computerElement=convertToOMElement( computerTypeList,"computer",omNamespace); //获取文学类书本子节literatureElement List<BookEntity> literatureTypeList=getBooks( publishing,"literature"); OMElement literatureElement=convertToOMElement( literatureTypeList,"literature",omNamespace); //加入多个类型的书本 ........... //构建XML树 OMElement response=factory.createOMElement( "getListResponse",omNamespace); OMElement returnValue=factory.createOMElement ("return",omNamespace); OMElement books=factory.createOMElement( "publishing",omNamespace); books.addAttribute("name", publishing, omNamespace); books.addChild(computerElement); books.addChild(literatureElement); ......... returnValue.addChild(books); response.addChild(returnValue); return response; } //把计算机类书本对象转换为XML信息 private OMElement convertToOMElement(List<BookEntity> list ,String typeName,OMNamespace omNamespace){ OMElement omElement=BeanUtil.getOMElement(new QName("theme") ,list.toArray(),new QName("book"),false,null); omElement.addAttribute("name",typeName,omNamespace); return omElement; } //根据书本类型查找数据 private List<BookEntity> getBooks(String publishing,String type){ List<BookEntity> list=new ArrayList<BookEntity>(); for(BookEntity book:virtualDatabase(publishing)) if(book.getType()=="computer") list.add(book); return list; } //虚拟数据 private List<BookEntity> virtualDatabase(String publishing){ List<BookEntity> list=new ArrayList<BookEntity>(); BookEntity book1=new BookEntity( 1,"Core JAVA Advanced Features","Gary Cornell", "computer",publishing, "Core Java by Cay S. Horstmann and Gary Cornell is a book\n"+ "in the Java series of Sun Microsystems Press, published \n"+ "by Prentice-Hall. The book is aimed at experienced \n"+ "programmers who want to learn how to write useful Java \n" + "applications and applets. No hype, no toy code, no language \n"+ "lawyering, just solid facts and in-depth research to help you \n"+ "write real programs." ); list.add(book1); ........ return list; } }
在配置services.xml文件时,需要把 messageReceiver 设置为 org.apache.axis2.receivers.RawXMLINOutMessageReceiver
<service name="BookService"> <description>This is a sample Web Service.</description> <!--ServiceClass指定实现服务的类。 --> <parameter name="ServiceClass" locked="false">axis2.serviceImpl.BookServiceImpl</parameter> <!-- operation 与Java Class中方法名对应。 --> <operation name="getList"> <messageReceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/> </operation> </service>
返还的 SOAP 信息
在客户端利用 StAX 就可以轻松地对返还数据进行分类处理,例如要在返回数据当中显示计算机类型的Book信息,可以使用 Iterator 方式进行遍历,利用 StaX 推时分析的特点跳过其他类型的节点,直至遇到 ns:name=computer 的节点时,才把该节点的XML树放入容器进行处理。使用此种遍历方式,所占用的内存空间更小,在返回数据量较大的系统当中更能突显其优势。
public static void main(String[] args) throws AxisFault { //设置请求的endpoint地址 EndpointReference targetEndpoint=new EndpointReference( "http://leslie-laptop:8080/axis2-1.6.2/services/BookService"); Options options=new Options(); options.setTo(targetEndpoint); //设置传输方式 //可使用 TRANSPORT_JMS;TRANSPORT_HTTP; //TRANSPORT_MAIL;TRANSPORT_TCP; options.setTransportInProtocol(Constants.TRANSPORT_HTTP); //把设置的地址、传输方式绑定到Service请求当中 ServiceClient sender=new ServiceClient(); sender.setOptions(options); //设置请求的 SOAP 信息,输入出版社名称 OMElement requestOMElement=getBookRequest("China Machine Press"); //发送请求 OMElement responseOMElement=sender.sendReceive(requestOMElement); //遍历返回值,在返回信息中获取computer类的Element OMElement computerBookElement=getComputerElement(responseOMElement); //把XML转换为BookEntity对象集 List<BookEntity> list=convertToBooks(computerBookElement); for(BookEntity book:list) DisplayBook(book); } //把XML数据转换为BookEntity对象集 private static List<BookEntity> convertToBooks(OMElement element) throws AxisFault{ List<BookEntity> list=new ArrayList<BookEntity>(); Iterator books=element.getChildElements(); while(books.hasNext()){ OMElement bookElement=(OMElement)books.next(); BookEntity book=(BookEntity) BeanUtil.processObject(bookElement, BookEntity.class, null, true, new DefaultObjectSupplier(), null); list.add(book); } return list; } //对OMElement元素进行遍历,找到computer类型的节点 private static OMElement getComputerElement(OMElement element){ OMElement returnOMElement=(OMElement)element .getChildElements().next(); OMElement publishingOMElement=(OMElement)returnOMElement .getChildElements().next(); Iterator themes=publishingOMElement.getChildElements(); OMElement theme=null; while(themes.hasNext()){ theme=(OMElement)themes.next(); OMAttribute themeName=(OMAttribute)theme.getAllAttributes().next(); if(themeName.getAttributeValue().equals("computer")) break; } return theme; } //构建请求文档 private static OMElement getBookRequest(String publishing){ //新建OMFactory工厂 OMFactory factory=OMAbstractFactory.getOMFactory(); //绑定OMNamespace,请求数据 OMNamespace omNamespace=factory.createOMNamespace( "http://serviceImpl.axis2","ns"); OMElement value=factory.createOMElement("publishing",omNamespace); value.addChild(factory.createOMText(value,publishing.toString())); //绑定请求方法名 OMElement method=factory.createOMElement("getList",omNamespace); method.addChild(value); return method; } private static void DisplayBook(BookEntity book){ System.out.println("##Id##:"+book.getId()+" ##Title##:"+book.getTitle() +"\n##Author##:"+book.getAuthor()+" ##Type##:"+book.getType() +" ##Publishing##:"+book.getPublishing()+"\n##Introduction##:\n" +book.getIntroduction()+"\n"); }
发送的SOAP请求
显示结果
七、Module 模块独立化处理方式
7.1 Axis 2.x 信息处理流程
Axis 2.x 对信息处理流程
作出了较大幅的修改,在介
绍模块处理结构前,需要简单介绍一下 Axis 2.x 的信息处理机制。Axis 1.x 只接受请求-响应的信息处理模式,而 Axis 2.x
支持 In-Only、In-Out 和 Robust-In 三种消息交换模式。而这三种消息交换机制是建立在 TransportListener 和
TransportSender 之上的,在 SOAP 信息进站时,系统会通过 TransportListener
进行监听。通过一系列处理后,最后会由 TransportSender 进行信息的回送。
系统定义了 InFlow、OutFlow
两种流用于处理服务器端的请求消息和响应消息。而 InFaultFlow、OutFaultFlow
只会在请求或者响应出现错误时才会被调用。当TransportListener 监听到入站信息时会把信息送到 InFlow 流当中,系统可通过修改
“ \WEB-INF\conf\axis2.xml” 配置文件,把多个 Phase 绑定到 InFlow 当中。每个 Phase
相当于一个阶段,同一个阶段
可以绑定多个 Handler 进行处理。数据通过 InFlow
流处理后就会被发送到 MessageReceiver,在 services.xml 中会绑定对应的 MessageReceiver
服务方法。最后通过 OutFlow 流对返回信息进行处理后,由 TransportSender 把 SOAP 响应回发到客户端。
7.2 Module 模块结构
Axis 2.x 把 Handler 放入Module
模块当中,进行了独立化处理。每个 Module 模块是一个容器,当中可以包含多个 Handler
处理程序、第三方库、模块相关资源和模块配置文件。系统把Module 模块定义为后缀名为 “ *.mar ” 的文件,系统可通过 “ jar cvf myModule.mar . ” 命令可以生成 *.mar 的模板文件。
当
中必须包含 module.xml 文件对 Handler 进行部署,否则系统会无法识别此模块。想要在某个 Web服务的 InFlow 流或
OutFlow 流中调用 Module 模块中的 Handler,还需要修改 axis2.xml 文件,在phaseOrder 中加入自定义的
phase, 并绑定 Handler 的处理类。最后修改 “ services.xml ” 文件,在对应此服务配置
中加入<module ref="ModuleName"> 字节 。
下面先以一个简单的例子,说明 Module 模块的使用方式。在例子中将建立一个 MyModule 模块,在模块中加入一个 InputHandler 处理文件对 InFlow 流进行检测。首先建立 org.apache.axis2.modules.Module 的子类 MyModule,此类是用于对模块init 、engageNotify 等事件进行监测的。然后建立 InputHandler 类,此类必须继承 org.apache.axis2.engine.Handler 且实现 org.apache.axis2.engine.Handler.AbstractHandler 接口的 public InvocationResponse invoke(MessageContext context) 方法,此方法的返回值 InvocationResponse 包括 CONTINUE,SUSPEND,ABORT 三个选项,可以"继续"或者"停止"流的执行。
在流输入时此方法将会被自动执行,它所带的 MessageContext 参数对象中将包括此服务的上下文信息。
此例子的主要目的是为开发人员显示一下在 InFlow 流可以获取到的数据信息,所以在此先介绍一下 MessageContext 常用方法:
方法 | 说明 |
getCurrentMessageContext() | 获取当前上下文对象 |
getExecutedPhases() |
获取包含在此流中的 Phase 集合
|
getAxisService() | 获取被调用的 AxisService 服务对象 |
getEnvelope() | 获取 SOAP,在 InFlow 中,此方法将显示该请求的 SOAP 信息 |
getFrom() | 获取客户端地址 |
getTo() | 获取服务地址 |
MessageContext 常用方法
当中 getAxisService 方法所返回的 AxisService 对象正是当前被调用的 Web服务对象。
方法 | 说明 |
getOperationContext() | 返回当前被调用的 OperationContext 上下文对象 |
getOperations() | 返回此服务所包含的所有 Operation 对象 |
getParameters() | 返回此服务的所包含的所有 Parameters 对象 |
getFileName() | 返回此*.aar 服务文件路径 |
getTargetNamespace() | 返回此服务的 targetNamespace 名称 |
getEndpointName() | 返回此服务的 Endpoint 名称 |
AxisService 常用方法
public class MyModule implements Module{ @Override public void applyPolicy(Policy arg0, AxisDescription arg1) throws AxisFault { // TODO Auto-generated method stub } @Override public boolean canSupportAssertion(Assertion arg0) { // TODO Auto-generated method stub return false; } @Override public void engageNotify(AxisDescription arg0) throws AxisFault { // TODO Auto-generated method stub } @Override public void init(ConfigurationContext arg0, AxisModule arg1) throws AxisFault { // TODO Auto-generated method stub } @Override public void shutdown(ConfigurationContext arg0) throws AxisFault { // TODO Auto-generated method stub } } public class InputHandler extends AbstractHandler implements Handler{ public InvocationResponse invoke(MessageContext context){ //显示当前上下文信息 System.out.println("##from:##\n "+context.getFrom() +"\n##to:##\n "+context.getTo()); //显示所执行的phase信息 phasesMessageDisplay(context.getExecutedPhases()); //显示服务对象信息 AxisService axisService=context.getAxisService(); serviceMessageDisplay(axisService); //显示当前operation信息 AxisOperation operation=context.getOperationContext().getAxisOperation(); currentOperationDisplay(operation); //显示服务的所有operation信息 operationsMessageDisplay(axisService.getOperations()); //显示服务参数parameters信息 parametersMessageDisplay(axisService.getParameters()); return InvocationResponse.CONTINUE; } //显示所执行的phases private void phasesMessageDisplay(Iterator<Handler> iterator){ String data="##phaseList:##\n"; while(iterator.hasNext()){ Handler handler=(Handler)iterator.next(); data+=" "+handler.getName(); } System.out.println(data); } //显示服务信息 private void serviceMessageDisplay(AxisService axisService){ System.out.println("\n##serviceFile:##\n "+axisService.getFileName()+ "\n##targetNamespace:##\n "+axisService.getTargetNamespace()+ "\n##endpointName##:\n "+axisService.getEndpointName()+"\n"); } //显示当前Operation信息 private void currentOperationDisplay(AxisOperation operation){ System.out.println("##currentOperation:##\n name:" +operation.getName().getLocalPart()+"\n messageReceive:" +operation.getMessageReceiver().toString()+"\n"); } //显示服务的所有Operation信息 private void operationsMessageDisplay(Iterator operations){ while(operations.hasNext()){ AxisOperation operation=(AxisOperation)operations.next(); System.out.println("##operation:##\n name:" +operation.getName().getLocalPart()+"\n messageReceive:" +operation.getMessageReceiver().toString()); } System.out.println(); } //显示parameter信息 private void parametersMessageDisplay(List<Parameter> parameters){ for(Parameter parameter:parameters){ System.out.println("##parameter:##\n name:"+parameter.getName() +"\n value:"+parameter.getValue().toString()); } } }
在 “ \WebRoot\META-INF\ ” 内加入 “ module.xml ” 配置文件
<module name="myModule" class="axis2.module.MyModule"> <InFlow> <handler name="inputHandler" class="axis2.handler.InputHandler"> <order phase="orderInPhase"/> </handler> </InFlow> </module>
把 “module.xml ” 配置文件(包含 “ META-INF ”文件夹)和编译后的 MyModule.class、InputHandler.class 加入到自定义文件夹,使用命令提示符进行入自定义文件夹内输入 “ jar cvf myModule.mar . ” 命令生成 “ myModule.mar ” 包,把生成的包加入 “\WEB-INF\ modules ” 文件夹内。
最后修改 “ \WEB-INF\conf\axis2.xml” 配置文件,加入自定义的 phase 配置。此时重启系统,即完成了 myModule.mar 自定义模块的配置。
注意:
自定义 handler 可以在 axis2.xml 或者 module.xml 中进行绑定。
axis2.xml 中所配置的是全局变量,如果直接在 axis2.xml 文件中加入对 handler 进行绑定,那所有的服务在 InFlow 和 OutFlow 中都执行此 handler。
如
果只在 axis2.xml 中建立自定义 phase,然后在 module.xml 中绑定 handler,那只有在服务绑定此 module
时,该 handler 才会被执行 。配置应该按需要而定,一般只有登录、日志记录、系统信息监视等 handler 才会在 axis2.xml
中直接绑定。
<phaseOrder type="InFlow"> <phase name="orderInPhase"> <handler name="inputHandler" class="axis2.handler.InputHandler"/> </phase> </phaseOrder>
想要在某 Web 服务中调用此模块,只需要修改对应的 services.xml 配置文件,在服务配置内加入“ <module ref=‘myModule’ /> ” 字节即可。
<service name="PersonService"> <description>This is a sample Web Service.</description> <!--使用myModule模块--> <module ref="myModule"/> <!-- ServiceClass指定实现服务的类。 --> <parameter name="ServiceClass" locked="false">axis2.serviceImpl.PersonServiceImpl</parameter> <!-- operation 与Java Class中方法名对应。 --> <operation name="GetPerson"> <messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/> </operation> <operation name="GetList"> <messageReceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/> </operation> <operation name="GetListByName"> <messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/> </operation> </service>
在启动此Web服务,调用 GetPerson 服务方法时,InputHandler 将会对服务流进行处理,显示测试结果:
7.3 Module 实用方式
以上对 Module
的使用方式进行了简单的介绍,下面想以一个更为实际的订单管理例子介绍一下 Module
的用途。在Web服务项目当中,很多的服务在操作前都需要先进行登录验证,所以下面例子当中会把用户登录功能独立开来,作为一个自定义 Handler
置于模块当中,这样可以使登录服务的功能更为独立,易于管理。用户在调用 OrderService 服务时,会先在头文件中加入用户信息,
在服务端接收到 SOAP 请求时,在 InFlow 流中加入 OrderInputHandler
进行处理,获取头文件信息进行登录,登录成功就会在 Session 中记录 User 对象信息。
像 Order
管理这类服务中,订单费用的计算往往是一个长期不变的规则,但销售商很多时候会进行产品的抽奖,优惠等销售策略,这些策略都是短期的,具有多变性。如果直
接把这些业务规则写入 OrderService 服务中,OderService 就会经常需要修改。此时,可以尝试利用 OutFlow 流 ,建立
OrderOutputHandler 对完成操作的 Order 进行检测。若通过得奖规则,则在SOAP返还信息的头文件中加入奖励信息。
由于本节的目的主要是为了展示 Module 的独立性与灵活性,所以省略了 OrderManager、UserManager、FavourableManager 等操作对象。
首先建立 OrderInputHandler 在 SOAP 信息进入 InFlow 流时进行登录处理。
然后建立 OrderOutputHandler 在 SOAP 信息进行 OutFlow 时对已处理Order对象进行检测。
public class MyModule implements Module{ @Override public void applyPolicy(Policy arg0, AxisDescription arg1) throws AxisFault { // TODO Auto-generated method stub } @Override public boolean canSupportAssertion(Assertion arg0) { // TODO Auto-generated method stub return false; } @Override public void engageNotify(AxisDescription arg0) throws AxisFault { // TODO Auto-generated method stub } @Override public void init(ConfigurationContext arg0, AxisModule arg1) throws AxisFault { // TODO Auto-generated method stub } @Override public void shutdown(ConfigurationContext arg0) throws AxisFault { // TODO Auto-generated method stub } } public class OrderInputHandler extends AbstractHandler implements Handler { public InvocationResponse invoke(MessageContext context){ //判断被调用的是否OrderSerivce的addOrder方法 if(context.getOperationContext().getAxisOperation() .getName().getLocalPart().equals("addOrder")){ //获取头文件信息 SOAPHeader head=context.getEnvelope().getHeader(); //把头文件信息转换成User对象进行登录 String[] userMes=head.getFirstElement().getText().split(","); //用户登录 UserEntity user=UserManager.Login(userMes[0],userMes[1]); ....... if(user!=null){ //登录成功记录User SessionContext session=context.getSessionContext(); if(session.getProperty("User")==null) session.setProperty("User", user); } } return InvocationResponse.CONTINUE; } } public class OrderOutputHandler extends AbstractHandler implements Handler{ public InvocationResponse invoke(MessageContext context){ //判断被调用的是否OrderSerivce的addOrder方法 if(context.getOperationContext().getAxisOperation() .getName().getLocalPart().equals("addOrder")){ //获取返回信息的SOAPBody,判断订单总体价格是否高于 200 dollar SOAPBody body=context.getEnvelope().getBody(); OMElement element=body.getFirstElement(); try { OrderEntity order = (OrderEntity) BeanUtil.processObject(element, OrderEntity.class, null, true, new DefaultObjectSupplier(), null); //总体价格高于 200 dollar的订单在头文件中输入获奖信息 if(order.getTotalPrice()>200){ //在数据库中记录获奖订单 Favourable favourable=FavourableManager.addOrder(order); ....... //修改头文件,加入获奖信息 setHead(context.getEnvelope().getHeader(),favourable); } catch (AxisFault e) { e.printStackTrace(); } } return InvocationResponse.CONTINUE; } //修改头文件,加入获奖信息 private void setHead(SOAPHeader head,favourable){ OMFactory factory=OMAbstractFactory.getOMFactory(); OMNamespace omNamespace=factory.createOMNamespace( "http://serviceImpl.axis2","ns"); OMElement element=factory.createOMElement("favourable",omNamespace); element.setText("Congratulations! Price is higher than 200 dollar ......"); //加入favourable 信息 ......... head.addChild(element); } } public class OrderEntity implements Serializable { private Integer id; private String orderCode; private Double totalPrice; ......... public OrderEntity(Integer id,String orderCode,Double totalPrice,........){ this.id=id; this.orderCode=orderCode; this.totalPrice=totalPrice; ........ } .......... }
完成自定义Handler后,进行 module.xml 配置,分别在 InFlow 流 OutFlow 绑定 OrderInputHandler 和 OrderOutputHandler
<module name="myModule" class="axis2.module.MyModule"> <InFlow> <handler name="orderInputHandler" class="axis2.handler.OrderInputHandler"> <order phase="orderInPhase"/> </handler> </InFlow> <OutFlow> <handler name="orderOutputHandler" class="axis2.handler.OrderOutputHandler"> <order phase="orderOutPhase"/> </handler> </OutFlow> </module>
修改 axis2.xml 文件,建立自定义的 phase ,在 InFlow 流和 OutFlow 流中加入 orderInPhase 和 orderOutPhase 。
<phaseOrder type="InFlow"> <phase name="orderInPhase"/> </phaseOrder> <phaseOrder type="OutFlow"> <!-- 调用自定义模块进行处理 --> <phase name="orderOutPhase"/> </phaseOrder>
建立 Web 服务OrderService ,当调用 addOrder 前先检测用户是否登录成功,若用户未登录则释放出异常。若登录成功,把输入的Order对象加入数据库,然后把处理后的 Order 转换为OMElement 返还到客户端。
public interface OrderService { OMElement addOrder(OMElement element) throws Exception; } public class OrderServiceImpl implements OrderService{ @Override public OMElement addOrder(OMElement element) throws Exception{ //验证是否登录成功 if(isLogged()){ //把订单加入数据库,把更新后的订单返回客户端 OrderEntity order = (OrderEntity) BeanUtil.processObject( element.getFirstElement(),OrderEntity.class, null, true, new DefaultObjectSupplier(), null); //加入订单,计算总体价格,Code号码等信息 OrderEntity orderRefresh=OrderManager.addOrder(order); ....... //把修改后order对象转换为OMElement XMLStreamReader reader=BeanUtil.getPullParser(orderRefresh); StreamWrapper parser=new StreamWrapper(reader); OMXMLParserWrapper stAXOMBuilder=OMXMLBuilderFactory .createStAXOMBuilder(OMAbstractFactory.getOMFactory(), parser); return stAXOMBuilder.getDocumentElement(); } else throw new Exception(); } //验证用户是否已经登录 private boolean isLogged(){ MessageContext context=MessageContext.getCurrentMessageContext(); SessionContext session=context.getSessionContext(); return session.getProperty("User")!=null; } }
在 services.xml 文件加入 module 节点
<service name="OrderService"> <description>This is a sample Web Service.</description> <module ref="myModule"/> <!-- ServiceClass指定实现服务的类。 --> <parameter name="ServiceClass" locked="false"> axis2.serviceImpl.OrderServiceImpl </parameter> <!-- operation 与Java Class中方法名对应。 --> <operation name="addOrder"> <messageReceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/> </operation> </service>
在客户端发送 OrderService.addOrder 请求时,在头文件加入用户userName,password等资料。为了在使用Session存储User对象,需要在客户端使用 options.setManageSession(bool)方法打开 sessionContext 。由于使用方式与 Axis1.x 较为相像,在此不再详细说明了。
public static void main(String[] args) throws RemoteException, OrderServiceExceptionException { // TODO Auto-generated method stub excute(); } public static void excute() throws AxisFault{ EndpointReference targetEndpoint=new EndpointReference( "http://leslie-laptop:8080/axis2-1.6.2/services/OrderService"); Options options=new Options(); options.setManageSession(true); options.setTo(targetEndpoint); //设置传输方式 //可使用 TRANSPORT_JMS;TRANSPORT_HTTP; //TRANSPORT_MAIL;TRANSPORT_TCP; options.setTransportInProtocol(Constants.TRANSPORT_HTTP); //把设置的地址、传输方式绑定到Service请求当中 ServiceClient sender=new ServiceClient(); sender.setOptions(options); //设置请求的 SOAP 信息 OMElement requestOMElement=getOrderRequest( new OrderEntity(-1,null,200.5,......)); //在头文件中加入用户资料 sender.addHeader(setHead()); OMElement responseOMElement=sender.sendReceive(requestOMElement); //对返回的SOAP进行处理,显示返回值 OrderEntity order=convertToOrder(responseOMElement); displayOrderProperty(order); } //在头文件中加入用户资料 private static OMElement setHead(){ //新建OMFactory工厂 OMFactory factory=OMAbstractFactory.getOMFactory(); //绑定OMNamespace,请求数据 OMNamespace omNamespace=factory.createOMNamespace( "http://serviceImpl.axis2","ns"); //加入用户资料 OMElement user=factory.createOMElement("User",omNamespace); user.setText("Leslie,12345678"); return user; } private static OMElement getOrderRequest(OrderEntity order){ //新建OMFactory工厂 OMFactory factory=OMAbstractFactory.getOMFactory(); //绑定OMNamespace OMNamespace omNamespace=factory.createOMNamespace( "http://serviceImpl.axis2","ns"); //绑定请求方法名 OMElement method=factory.createOMElement("addOrder",omNamespace); //把order对象转换为OMElement javax.xml.stream.XMLStreamReader reader=BeanUtil.getPullParser(order); StreamWrapper parser=new StreamWrapper(reader); OMXMLParserWrapper stAXOMBuilder=OMXMLBuilderFactory .createStAXOMBuilder(OMAbstractFactory.getOMFactory(), parser); OMElement param=stAXOMBuilder.getDocumentElement(); method.addChild(param); return method; } //把返回OMElement对象转换成 person对象 private static OrderEntity convertToOrder(OMElement element) throws AxisFault{ OrderEntity order =null; OMElement omElement = element.getFirstElement().getFirstElement(); String localName=element.getLocalName().toLowerCase(); if (localName.equals("orderentity")) { order = (OrderEntity) BeanUtil.processObject(element, OrderEntity.class, null, true, new DefaultObjectSupplier(), null); } return order; } //显示Order数据 private static void displayOrderProperty(OrderEntity order){ System.out.println("Id:"+order.getId()+" Code:"+order.getOrderCode() +" TotalPrice:"+ order.getTotalPrice()); }
八、异步调用Web服务
在 Axis 1.x 中服务只支持 “请求-回复”
的操作方式,客户端在发送请求后将处于等待的状态,在Web服务操作时间较长的情况下,这种操作方式将影响了系统的效率。从 Axis 2.x
开始客户端支持异步操作的方式,在发送请求后,系统将使用异步线程绑定回调操作。在发出请求后,客户端无需再处理于长期等待的状态。生成异步操作的方法有
很多,比较简单的是使用 WSDL2Java 的 “-a” 命令:
WSDL2Java -uri http://localhost/axis2-1.6.2/services/PersonSerivce.wsdl
-p 包名 -o 文件夹 -a
所生成的客户端会包含一个 ServiceCallbackHandler 类,下面的例子当中,只要实现了 PersonServiceCallbackHandler 类的 receiveResultgetList
方法,在调用 personServiceStub.startgetList(PersonServiceStub.GetList
, PersonServiceCallbackHandler)方法后,系统将释放主线程。当接收到服务端的返还信息后,信息将交由
PersonServiceCallbackHandler 所绑定的方法进行处理。
服务端
public class PersonService{ public List<PersonEntity> getList(){ List<PersonEntity> list=new ArrayList<PersonEntity>(); list.add(new PersonEntity(1,"Leslie",32,"tianhe")); list.add(new PersonEntity(2,"Elva",28,"henan")); return list; } }
客户端
public static void main(String[] args) throws InterruptedException, RemoteException { // TODO Auto-generated method stub threadMessage("start "); //建立服务对象 PersonServiceStub personService=new PersonServiceStub(); PersonServiceStub.GetList getList=new PersonServiceStub.GetList(); //建立回调函数 PersonServiceCallbackHandler callback=new PersonServiceCallbackHandler(){ public void receiveResultgetList(GetListResponse response){ threadMessage("callback "); PersonEntity[] list=response.get_return(); for(Integer n=0;n<list.length;n++) displayPersonProperty(list[n]); } }; //启动异步服务 personService.startgetList(getList,callback); Thread.sleep(500); } //显示线程id private static void threadMessage(String data){ Thread thread=Thread.currentThread(); System.out.println(data +"threadId: "+thread.getId()); } //显示对象信息 private static void displayPersonProperty(PersonEntity person){ System.out.println("Id:"+person.getId() +" Name:" +person.getName() +" Age:"+ person.getAge() +" Address:"+person.getAddress() ); }
测试结果
本章小结
Aixs 的主要特点在于其操作的灵活性,它能对请求和回发的 SOAP 信息直接进行处理,在头文件或者自定义节点中加入数据。特别在Axis 2.x 引入 AXIOM 后,其优点更为突出。它使用 StAX(
Streaming
API for XML ) 拉式(Pull)解析器,可尽量减轻对系统资源的压力。Axis 2.x 使用 Module
模块化的部署方式,使系统功能分割更为简单, Module 可以独立于服务进行开发。为了解决客户端为等待返回数据而长时间处于柱塞状态,Axis
2.x 还加入异步操作的方法,提高了客户端的运行效率。
由于本人并非 JAVA 方面的专家,文章难免存在错误之处,敬请读者点评。
评论
谢谢支持,我会继续努力的!
多谢支持
相关推荐
Java远程通信技术——Axis实战.doc
然而,需要注意的是,尽管Axis1功能强大,但随着技术的发展,更现代的框架如JAX-WS(Java API for XML Web Services)和Spring-WS已经提供了更高级的功能和更好的性能。 总结一下,"webServices学习之二——axis1...
Web服务在IT行业中扮演着重要的角色,它允许不同的应用程序通过网络进行通信和交换数据。...随着技术的发展,如RESTful API的流行,理解SOAP和Axis1可以帮助我们更好地理解和适应各种Web服务解决方案。
在软件开发领域,特别是在企业级应用中,Web服务作为一种标准的技术规范被广泛采用,它允许不同系统间进行通信与数据交换。Java Web Service 是基于Java技术构建的一种Web服务实现方式,它遵循一系列标准协议(如...
AXIS2远程调用WebService是Java开发者在进行分布式服务交互...理解并掌握这些步骤,你就可以自如地在Java环境中使用WebService进行远程通信了。在实际项目中,可能还需要考虑安全性、性能优化以及错误处理等更多细节。
总的来说,Java和Axis2的结合提供了一种强大而灵活的方式来调用Web服务,允许开发者轻松地集成远程功能到自己的应用程序中。通过理解这些概念和实践,你可以更好地利用Web服务接口,提升应用的扩展性和互操作性。
axis2根据wsdl生成java客户端代码 D:\Software\axis2-1.6.2\bin>wsdl2java.bat -uri http://10.33.30.216:9099/facs/services/ResourceSynchroWebService?wsdl -o E:\wsdloutput -p com.util wsdl2java.bat -uri ...
Java Web服务(Web Service)是一种基于开放...通过理解以上概念和流程,你可以构建和使用基于Java和Axis的Web服务,实现跨平台、跨系统的应用间通信。这个例子提供了一个很好的起点,让你深入理解Web服务的实现细节。
Java Axis WebService 开发实例详解 在Java世界中,开发Web服务时,Axis是一个非常流行的开源工具,它允许开发者创建、部署和使用Web服务。本实例将深入探讨如何使用Axis来构建一个简单的Web服务,并进行调用。这个...
根据提供的标题、描述、标签及部分内容,我们可以提炼出与 Axis 相关的 Java 知识点,主要包括 Axis 的安装配置、基本使用流程以及部署服务等内容。 ### 一、Axis 简介 #### 1.1 Axis 是什么? Axis 是 Apache ...
Eclipse Java Axis2 是一个基于Java的Web服务开发框架,由Apache软件基金会开发。它主要用于构建和部署SOAP(简单对象访问协议)Web服务。在Java环境中,Eclipse作为流行的集成开发环境(IDE),提供了强大的支持来...
标题中的“axis2学习——开发自定义的axis2服务”表明了本文主要涉及Apache Axis2框架,这是一个用于构建Web服务和SOA(Service-Oriented Architecture)应用的开放源码平台。Axis2允许开发者创建、部署和管理服务,...
这篇博客"axis2学习——客户端的开发"主要探讨了如何使用Axis2来创建和操作Web服务的客户端。 首先,让我们了解什么是Apache Axis2。Axis2是Axis1的下一代版本,它提供了更高效、更灵活的服务框架。它是基于模块化...
在IT行业中,Web服务是不同系统之间进行通信和数据交换的一种常见方式。WS-DL(Web Service Description Language)文件是一种XML格式,用于定义Web服务的接口、操作和消息结构。当我们需要与一个由WS-DL描述的服务...
Java Axis2 WebService 实现详解 在Java世界中,创建和使用Web服务是一个常见的任务,而Axis2是Apache软件基金会开发的一个高效的Web服务框架。它提供了丰富的功能,使得开发、部署和管理Web服务变得简单易行。本篇...
axis2-1.6.2.zip, windows axis2工具,根据 WSDL生成java文件。 1、axis2客户端下载地址:http://mirror.esocc.com/apache//axis/axis2/java/core/1.6.2/axis2-1.6.2-bin.zip; 2、下载解压在D:\Work_Program_...
Java的Web服务(Web Service)是一种基于开放标准的、平台无关的通信协议,它允许不同系统之间进行数据交换。在Java中,Apache Axis2是一个强大的Web服务引擎,它提供了高效且灵活的服务创建和部署机制。本篇文章将...