资源描述
AXIS学习笔记(一)
作者: ∣来源:JavaResearch∣原文地址∣2005-6-9
前天头告诉我用SOAP WEB服务开发一个客户程序,用来与企业内部的ERP进行交互。晚上赶快找相关的资料猛看,总算对SOAP有了一定的认识。干程 序员这行真不容易,好象得不停地学习新东西,一不小心就被淘汰:(不过学习也是个很有意思的事情。好了,废话少说,让我们开始吧。
一、软件环境
1、axis-1_2 (从apache网站下载最新axis-bin-1_2.zip解压即可)
2、Tomcat5.0
3、JDK5.0
二、相关配置
1、在你的%TOMCAT_HOME%\common\lib下需要加入三个包 activation.jar、mail.jar、tools.jar
2、环境变量设置
AXIS_HOME 即axis-bin-1_2.zip解压的目录(我的是在F:\soap\axis-1_2)
AXIS_LIB 即 %AXIS_HOME%\lib
AXISCLASSPATH 即 %AXIS_LIB%\axis.jar;%AXIS_LIB%\commons-discovery- 0.2.jar;%AXIS_LIB%\commons-logging-1.0.4.jar;%AXIS_LIB% \jaxrpc.jar;%AXIS_LIB%\saaj.jar;%AXIS_LIB%\log4j-1.2.8.jar;也就是 把%AXIS_LIB%下所用JAR文件都导入
三、实验一下
在%AXIS_HOME%\webapps下找到axis文件夹,将其整个拷贝到%TOMCAT_HOME%\webapps下,启动
Tomcat,打开浏览器访问http://localhost:8080/axis/,出现以下页面说明你配置成功了。很简单吧:)
四、发布我们的第一个程序
第一个程序简单的返回HELLO WORLD!
HelloWorld.java
public class HelloWorld {
public String sayHello()
{
return "HELLO WORLD!";
}
}
我们的第一种发布方式:
将HelloWorld.java拷贝到%TOMCAT_HOME%\webapps\axis下,然后将其改名为HelloWorld.jws,这样 AXIS就自然将其发布了。现在写个客户端程序访问一下:
TestClient.java
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import javax.xml.rpc.ParameterMode;
public class TestClient
{
public static void main(String [] args) throws Exception {
String endpoint = "http://localhost:" +"8080"+ "/axis /HelloWorld.jws";//指明服务所在位置
Service service = new Service(); //创建一个Service实例,注意是必须的!
Call call = (Call) service.createCall();//创建Call实例,也是必须的!
call.setTargetEndpointAddress( new .URL(endpoint) );//为Call 设置服务的位置
call.setOperationName( "sayHello" );//注意方法名与HelloWorld.java中一样!!
String res = (String) call.invoke( new Object[] {} );//返回 String,没有传入参数
System.out.println( res );
}
}
我的测试是在jbuilder2005中,注意项目中要导入其自带的AXIS包(当然应该把其中JAR文件替换一下),可以看到程序返回 了 "HELLO WORLD!"
可以看到在AXIS里发布服务其实是一件很容易的事,这是因为这个服务很简单的原因:)下面我们介绍第二种发布方式,这是常用的。
我们的第二种发布方式:
1、将HelloWorld.java编译成HelloWorld.class,放到%TOMCAT_HOME%\webapps\axis\WEB- INF\classes
下
2、在%TOMCAT_HOME%\webapps\axis\WEB-INF下新建deploy.wsdd文件,即SOAP服务发布描述文件
deploy.wsdd
<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<service name="HelloWorld" provider="java:RPC">
<parameter name="className" value="HelloWorld"/>
<parameter name="allowedMethods" value="sayHello"/>
</service>
</deployment>
在DOS下转换目录到%TOMCAT_HOME%\webapps\axis\WEB-INF,命令:
java -cp %AXISCLASSPATH% org.apache.axis.client.AdminClient deploy.wsdd
你会发现目录下多了一个server-config.wsdd文件,这就是AXIS的配置文件,以后所有的服务发布描述都会在里面找到。(当然,你可以直 接修改它,不用再写deploy.wsdd)然后打开浏览器http://localhost:8080/axis/servlet /AxisServlet,你就会看到你的服务已发布
同样用客户端程序访问一下:(注意和上边的差别!!)
HelloClient.java
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
public class HelloClient
{
public static void main(String [] args) throws Exception {
String endpoint = "http://localhost:" +"8080"+ "/axis/services /HelloWorld";//注意!差别仅仅在这里!!
Service service = new Service();
Call call = (Call) service.createCall();
call.setTargetEndpointAddress( new .URL(endpoint) );
call.setOperationName("sayHello" );
String res = (String) call.invoke( new Object[] {} );
System.out.println( res );
}
}
好了,相信你对AXIS已有了大致的了解。接下来将会涉及到传参数、JAVABEAN对象,及AXIS的安全问题,下次再说吧:)也欢迎和我,一个快乐的 JAVA程序员,联系:)ronghao100@
AXIS学习笔记(二)
作者: ∣来源:JavaResearch∣原文地址∣2005-6-14
原文标题:使用Handler来增强Web服务的功能
原文作者: 陈亚强
高级软件工程师, 北京华园天一科技有限公司 2003 年 8 月
Handler的基本概念
J2EE Web 服务中的Handler技术特点非常像Servlet技术中的Filter。我们知道,在Servlet中,当一个HTTP到达服务端 时,往往要经过多个Filter对请求进行过滤,然后才到达提供服务的Servlet,这些Filter的功能往往是对请求进行统一编码,对用户进行认 证,把用户的访问写入系统日志等。相应的,Web服务中的Handler通常也提供以下的功能:
对客户端进行认证、授权;
把用户的访问写入系统日志;
对请求的SOAP消息进行加密,解密;
为Web Services对象做缓存。
SOAP消息Handler能够访问代表RPC请求或者响应的SOAP消息。在JAX-RPC技术中,SOAP消息Handler可以部署在服务端,也可 以在客户端使用。
下面我们来看一个典型的SOAP消息Handler处理顺序:
某个在线支付服务需要防止非授权的用户访问或者撰改服务端和客户端传输的信息,从而使用消息摘要(Message Digest)的方法对请求和响应的 SOAP消息进行加密。当客户端发送SOAP消⑹保?突Ф说?andler把请求消息中的某些敏感的信息(如信用卡密码)进行加密,然后把加密后的 SOAP消息传输到服务端;服务端的SOAP消息Handler截取客户端的请求,把请求的SOAP 消息进行解密,然后把解密后的SOAP消息派发到目标的Web服务端点。
Apache axis是我们当前开发Web服务的较好的选择,使用axisWeb服务开发工具,可以使用Handler来对服务端的请求和响应进行处理。典型的情况下,请求传递如图1所示。
图1 SOAP消息的传递顺序
在图中,轴心点(pivot point)是Apache与提供程序功能相当的部分,通过它来和目标的Web服务进行交互,它通常称为Provider。 axis中常用的Provider有Java:RPC,java:MSG,java:EJB。一个Web服务可以部署一个或者多个Handler。
Apache axis中的Handler体系结构和JAX-RPC 1.0(JSR101)中的体系结构稍有不同,需要声明的是,本文的代码在axis 中开发,故需要在axis环境下运行。
在axis环境下,SOAP消息Handler必须实现org.apache.axis.Handler接口(在JAX-RPC 1.0规范中,SOAP 消息Handler必须实现javax.xml.rpc.handler.Handler接口),org.apache.axis.Handler接口的 部分代码如下:
例程1 org.apache.axis.Handle的部分代码
public interface Handler extends Serializable {
public void init();
public void cleanup();
public void invoke(MessageContext msgContext) throws AxisFault ;
public void onFault(MessageContext msgContext);
public void setOption(String name, Object value);
public Object getOption(String name);
public void setName(String name);
public String getName();
public Element getDeploymentData(Document doc);
public void generateWSDL(MessageContext msgContext) throws AxisFault;
…
}
为了提供开发的方便,在编写Handler时,只要继承org.apache.axis.handlers. BasicHandler即 可,BasicHandler是Handler的一个模板,我们看它的部分代码:
例程2 BasicHandler的部分代码
public abstract class BasicHandler implements Handler {
protected static Log log =
LogFactory.getLog(BasicHandler.class.getName());
protected Hashtable options;
protected String name;
//这个方法必须在Handler中实现。
public abstract void invoke(MessageContext msgContext) throws AxisFault;
public void setOption(String name, Object value) {
if ( options == null ) initHashtable();
options.put( name, value );
}
…
}
BasicHandler中的(MessageContext msgContext)方法是Handler实现类必须实现的方法,它通过 MessageContext来获得请求或者响应的SOAPMessage对象,然后对SOAPMessage进行处理。
在介绍Handler的开发之前,我们先来看一下目标Web服务的端点实现类的代码,如例程3所示。
例程3 目标Web服务的端点实现类
package com.hellking.webservice;
public class HandleredService
{
//一个简单的Web服务
public String publicMethod(String name)
{
return "Hello!"+name;
}
}
//另一个Web服务端点:
package com.hellking.webservice;
public class OrderService
{
//web服务方法:获得客户端的订单信息,并且对订单信息进行对应的处理,
通常情况是把订单的信息写入数据库,然后可客户端返回确认信息。
public String orderProduct(String name,String address,String item,int quantity,Card card)
{
String cardId=card.getCardId();
String cardType=card.getCardType();
String password=card.getPassword();
String rderInfo="name="+name+",address="+address+",item="+item+",quantity="+quantity+"
,cardId="+cardId+",cardType="+cardType+",password="+password;
System.out.println("这里是客户端发送来的信息:");
System.out.println(orderInfo);
return orderInfo;
}
}
下面我们分不同情况讨论Handler的使用实例。
使用Handler为系统做日志
Handler为系统做日志是一种比较常见而且简单的使用方式。和Servlet中的Filter一样,我们可以使用Handler来把用户的访问写入系 统日志。下面我们来看日志Handler的具体代码,如例程4所示。
例程4 LogHandler的代码
package com.hellking.webservice;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.util.Date;
import org.apache.axis.AxisFault;
import org.apache.axis.Handler;
import org.apache.axis.MessageContext;
import org.apache.axis.handlers.BasicHandler;
public class LogHandler extends BasicHandler {
/**invoke,每一个handler都必须实现的方法。
*/
public void invoke(MessageContext msgContext) throws AxisFault
{
//每当web服务被调用,都记录到log中。
try {
Handler handler = msgContext.getService();
String filename = (String)getOption("filename");
if ((filename == null) || (filename.equals("")))
throw new AxisFault("Server.NoLogFile",
"No log file configured for the LogHandler!",
null, null);
FileOutputStream fos = new FileOutputStream(filename, true);
PrintWriter writer = new PrintWriter(fos);
Integer counter = (Integer)handler.getOption("accesses");
if (counter == null)
counter = new Integer(0);
counter = new Integer(counter.intValue() + 1);
Date date = new Date();
msgContext.getMessage().writeTo(System.out);
String result = "在"+date + ": Web 服务 " +
msgContext.getTargetService() +
" 被调用,现在已经共调用了 " + counter + " 次.";
handler.setOption("accesses", counter);
writer.println(result);
writer.close();
} catch (Exception e) {
throw AxisFault.makeFault(e);
}
}
}
前面我们说过,Handler实现类必须实现invoke方法,invoke方法是Handler处理其业务的入口点。LogHandler的主要功能是 把客户端访问的Web服务的名称和访问时间、访问的次数记录到一个日志文件中。
下面部署这个前面开发的Web服务对像,然后为Web服务指定Handler。编辑Axis_Home/WEB-INF/ server- config.wsdd文件,在其中加入以下的内容:
<service name="HandleredService" provider="java:RPC">
<parameter name="allowedMethods" value="*"/>
<parameter name="className" value="com.hellking.webservice.HandleredService"/>
<parameter name="allowedRoles" value="chen"/>
<beanMapping languageSpecificType="java:com.hellking.webservice.Card"
qname="card:card" xmlns:card="card"/>
<requestFlow>
<handler name="logging" type="java:com.hellking.webservice.LogHandler">
<parameter name="filename" value="c:\\MyService.log"/>
</handler>
</requestFlow>
</service>
…
</globalConfiguration>
…
<handler name="logging" type="java:com.hellking.webservice.LogHandler">
<parameter name="filename" value="c:\\MyService.log"/>
</handler>
…
<service name="HandleredService" provider="java:RPC">
…
<requestFlow>
<handler type="logging"/>
…<!--在这里可以指定多个Handler-->
</requestFlow>
</service>
http://127.0.0.1:8080/handler/services/HandleredService?wsdl&method=publicMethod&name=chen
注意:这个URL需要根据具体情况改变。
在Sun Jul 06 22:42:03 CST 2003: Web 服务 HandleredService 被调用,现在已经共调用了 1 次.
在Sun Jul 06 22:42:06 CST 2003: Web 服务 HandleredService 被调用,现在已经共调用了 2 次.
在Sun Jul 06 22:42:13 CST 2003: Web 服务 HandleredService 被调用,现在已经共调用了 3 次.
使用Handler对用户的访问认证
使用Handler为用户访问认证也是它的典型使用,通过它,可以减少在Web服务端代码中认证的麻烦,同时可以在部署描述符中灵活改变用户的访问权 限。
对用户认证的Handler代码如下:
例程5 认证的Handler
package com.hellking.webservice;
import….
//此handler的目的是对用户认证,只有认证的用户才能访问目标服务。
public class AuthenticationHandler extends BasicHandler
{
/**invoke,每一个handler都必须实现的方法。
*/
public void invoke(MessageContext msgContext)throws AxisFault
{
SecurityProvider provider = (SecurityProvider)msgContext.getProperty("securityProvider");
if(provider==null)
{
provider= new SimpleSecurityProvider();
msgContext.setProperty("securityProvider", provider);
}
if(provider!=null)
{
String userId=msgContext.getUsername();
String password=msgContext.getPassword();
//对用户进行认证,如果authUser==null,表示没有通过认证,
抛出Server.Unauthenticated异常。
org.apache.axis.security.AuthenticatedUser authUser
= provider.authenticate(msgContext);
if(authUser==null)
throw new AxisFault("Server.Unauthenticated",
Messages.getMessage("cantAuth01", userId), null,null);
//用户通过认证,把用户的设置成认证了的用户。
msgContext.setProperty("authenticatedUser", authUser);
}
}
}
在AuthenticationHandler代码里,它从MessageContext中获得用户信息,然后进行认证,如果认证成功,那么就使用 msgContext.setProperty("authenticatedUser", authUser)方法把用户设置成认证了的用户,如果认证 不成功,那么就抛出Server.Unauthenticated异常。
部署这个Handler,同样,在server-config里加入以下的内容:
<handler name="authen" type="java:com.hellking.webservice.AuthenticationHandler"/>
…
<service name="HandleredService" provider="java:RPC">
<parameter name="allowedRoles" value="chen"/>
…
</service>
WEB-INF/users.lst文件中加入以下用户:
hellking hellking
chen chen
http://127.0.0.1:8080/handler/services/HandleredService?wsdl&method=publicMethod&name=chen
将会提示输入用户名和密码,如图2所示。
图2 访问web服务时的验证
如果客户端是应用程序,那么可以这样在客户端设置用户名和密码:
例程6 在客户端设置用户名和密码
http://127.0.0.1:808
String endpointURL = "http://127.0.0.1:8080/handler/services/HandleredService?wsdl";
Service service = new Service();
Call call = (Call) service.createCall();
call.setTargetEndpointAddress( new .URL(endpointURL) );
call.setOperationName( new
QName("HandleredService", "orderProduct") );//设置操作的名称。
//由于需要认证,故需要设置调用的用户名和密码。
call.getMessageContext().setUsername("chen");
call.getMessageContext().setPassword("chen");
使用Handler对用户的访问授权
对于已经认证了的用户,有时在他们操作某个特定的服务时,还需要进行授权,只有授权的用户才能继续进行操作。我们看对用户进行授权的Handler的代 码。
例程7 对用户进行授权的代码
package com.hellking.webservice;
import…
//此handler的目的是对认证的用户授权,只有授权的用户才能访问目标服务。
public class AuthorizationHandler extends BasicHandler
{
/**invoke,每一个handler都必须实现的方法。
*/
public void invoke(MessageContext msgContext)
throws AxisFault
{
AuthenticatedUser user = (AuthenticatedUser)msgContext.getProperty("authenticatedUser");
if(user == null)
throw new AxisFault("Server.NoUser", Messages.getMessage("needUser00"), null, null);
String userId = user.getName();
Handler serviceHandler = msgContext.getService();
if(serviceHandler == null)
throw new AxisFault(Messages.getMessage("needService00"));
String serviceName = serviceHandler.getName();
String allowedRoles = (String)serviceHandler.getOption("allowedRoles");
if(allowedRoles == null)
{
return;
}
SecurityProvider provider = (SecurityProvider)msgContext.getProperty("securityProvider");
if(provider == null)
throw new AxisFault(Messages.getMessage("noSecurity00"));
for(StringTokenizer st = new StringTokenizer(allowedRoles, ","); st.hasMoreTokens();)
{
String thisRole = st.nextToken();
if(provider.userMatches(user, thisRole))
{
return;//访问授权通过。
}
}
//没有通过授权,不能访问目标服务,抛出Server.Unauthorized异常。
throw new AxisFault("Server.Unauthorized",
Messages.getMessage("cantAuth02", userId, serviceName), null, null);
}
}
在service-config.wsdd文件中,我们为Web服务指定了以下的用户:
<parameter name="allowedRoles" value="chen,hellking"/>
provider.userMatches(user, thisRo
展开阅读全文