Java WebService学习笔记 - Axis(一)
实际开发中,很多系统都是基于历史遗留系统进行开发,有时,这些系统基于不同的语言,如C,C++,C#,java,PHP等等。为了实现历史系统的再利用,或向外部程序暴露调用接口,于是就产生了WebService规范。WebService用于实现系统的透明访问,其最终目的:实现异构系统间通信。
单从Java方面考虑,实现WebService的方法有jdk1.6版本添加的JWS,Axis1/2,XFIRE,Celtix,CXF(Xfire和Celtix的整合)。
综合来看Axis1,Xfire,Celtix成熟但即将退出的版本。内置的JWS,Axis和CXF却也不是很成熟(哎,青黄不接)。
当利用Java版Axis有两个途径,以Java码作为Web服务。最简单的一种是使用原生的jws(Java Web Service的文件)。另一种方法是使用定制的部署文件。定制部署让您能自选资源,什么要予以曝光。
第一种实现方式:即时发布
实现此功能需要借助 axis-1_4\webapps下的axis工程,将其部署到apache服务器webapps目录下。
原生的jws和java源代码的唯一区别是后缀名,当然采用这种方式也不能使用package进行打包.下面提供简单的原生jws和远程调用实现。
Hello.jws内容:
public class Hello { public String sayHello(String name) { StringBuffer greeting = new StringBuffer("Hello "); if ( name != null ) { greeting.append(name); } greeting.append(", nice to see you!"); return greeting.toString(); } }将Hello.jws文件放到apache服务器webapps/axis/目录下,启动服务器。
通过 http://localhost:8080/axis/Hello.jws?wsdl 可以获得Hello.jws的WebService定义,内容如下
<?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions targetNamespace="http://localhost:8080/axis/Hello.jws" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:impl="http://localhost:8080/axis/Hello.jws" xmlns:intf="http://localhost:8080/axis/Hello.jws" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <!--WSDL created by Apache Axis version: 1.4 Built on Apr 22, 2006 (06:55:48 PDT)--> <wsdl:message name="sayHelloResponse"> <wsdl:part name="sayHelloReturn" type="xsd:string"/> </wsdl:message> <wsdl:message name="sayHelloRequest"> <wsdl:part name="name" type="xsd:string"/> </wsdl:message> <wsdl:portType name="Hello"> <wsdl:operation name="sayHello" parameterOrder="name"> <wsdl:input message="impl:sayHelloRequest" name="sayHelloRequest"/> <wsdl:output message="impl:sayHelloResponse" name="sayHelloResponse"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="HelloSoapBinding" type="impl:Hello"> <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="sayHello"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="sayHelloRequest"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://DefaultNamespace" use="encoded"/> </wsdl:input> <wsdl:output name="sayHelloResponse"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost:8080/axis/Hello.jws" use="encoded"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="HelloService"> <wsdl:port binding="impl:HelloSoapBinding" name="Hello"> <wsdlsoap:address location="<span style="color:#FF0000;">http://localhost:8080/axis/Hello.jws</span>"/> </wsdl:port> </wsdl:service> </wsdl:definitions>至此,简单的Service端就部署成功了,接下来要通过一段程序对Hello.jws进行访问。
使用eclipse创建一个java project,并添加jar包,必须的jar包包括axis.jar;jaxrpc.jar;commons-loggin-1.x.jar;commons-discovery-0.x.jar
import javax.xml.namespace.QName; import org.apache.axis.client.Call; import org.apache.axis.client.Service; public class HelloClient { public static void main(String[] args) { System.out.println(new HelloClient().sayHello("Han MeiMei")); } public String sayHello(String name) { String result = null; try { //1.设置远程访问链接 String url = "http://localhost:8080/axis/Hello.jws"; //2.获取Service对象 Service service = new Service(); //3.通过Service对象获取远程调用对象Call Call call = (Call) service.createCall(); //4.设置远程调用桩 call.setTargetEndpointAddress(url); //5.设置远程操作方法名 call.setOperationName(new QName(url, "sayHello")); //6.设置参数,执行远程方法 result = (String)call.invoke(new Object[]{name}); } catch(Exception e) { e.printStackTrace(); } return result; } }
执行结果如下:
May 19, 2014 2:11:40 PM org.apache.axis.utils.JavaUtils isAttachmentSupported WARNING: Unable to find required classes (javax.activation.DataHandler and javax.mail.internet.MimeMultipart). Attachment support is disabled. <span style="color:#FF0000;">Hello Han MeiMei, nice to see you!</span>第二种实现方式:定制发布
第一种发布方式比较快捷,发布方式简单,但有以下缺点:
1.必须要有源文件,同时不能包含package结构
2.发布之后所有方法均开放,不可控制
针对以上缺点,axis提供定制发布方式,具体步骤如下:
编写Hello.java类
package com.webservice.wsdd; public class Hello { public String sayHello(String name) { StringBuffer greeting = new StringBuffer("Hello "); if(name != null) { greeting.append(name); } greeting.append(",nice to see you!"); return greeting.toString(); } public int add(int a,int b) { return a + b; } }
使用命令行进行编译,得到class文件(包括包)
javac -d ./ Hello.java
将com包所有内容拷贝到apache服务器webapps/axis/WEB-INF/classes下。
编写hello.wsdd配置文件,放置到webapps/axis/WEB-INF/classes/com下 WSDD文档具体意义可查看Axis WSDD文件参考文档
<deployment name="test" xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <!--Service name:服务名称,自己确定--> <service name="Hello" provider="java:RPC"> <!--parameter className:类路径及名称 allowedMethods:可以指定方法名,也可以使用×代表全部 --> <parameter name="className" value="com.webservice.wsdd.Hello" /> <!-- 定制方法,此处指定制sayHello方法 --> <parameter name="allowedMethods" value="sayHello" /> </service> </deployment><span style="color:#FF0000;"><strong></strong></span>启动服务器,进入到hello.wsdd位置,使用命令生成server-config.wsdd配置文件
java org.apache.axis.client.AdminClient hello.wsdd --需要自己配置classpath环境变量
生成的server-config.wsdd配置文件位于webapps/axis/WEB-INF/路径下,内容如下,如果不想生成,也可以拷贝一份放在该路径下
<?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="E:\apache-tomcat-7.0.53\webapps\axis\WEB-INF\attachments"/> <parameter name="dotNetSoapEncFix" value="true"/> <parameter name="enableNamespacePrefixOptimization" value="false"/> <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="URLMapper" type="java:org.apache.axis.handlers.http.URLMapper"/> <handler name="LocalResponder" type="java:org.apache.axis.transport.local.LocalResponder"/> <handler name="Authenticate" type="java:org.apache.axis.handlers.SimpleAuthenticationHandler"/> <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> <span style="background-color: rgb(255, 255, 51);"> <service name="Hello" provider="java:RPC"> <parameter name="allowedMethods" value="sayHello"/> <parameter name="className" value="com.webservice.wsdd.Hello"/> </service></span> <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>
使用http://localhost:8080/axis/services/Hello?wsdl 可以查看WebService描述,内容如下
<?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions targetNamespace="http://localhost:8080/axis/services/Hello" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:impl="http://localhost:8080/axis/services/Hello" xmlns:intf="http://localhost:8080/axis/services/Hello" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <!--WSDL created by Apache Axis version: 1.4 Built on Apr 22, 2006 (06:55:48 PDT)--> <wsdl:message name="sayHelloResponse"> <wsdl:part name="sayHelloReturn" type="soapenc:string"/> </wsdl:message> <wsdl:message name="sayHelloRequest"> <wsdl:part name="in0" type="soapenc:string"/> </wsdl:message> <wsdl:portType name="Hello"> <wsdl:operation name="sayHello" parameterOrder="in0"> <wsdl:input message="impl:sayHelloRequest" name="sayHelloRequest"/> <wsdl:output message="impl:sayHelloResponse" name="sayHelloResponse"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="HelloSoapBinding" type="impl:Hello"> <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="sayHello"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="sayHelloRequest"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://wsdd.webservice.com" use="encoded"/> </wsdl:input> <wsdl:output name="sayHelloResponse"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost:8080/axis/services/Hello" use="encoded"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="HelloService"> <wsdl:port binding="impl:HelloSoapBinding" name="Hello"> <wsdlsoap:address location="<span style="color:#FF0000;">http://localhost:8080/axis/services/Hello</span>"/> </wsdl:port> </wsdl:service> </wsdl:definitions>
此时定制服务发布完成。
访问方式只需把第一步的访问链接替换成上面红字部分即可
补充:开发中,有时候需要通过WebService传递对象,此时的处理方式与上述方法又有不同
Axis处理对象参数/返回值
编写Question.java和Answer.java 注意:Bean对象一定要实现Serializable接口。
package com.webservice.wsdd; import java.io.Serializable; @SuppressWarnings("serial") public class Question implements Serializable { private int id; private String question; private String answer; public void setId(int id) { this.id = id; } public int getId() { return this.id; } public void setQuestion(String question) { this.question = question; } public String getQuestion() { return this.question; } public void setAnswer(String answer) { this.answer = answer; } public String getAnswer() { return this.answer; } }
package com.webservice.wsdd; public class Answer { public Question answerQuestion(Question question) { Question tmp = question; doRead(tmp); tmp.setAnswer("do not know the answer!"); return tmp; } private void doRead(Question question) { System.out.println("read question:"+question.getQuestion()); } }
编译后放到服务器classes目录下,在server-config.wsdd中注册服务,较之前多了红字部分。
<service name="Answer" provider="java:RPC"> <parameter name="className" value="com.webservice.wsdd.Answer"/> <parameter name="allowedMethods" value="*"/> <span style="color:#FF0000;"><!-- qname:自定义bean名称 xmlns:自定义的xml命名空间,xmlns冒号后面部分取自qname属性,必须要有,否则报错 languageSpecificType:语言类型及类路径 --> <beanMapping qname="bean:Question" xmlns:bean="BeanManger" languageSpecificType="java:com.webservice.wsdd.Question" /></span> </service>
启动服务器,服务发布成功。可以在 http://localhost:8080/axis/servlet/AxisServlet 下查看到该服务
客户端代码QuestionClient.java
package com.client; import javax.xml.namespace.QName; import javax.xml.rpc.ParameterMode; import org.apache.axis.client.Call; import org.apache.axis.client.Service; import org.apache.axis.encoding.ser.BeanDeserializerFactory; import org.apache.axis.encoding.ser.BeanSerializerFactory; import com.webservice.wsdd.Question; public class QuestionClient { public static void main(String[] args) { Question question = new Question(); question.setQuestion("先有鸡还是先有蛋!"); new QuestionClient().askAndAnswer(question); } /** * @param question */ public void askAndAnswer(Question question) { String url = "http://localhost:8080/axis/services/Answer"; Service service = new Service(); try { Call call = (Call)service.createCall(); call.setTargetEndpointAddress(url); //注册Bean及序列化和反序列化工程映射关系 QName qname = new QName("bean:BeanManger","Question"); call.registerTypeMapping(Question.class, qname, new BeanSerializerFactory(Question.class, qname), new BeanDeserializerFactory(Question.class, qname) ); call.setOperationName(new QName(url, "answerQuestion")); call.setReturnClass(Question.class); //设置调用方法的参数 call.addParameter("question", qname, ParameterMode.IN); Question tmp = (Question)call.invoke(new Object[]{question}); if(tmp!=null) { System.out.println("Question:"+tmp.getQuestion()); System.out.println("Answer:"+tmp.getAnswer()); } } catch(Exception e) { e.printStackTrace(); } } }
执行结果:
Question:先有鸡还是先有蛋! Answer:do not know the answer!
下一篇 Java WebService学习笔记 - Axis进阶(二)