SOAP、WSDL、UDDI,这些名词相信只要了解过 Web Service 的都不陌生,根据 Apache 的定义,Axis 是一种 W3C SOAP 实现,国内有些介绍还特别注明了:Axis 并不完全是 SOAP 引擎,它还包括独立的 SOAP 服务器、嵌入 Servlet 引擎的服务器、支持 WSDL 并提供转化 WSDL 为 Java 类的工具、例子程序、TCP/IP 数据包监视工具,等等。Axis 部署 Web Serive 有两种方式,最简单的是拷贝 java 源代码文件到 web 文件夹下把扩展名改为 .jws 直接调用,可参考这篇文章: 用Axis 1.1 for Java进行Web Services开发(1)。另一种方式是通过 WSDD(Web Services描述文档)部署,可参考: 使用Axis发布简单的Web服务。在我的应用中,使用的是后者,以便 Axis 进行自动序列化/反序列化处理。
实现一次 SSO 登陆验证,最少要传入用户名、密码。为了达到这种目的,在客户端我们构造 User 对象(本文中 User 对象仅包含用户名和密码),并通过 Axis 自动序列化传递出去;到了 SSO 端,Axis 自动反序列化之后还原成 User 对象;最后返回给客户端说明本次登陆的结果,返回的结果不仅仅包含例如“登陆成功”之类的简单信息,也许还有很多其他信息,看来创建一个叫做 Respond 的对象(本文中 Respond 对象仅包含登陆 ID 和结果描述)很有必要了,把 Respond 传回给客户端说明登陆结果。
暴露给客户端供登陆验证的服务类是 AuthService。该类代码简单表示如下:
public
class
AuthService {
/**
* 验证用户名和密码
*
@param
String userName 用户名
*
@param
String passWord 密码
*
@return
Respond 登陆验证后返回
*/
public
Respond login(User user){
String name
=
user.getName();
String password
=
user.password();
//
进行数据库验证
//
..
//
Respond respond
=
new
Respond();
respond.setId(
"
123
"
);
respond.setDesc(
"
登陆成功
"
);
return
respond;
}
}
User 和 Respond 以及服务类都写好了。通过命令行方式,我生成了 server-config.wsdd,内容如下:
<?
xml version="1.0" encoding="UTF-8"
?>
<
deployment
xmlns
="http://xml.apache.org/axis/wsdd/"
xmlns:java
="http://xml.apache.org/axis/wsdd/providers/java"
>
<
globalConfiguration
>
<
parameter
name
="sendMultiRefs"
value
="true"
/>
<
parameter
name
="disablePrettyXML"
value
="true"
/>
<
parameter
name
="adminPassword"
value
="admin"
/>
<
parameter
name
="attachments.Directory"
value
="D:/workspace/SSO/web/WEB-INF/attachments"
/>
<
parameter
name
="dotNetSoapEncFix"
value
="true"
/>
<
parameter
name
="enableNamespacePrefixOptimization"
value
="true"
/>
<
parameter
name
="sendXMLDeclaration"
value
="true"
/>
<
parameter
name
="sendXsiTypes"
value
="true"
/>
<
parameter
name
="attachments.implementation"
value
="org.apache.axis.attachments.AttachmentsImpl"
/>
<
requestFlow
>
<
handler
type
="java:org.apache.axis.handlers.JWSHandler"
>
<
parameter
name
="scope"
value
="session"
/>
</
handler
>
<
handler
type
="java:org.apache.axis.handlers.JWSHandler"
>
<
parameter
name
="scope"
value
="request"
/>
<
parameter
name
="extension"
value
=".jwr"
/>
</
handler
>
</
requestFlow
>
</
globalConfiguration
>
<
handler
name
="LocalResponder"
type
="java:org.apache.axis.transport.local.LocalResponder"
/>
<
handler
name
="URLMapper"
type
="java:org.apache.axis.handlers.http.URLMapper"
/>
<
handler
name
="Authenticate"
type
="java:org.apache.axis.handlers.SimpleAuthenticationHandler"
/>
<
service
name
="AuthService"
provider
="java:RPC"
>
<
parameter
name
="allowedMethods"
value
="*"
/>
<
parameter
name
="className"
value
="com.cdmcs.sso.AuthService"
/>
<
beanMapping
languageSpecificType
="java:sso.Respond"
qname
="ns:resp"
xmlns:ns
="urn:BeanService"
/>
<
beanMapping
languageSpecificType
="java:sso.User"
qname
="ns:user"
xmlns:ns
="urn:BeanService"
/>
</
service
>
<
service
name
="AdminService"
provider
="java:MSG"
>
<
parameter
name
="allowedMethods"
value
="AdminService"
/>
<
parameter
name
="enableRemoteAdmin"
value
="false"
/>
<
parameter
name
="className"
value
="org.apache.axis.utils.Admin"
/>
<
namespace
>
http://xml.apache.org/axis/wsdd/
</
namespace
>
</
service
>
<
service
name
="Version"
provider
="java:RPC"
>
<
parameter
name
="allowedMethods"
value
="getVersion"
/>
<
parameter
name
="className"
value
="org.apache.axis.Version"
/>
</
service
>
<
transport
name
="http"
>
<
requestFlow
>
<
handler
type
="URLMapper"
/>
<
handler
type
="java:org.apache.axis.handlers.http.HTTPAuthHandler"
/>
</
requestFlow
>
<
parameter
name
="qs:list"
value
="org.apache.axis.transport.http.QSListHandler"
/>
<
parameter
name
="qs:wsdl"
value
="org.apache.axis.transport.http.QSWSDLHandler"
/>
<
parameter
name
="qs.list"
value
="org.apache.axis.transport.http.QSListHandler"
/>
<
parameter
name
="qs.method"
value
="org.apache.axis.transport.http.QSMethodHandler"
/>
<
parameter
name
="qs:method"
value
="org.apache.axis.transport.http.QSMethodHandler"
/>
<
parameter
name
="qs.wsdl"
value
="org.apache.axis.transport.http.QSWSDLHandler"
/>
</
transport
>
<
transport
name
="local"
>
<
responseFlow
>
<
handler
type
="LocalResponder"
/>
</
responseFlow
>
</
transport
>
</
deployment
>
要说明的是,深究上述配置文件具体含义不是本文的目的,要对其具体了解,请参考 Axis 文档。其中,只有下面的 XML 才是我们感兴趣的:
<service name="AuthService" provider="java:RPC">
<parameter name="allowedMethods" value="*"/>
<parameter name="className" value="com.cdmcs.sso.AuthService"/>
<beanMapping languageSpecificType="java:sso.Respond" qname="ns:resp" xmlns:ns="urn:BeanService"/>
<beanMapping languageSpecificType="java:sso.bo.User" qname="ns:user" xmlns:ns="urn:BeanService"/>
</service>
注:sso.Respond 为要注册的类,全路径和类名
为了完成自动序列化/反序列化,我们使用“beanMapping”元素指定要进行处理的 bean 文件。只有在 WSDD 中定义了这些,才能享受到 Axis 带来的自动序列化/反序列化优势。
客户端代码:
public
class
TestClient {
public
static
void
main(String[] args) {
try
{
String endpoint
=
"
http://127.0.0.1:8080/services/AuthService?wsdl
"
;
Service service
=
new
Service();
Call call
=
(Call) service.createCall();
QName qn
=
new
QName(
"
urn:BeanService
"
,
"
resp
"
);
QName qx
=
new
QName(
"
urn:BeanService
"
,
"
user
"
);
//
注册 bean
call.registerTypeMapping(Respond.
class
,qn,
new
BeanSerializerFactory(Respond.
class
, qn),
new
BeanDeserializerFactory(Respond.
class
, qn));
call.registerTypeMapping(User.
class
,qx,
new
BeanSerializerFactory(User.
class
, qx),
new
BeanDeserializerFactory(User.
class
, qx));
call.setTargetEndpointAddress(
new
java.net.URL(endpoint));
call.setOperationName(
new
QName(
"
http://soapinterop.org/
"
,
"
login
"
));
User user
=
new
User();
mul.setName(
"
test
"
);
mul.setPassword(
"
test
"
);
Respond respond
=
(Reopond) call.invoke(
new
Object[] {user});
System.out.println(
"
登陆,返回'
"
+
respond.getDesc()
+
"
'。
"
);
}
catch
(Exception e) {
e.printStackTrace();
}
}
}
正如我们期望的,打印出“登陆成功”。通过上面的范例,我们发现,Axis 的自动序列化/反序列化机制还是很方便的,除了 bean 以外,其他类型的对象也可以让 Axis 来完成,具体参考 Axis 文档,如果要传递的对象 Axis 未提供自动序列化/反序列化支持,请考虑人工实现,参考: 深度编程Axis序列化/反序列化器开发指南。