`
923723914
  • 浏览: 635788 次
文章分类
社区版块
存档分类
最新评论

OpenJWeb中使用cxf webservice搭建跨平台SOA框架

 
阅读更多

在企业应用开发中,为了实现应用之间的松耦合,避免应用之间的过度依赖,可以使用WebService和socket通信这两种跨平台的解决方案。因为openjweb框架中整合了apache cxf框架,所以openjweb快速开发平台本身也是一个WebService服务器。在openjweb平台中为各子系统设计cxf webservice服务器端接口服务,可以实现其他异构应用系统请求openjweb各子系统提供的服务。比如其他应用系统从openjweb中获取openjweb系统里的部门信息。

在openjweb中用cxf开发webservice非常简单,一般可针对每个子系统设计一个webservice 服务器端组件,具体接口功能可视具体应用而定。下面介绍在openjweb中开发cxf服务端接口的过程:

(1)首先在D:\project\openjweb\src\java\applicationContext-cxf.xml中,定义一个webservice服务器端组件(当前示例为门店子系统定义一个服务器端组件):

<!--门店服务端-->

<jaxws:endpoint id="IStoreWS" implementor="com.tzsoft.store.ws.StoreWSImpl" address="/storeWS">
<jaxws:inInterceptors>
<bean class="org.openjweb.core.webservice.cxf.service.ServerAuthIntercepter"></bean>
</jaxws:inInterceptors>
</jaxws:endpoint>

这里要实现一个门店应用的WebService服务器端接口类IStoreWS.java和实现类StoreWSImpl.java,注意IStoreWS.java和应用系统自己的业务逻辑接口不同,IStoreWS.java

声明的只是为了给外部调用的WebService接口,在职责上和子系统内部声明的业务逻辑接口是有不同用途的。前者是粗粒度的,后者是细粒度的。下面是IStoreWS.java代码:

package com.tzsoft.store.ws;

import javax.jws.WebParam;
import javax.jws.WebService;

/**
* WebService接口定义类.
*
* 使用@WebService将接口中的所有方法输出为Web Service.
* 可用annotation对设置方法、参数和返回值在WSDL中的定义.
*/
@WebService
public interface IStoreWS
{
/**
* 上传会员卡号
* @param comId 单位编码
* @param deptId 部门编码
* @param memCard
* @return
*/

String uploadMemCard(
@WebParam(name = "comId")String comId,
@WebParam(name = "deptId")String deptId,
@WebParam(name = "memCard")String memCard) ;
}

下面是实现类:

package com.tzsoft.store.ws;

import javax.annotation.Resource;
import javax.jws.WebService;

import com.tzsoft.store.service.IStoreService;

//import org.openjweb.core.service.IUserAuthService;
@WebService(endpointInterface = "com.tzsoft.store.ws.IStoreWS")
public class StoreWSImpl implements IStoreWS
{
@Resource(name = "IStoreService")
IStoreService storeService;

public String uploadMemCard(String comId, String deptId, String memCard)
{
String s = "success";
try
{
System.out.println("下面会员卡调用.....");

storeService.receiveMemCard(comId, deptId, memCard);
}
catch(Exception ex)
{

}
return "哈哈 ,成功了耶!";
}

}
注意代码里的@WebService注解的使用。

因为WebService是跨平台的调用,所以可以向指定的WebService地址发送SOAP包就可以了。下面介绍如何向门店WebService地址发送调用请求并返回调用结果。

操作过程:

(1)建立一个批处理文件,内容:

java -classpath . SOAPClient4XG http://localhost:8088/portal/services/storeWS cxf4.xml

(2)创建一个SOAPClient4XG.java类并编译,此类用于将基于SOAP格式的xml请求文件发送到WebService地址执行WebService调用,并返回执行结果:

import java.io.*;
import java.net.*;

public class SOAPClient4XG {
public static void main(String[] args) throws Exception {

if (args.length < 2) {
System.err.println("Usage: java SOAPClient4XG " +
"http://soapURL soapEnvelopefile.xml" +
" [SOAPAction]");
System.err.println("SOAPAction is optional.");
System.exit(1);
}

String SOAPUrl = args[0];
String xmlFile2Send = args[1];

String SOAPAction = "";
if (args.length > 2)
SOAPAction = args[2];

// Create the connection where we're going to send the file.
URL url = new URL(SOAPUrl);
URLConnection connection = url.openConnection();
HttpURLConnection httpConn = (HttpURLConnection) connection;

// Open the input file. After we copy it to a byte array, we can see
// how big it is so that we can set the HTTP Cotent-Length
// property. (See complete e-mail below for more on this.)

FileInputStream fin = new FileInputStream(xmlFile2Send);

ByteArrayOutputStream bout = new ByteArrayOutputStream();

// Copy the SOAP file to the open connection.
copy(fin,bout);
fin.close();

byte[] b = bout.toByteArray();

// Set the appropriate HTTP parameters.
httpConn.setRequestProperty( "Content-Length",
String.valueOf( b.length ) );
httpConn.setRequestProperty("Content-Type","text/xml; charset=utf-8");
httpConn.setRequestProperty("SOAPAction",SOAPAction);
httpConn.setRequestMethod( "POST" );
httpConn.setDoOutput(true);
httpConn.setDoInput(true);

// Everything's set up; send the XML that was read in to b.
OutputStream out = httpConn.getOutputStream();
out.write( b );
out.close();

// Read the response and write it to standard out.

InputStreamReader isr =
new InputStreamReader(httpConn.getInputStream());
BufferedReader in = new BufferedReader(isr);

String inputLine;

while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);

in.close();
}

// copy method from From E.R. Harold's book "Java I/O"
public static void copy(InputStream in, OutputStream out)
throws IOException {

// do not allow other threads to read from the
// input or write to the output while copying is
// taking place

synchronized (in) {
synchronized (out) {

byte[] buffer = new byte[256];
while (true) {
int bytesRead = in.read(buffer);
if (bytesRead == -1) break;
out.write(buffer, 0, bytesRead);
}
}
}
}
}

(3)创建一个xml请求调用文件,格式是cxf的客户端xml书写格式:

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soap:Header>
<auth:authentication xmlns:auth="http://localhost:8088/portal//authentication">
<auth:systemID>1</auth:systemID>
<auth:userID>test</auth:userID>
<auth:password>test</auth:password>
</auth:authentication>

</soap:Header>
<soap:Body>
<ns1:uploadMemCard xmlns:ns1="http://ws.store.tzsoft.com/">
<comId>C0001</comId>
<deptId>C0001</deptId>
<memCard>0001</memCard>
</ns1:uploadMemCard>
</soap:Body>
</soap:Envelope>

上面的uploadMemCard是调用门店webService的上传会员卡号的方法,注意xmlns:ns1=http://ws.store.tzsft.com/"这个对应的IStoreWS的目录路径,不过是反着写的。

(4)执行批处理文件会返回调用结果:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">

<soap:Body>

<ns2:uploadMemCardResponse xmlns:ns2="http://ws.store.tzsoft.com/"><return>哈哈
,成功了耶!</return>

</ns2:uploadMemCardResponse>

</soap:Body>

</soap:Envelope>

这种调用方式是发送xml流的方式,特点是不受编程语言的限制。但是需要知道发送 的SOAP包的具体格式。另外对响应包也要进行xml解析才能取得具体结果。

如果使用Java客户端调用,可参考下面的例子(这个例子带了一个加密头,即SOAP Header中嵌入用户名和密码):

public class TestCxfClient

{

public static String testStoreWS(String wsAddr,String comId,String deptId,String memCard,boolean isSecret)
{
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
AddSoapHeader ash = new AddSoapHeader();
if(isSecret)
{
logger.info("带加密头a............!");
ArrayList list = new ArrayList();
// 添加soap header 信息
list.add(ash);
//注入拦截器,getOutInterceptors代表调用服务端时触发,getInInterceptors就是被调用才触发
factory.setOutInterceptors(list);
}
else
{
System.out.println("不带加密头,如果不带加密头,需去掉applicationContext-cxf.xml中配置的拦截器............");
}

factory.setServiceClass(IStoreWS.class);//实例化ws
factory.setAddress(wsAddr);
Object obj = factory.create();
IStoreWS service = (IStoreWS)obj;
//下面这行代码是具体调用服务段的deleteTeskTask()
String msg = "";
try
{
msg = service.uploadMemCard(comId, deptId,memCard);
}
catch(Exception ex)
{
ex.printStackTrace();
logger.error(ex.toString());
}
return msg;
}

}

为了在客户端调用时增加SOAP Header以便在 SOAP Header中写入用户名和口令,需要在applicationContext-cxf.xml配置文件中加入拦截器:

<jaxws:client id="clientTestService" serviceClass="org.openjweb.core.webservice.cxf.service.TestCxfClient"
address="http://localhost:8088/portal/services/cxfDemoWS">
<jaxws:outInterceptors>
<bean class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor" />
<ref bean="wsOutInterceptor"/>
</jaxws:outInterceptors>
</jaxws:client>

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics