构建 SOAP 服务
如果您觉得构建 Web 服务客户机的过程相当简单,事实的确如此。而就很多方面而言,构建服务的过程也同样简单。
总体过程
创建 Axis2 Web 服务的整个过程涉及以下步骤:
- 创建服务清单
- 创建类
- 将其打包为 Axis 存档文件
- 将 Axis 存档文件上载到 Axis2 Web 应用程序
- 重新启动服务器(如果有必要)
这就是全部步骤。让我们首先从服务清单开始。
创建清单
服务清单告知 Axis2 应用程序(就更大的范围而言,应用服务器)哪个请求与哪个类对应。例如,可以如清单 22 中所示的那样指定两个服务函数。
清单 22. 在清单中指定两个服务函数
<service name="CMSService">
<description>
This is a sample Web Service for the newspaper's
Content Managment System.
</description>
<parameter name="ServiceClass" locked="false"
>CMSService</parameter>
<operation name="getNumberOfArticles">
<messageReceiver class=
"org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>
</operation>
<operation name="addArticle">
<messageReceiver class=
"org.apache.axis2.receivers.RawXMLINOnlyMessageReceiver"/>
</operation>
</service>
|
首先,定义服务,提供其名称和描述,并指定实际为请求服务的类。接下来,定义实际的操作。请注意,此示例指定了两种不同类型的 messageReceiver
。第一个 RawXMLINOutMessageReceiver
用于传统的请求/响应服务。第二个 RawXMLINOnlyMessageReceiver
用于单向消息。操作的名称与有效负载的根元素以及要执行的方法对应。
将此文件保存为 services.xml。
接下来,让我们创建实际的应用程序。
创建应用程序
让我们首先创建模拟前面看到的 echo
函数的类(将直接返回原始有效负载的副本),如清单 23 中所示。
清单 23. CMSService 类
import org.apache.axis2.om.OMElement;
import javax.xml.stream.XMLStreamException;
public class CMSService {
public OMElement getNumberOfArticles(OMElement element)
throws XMLStreamException {
element.build();
element.detach();
return element;
}
}
|
要编译此应用程序,请确保 <axis2_home>/lib 中的所有 *.jar 文件都在您的 CLASSPATH 上。
此应用程序相当简单,仅包含一个与 getNumbereOfArticles
操作对应的类。此函数和任何要作为操作的函数一样,接收单个 OMElement
参数(表示有效负载)。此处,您将首先使用 build()
方法来确定已接收到所有数据——AXIOM 使用一个 pull 方法访问数据——然后将元素从其当前树中分离,以便能够将其返回。
如果喜欢冒险,可以自由地部署服务和访问服务,以访问服务并查看结果。应该看到与清单 24 中所示类似的结果输出。
清单 24. CMSService 类响应
<cms:getNumberOfArticles><cms:category>classifieds</cms:category></cms:
getNumberOfArticles>
|
接下来让我们了解如何实际处理数据。
提取有效负载
为了从有效负载提取信息,将使用与 DOM 非常类似的技术来对接收到的有效负载元素进行操作(请参见清单 25)。
清单 25. 提取有效负载信息
...
import javax.xml.stream.XMLStreamException;
public class CMSService {
public OMElement getNumberOfArticles(OMElement element)
throws XMLStreamException {
element.build();
element.detach();
String rootName = element.getLocalName();
OMElement categoryElement = element.getFirstElement();
String categoryElementName = categoryElement.getLocalName();
String categoryValue = childElement.getText();
return element;
}
}
|
请记住,有效负载的根是 getNumberOfArticles
函数接收的元素。在此情况下,将提取元素的名称,然后移动到第一个元素子项(与第一个子项不同,后者可能是空格文本节点)并提取其名称和值。请注意,使用的是 getText()
方法来提取实际上是 category 元素的文本节点子项的值。这无疑非常简捷!
创建并返回响应
最后,将需要使用从请求的有效负载提取数据来创建响应。在本例中,将从第二个函数(在实际应用程序中,该函数将进行一些其他的工作)提供响应(请参见清单 26)。
清单 26. 创建响应
...
import javax.xml.stream.XMLStreamException;
public class CMSService {
public OMElement getNumberOfArticles(OMElement element)
throws XMLStreamException {
element.build();
element.detach();
String rootName = element.getLocalName();
OMElement childElement = element.getFirstElement();
String childName = childElement.getLocalName();
String categoryValue = childElement.getText();
SOAPFactory factory = OMAbstractFactory.getSOAP12Factory();
OMNamespace namespace = factory.createOMNamespace(
"http://daily-moon.com/cms/", "resp");
OMElement resultElem = factory.createOMElement(
"numberOfArticles",namespace);
String actualValue =
(articleCount(categoryValue)).toString();
resultElem.setText(actualValue);
return resultElem;
}
private Integer articleCount(String catId){
//Perform some function such as searching the CMS
//database, and return the actual value. For our
//purposes, you'll hardcode it.
return new Integer(42);
}
}
|
首先,创建将用于创建所有其他对象的工厂,然后创建将添加到响应的有效负载的命名空间。接下来,创建实际结果元素,在本例中为名为 numberOfArticles
的元素。
numberOfArticles
元素的内容将为 articleCount()
函数返回的一个数字,在本例中,该函数可以为任何内容。在实际的应用程序中,将进行所需进行的任何工作来获取此数据。获取了此数据后,会将其设置为 numberOfArticles
元素的内容,并直接返回该元素。
现在剩下的就是部署服务了。
部署服务
为了部署服务,需要创建一个 Axis 存档文件。此文件和 *.jar 或 *.war 文件类似,实际是使用特殊文件扩展名(在本例中使用的是 .aar)的 zip 文件。请按照以下步骤创建此文件:
- 将 <AXIS2_HOME>/lib 目录中的所有文件添加到 CLASSPATH 并编译 CMSService.java 文件。
- 在与 CMSService.class 文件相同的目录中创建名为 META-INF 的新目录。
- 从包含 CMSService.class 文件的目录中发出以下命令:<code type="section" width="100"> jar cvf CMSService.aar ./* </code> 应该看到与以下类似的结果:<code type="section" width="100"> added manifest adding:CMSService.class(in = 513) (out= 330)(deflated 35%) adding:CMSService.java(in = 328) (out= 182)(deflated 44%) ignoring entry META-INF/ adding:META-INF/services.xml(in = 391) (out= 229)(deflated 41%) </code>
- 使用安装示例服务中列出的步骤将此服务添加到服务器上。(如果看到 Web 接口上有 Servlet 错误,请确保登录到了 Axis2 应用程序。如果会话已过期,应用程序将不一定会通知您,而可能会直接显示错误。)
- 如果有必要,请重新启动 Geronimo。(将可能不必在添加服务后进行此操作,但在进行更改后可能必须这样做。)
如果单击 View services 链接,应该看到与图 4 中所示类似的内容。
图 4. 可用服务
访问服务
现在已经完成了服务构建,接下来要通过客户机对其进行访问。对前面创建的 ClassifiedClient.java 文件进行以下更改(请参见清单 27)。
清单 27. 修改 ClassifiedClient
...
public class ClassifiedClient {
private static EndpointReference targetEPR =
new EndpointReference(
"http://localhost:8080/axis2/services/CMSService");
public static OMElement getEchoOMElement() {
SOAPFactory fac = OMAbstractFactory.getSOAP12Factory();
OMNamespace omNs = fac.createOMNamespace(
"http://daily-moon.com/cms", "cms");
OMElement method = fac.createOMElement("getNumberOfArticles", omNs);
OMElement value = fac.createOMElement("category", omNs);
value.addChild(fac.createText(value, "classifieds"));
method.addChild(value);
return method;
}
public static void main(String[] args) {
try {
OMElement payload = ClassifiedClient.getEchoOMElement();
Options options = new Options();
options.setTo(targetEPR);
options.setTransportInProtocol(Constants.TRANSPORT_HTTP);
ServiceClient sender = new ServiceClient();
sender.setOptions(options);
OMElement result = sender.sendReceive(payload);
String response = result.getText();
System.out.println("There are "+response+" classifieds at the moment.");
} catch (Exception e) { //(XMLStreamException e) {
System.out.println(e.toString());
}
}
}
|
编译并运行了此应用程序后,应看到清单 28 中所示的响应。
清单 28. ClassifiedClient 响应
There are 42 classifieds at the moment.
|
单向服务
继续讨论之前,让我们了解一下处理单向服务(而非请求/响应服务)时涉及到的不同之处。
服务
创建单向服务非常简单。此过程与创建请求/响应服务完全类似,至少不会实际返回任何内容。例如,可以为 CMSService
类创建 addArticle
操作,如图 29 中所示。
清单 29. CMSServiceclass 中的 addArticle 操作...
private Integer articleCount(String catId){
...
}
public void addArticle(OMElement element)
throws XMLStreamException{
element.build();
System.out.println(element);
}
}
|
在 services.xml 文件中,将 addArticle
操作指定为“in only”操作,因此不会等待返回任何内容,但即使这样,也能看到会实际发生一些事项,会在命令行输出接收到的有效负载。您将在 Geronimo 窗口中看到此信息。
在实际应用程序中,此方法将从有效负载提取信息,并会实际添加到某种类型的数据库或其他存储库。
客户机
此服务的客户机也与请求/响应服务所使用的服务类似(请参见清单 30)。
清单 30. 创建客户机
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.om.OMElement;
import org.apache.axis2.SOAP.SOAPFactory;
import org.apache.axis2.om.OMAbstractFactory;
import org.apache.axis2.om.OMNamespace;
public class AddArticleClient {
private static EndpointReference targetEPR =
new EndpointReference(
"http://localhost:8080/axis2/services/CMSService");
private static OMElement getOMElement(){
SOAPFactory fac = OMAbstractFactory.getSOAP12Factory();
OMNamespace omNs = fac.createOMNamespace(
"http://daily-moon.com", "cms");
OMElement method = fac.createOMElement("addArticle", omNs);
OMElement category = fac.createOMElement("category", omNs);
category.setText("classifieds");
OMElement subcategory =
fac.createOMElement("subcategory", omNs);
category.setText("wantads");
OMElement adtext = fac.createOMElement("article", omNs);
adtext.setText("Do you have good head for numbers"+
" and a great deal of patience? Do you like"+
" to sit for hours sorting objects by their"+
" size? If so, then you could be the"+
" next goober counter in the world famous"+
" Murphy Brothers peanut factory. "+
" Willingness to dress up as our mascot"+
" helpful, but not required.");
method.addChild(category);
method.addChild(subcategory);
method.addChild(adtext);
return method;
}
public static void main(String[] args) {
try {
OMElement payload = AddArticleClient.getOMElement();
ServiceClient serviceClient = new ServiceClient();
Options options = new Options();
serviceClient.setOptions(options);
options.setTo(targetEPR);
serviceClient.fireAndForget(payload);
} catch (AxisFault axisFault) {
axisFault.printStackTrace();
}
}
}
|
尽管有效负载不同,但正如您在 getOMElement()
方法中看到的,编程方面目前的唯一真正的更改是使用 fireAndForget()
方法替代 sendReceive()
方法。此方法并不会返回响应。
如果运行此客户机,应该在 Geronimo 窗口中看到与图 5 中所示类似的输出。
图 5. 命令行输出
posted on 2006-12-29 18:39
SIMONE 阅读(828)
评论(0) 编辑 收藏 所属分类:
AXIS 、
JAVA