Web Service是一个平台独立的,低耦合的,自包含的、基于可编程的web的应用程序,可使用开放的XML(标准通用标记语言下的一个子集)标准来描述、发布、发现、协调和配置这些应用程序,用于开发分布式的交互操作的应用程序。
Web Service技术, 能使得运行在不同机器上的不同应用无须借助附加的、专门的第三方软件或硬件, 就可相互交换数据或集成。依据Web Service规范实施的应用之间, 无论它们所使用的语言、 平台或内部协议是什么, 都可以相互交换数据。Web Service是自描述、 自包含的可用网络模块, 可以执行具体的业务功能。Web Service也很容易部署, 因为它们基于一些常规的产业标准以及已有的一些技术,诸如标准通用标记语言下的子集XML、HTTP。Web Service减少了应用接口的花费。Web Service为整个企业甚至多个组织之间的业务流程的集成提供了一个通用机制。
本文将介绍其 CXF、HTTP 及 sapjco3 方式调用。
本类为 CXF 动态方式调用,无需生成客户端代码。
LoginInterceptor 类为用户验证拦截器。
public class CxfUtils {
private static String _wsdlUrl;
private static String _nameSpace;
/*private static String username = "test";
private static String password = "123456";*/
public static Logger logger = Logger.getLogger(CxfUtils.class);
public CxfUtils(String wsdlUrl, String nameSpace) {
_wsdlUrl = wsdlUrl;
_nameSpace = nameSpace;
}
/**
* 调用webservice 接口
*
* @param method
* 调用方法名
* @param params
* 接口传入参数
* @return
*/
public String invoke(String method, String... params) {
try {
if (StringUtils.isEmpty(method)) {
return null;
}
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
QName qName = new QName(_nameSpace, method);
org.apache.cxf.endpoint.Client client = dcf.createClient(_wsdlUrl);
// 用户验证,注:能访问到接口内容,访问方法使用验证
// client.getOutInterceptors().add(new LoginInterceptor(username,password));
logger.debug("接口连接成功!");
HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy(); // 策略
httpClientPolicy.setConnectionTimeout(36000); // 连接超时
httpClientPolicy.setAllowChunking(false);
httpClientPolicy.setReceiveTimeout(10000); // 接收超时
HTTPConduit http = (HTTPConduit) client.getConduit();
http.setClient(httpClientPolicy);
Object[] resobj = client.invoke(qName, params);
logger.debug("数据发送成功!");
if (resobj.length <= 0 || resobj == null) {
return null;
}
return resobj[0].toString();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
// 用户登录验证
class LoginInterceptor extends AbstractPhaseInterceptor {
private String username;
private String password;
public static Logger logger = Logger.getLogger(LoginInterceptor.class);
public LoginInterceptor(String username, String password) {
// 设置在发送请求前阶段进行拦截
super(Phase.PREPARE_SEND);
this.username = username;
this.password = password;
}
@Override
public void handleMessage(SoapMessage soapMessage) throws Fault {
try {
List headers = soapMessage.getHeaders();
Document doc = DOMUtils.createDocument();
Element auth = doc.createElementNS("http://www.w3.org/2001/XMLSchema", "SecurityHeader");
Element UserName = doc.createElement("username");
Element UserPass = doc.createElement("password");
UserName.setTextContent(username);
UserPass.setTextContent(password);
auth.appendChild(UserName);
auth.appendChild(UserPass);
headers.add(0, new Header(new QName("SecurityHeader"), auth));
logger.debug("用户名密码验证发送!");
} catch (DOMException e) {
// TODO Auto-generated catch block
e.printStackTrace();
logger.debug("用户名密码验证失败!");
}
}
}
本类使用的 HttpClient 方式,原生的 HTTP URL 方式在示例代码包中。
public class HTTPClientUtils {
/**
*
* @param uri : 接口地址
* @param content : 传输参数 XML
* @param nameSpace :接口 nameSpace
* @param method: 接口方法
* @return
*/
public static String doHttpPostByHttpClient(String uri, String content, String nameSpace, String method) {
try {
// HttpClient发送SOAP请求
int timeout = 10000;
HttpClient client = new HttpClient();
// 如果需要用户名密码验证;不需要验证登录则不需要以下4行
/*
* String username = "test"; String password = "1234567";
* UsernamePasswordCredentials creds = new UsernamePasswordCredentials(username,
* password); client.getState().setCredentials(AuthScope.ANY, creds);
*/
PostMethod postMethod = new PostMethod(uri);
// 设置连接超时
client.getHttpConnectionManager().getParams().setConnectionTimeout(timeout);
// 设置读取时间超时
client.getHttpConnectionManager().getParams().setSoTimeout(timeout);
// 然后把Soap请求数据添加到PostMethod中
RequestEntity requestEntity = new StringRequestEntity(content, "text/xml", "UTF-8");
// 设置请求头部,否则可能会报 “no SOAPAction header” 的错误
postMethod.setRequestHeader("SOAPAction", nameSpace + method);
// 设置请求体
postMethod.setRequestEntity(requestEntity);
int status = client.executeMethod(postMethod);
if (status == 200) {// 成功
InputStream is = postMethod.getResponseBodyAsStream();
// 获取请求结果字符串
String result = IOUtils.toString(is);
return result;
} else {
System.out.println("错误代码:" + status + ":" + postMethod.getResponseBodyAsString());
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
注:此方式必须需要 sapjco3.dll 和 sapjco3.jar 工具包,sap 接口类方法与参数都可以在代码中操作。
获取 sapjco 连接
public class SapConnect {
private static Logger log = Logger.getLogger(SapConnect.class); // 初始化日志对象
public static final String ABAP_AS_POOLED = "ECD";//连接池名;
static {
Properties connectProperties = new Properties();
//详细信息咨询接口开发人员
connectProperties.setProperty(DestinationDataProvider.JCO_ASHOST, "61.147.124.120");// 服务器
connectProperties.setProperty(DestinationDataProvider.JCO_SYSNR, "00"); // 系统编号
connectProperties.setProperty(DestinationDataProvider.JCO_CLIENT, "120"); // SAP集团
connectProperties.setProperty(DestinationDataProvider.JCO_USER, "wms"); // SAP用户名
connectProperties.setProperty(DestinationDataProvider.JCO_PASSWD, "1234567"); // 密码
connectProperties.setProperty(DestinationDataProvider.JCO_LANG, "zh"); // 登录语言
connectProperties.setProperty(DestinationDataProvider.JCO_POOL_CAPACITY, "3"); // 最大连接数
connectProperties.setProperty(DestinationDataProvider.JCO_PEAK_LIMIT, "10"); // 最大连接线程
createDataFile(ABAP_AS_POOLED, "jcoDestination", connectProperties);
}
/**
* 创建SAP接口属性文件。
*
* @param name
* ABAP管道名称
* @param suffix
* 属性文件后缀
* @param properties
* 属性文件内容
*/
private static void createDataFile(String name, String suffix, Properties properties) {
File cfg = new File(name + "." + suffix);
if (cfg.exists()) {
cfg.deleteOnExit();
}
try {
FileOutputStream fos = new FileOutputStream(cfg, false);
properties.store(fos, "for tests only !");
fos.close();
} catch (Exception e) {
log.error("Create Data file fault, error msg: " + e.toString());
throw new RuntimeException("Unable to create the destination file " + cfg.getName(), e);
}
}
/**
* 获取SAP连接
*
* @return SAP连接对象
*/
public static JCoDestination connect() {
JCoDestination destination = null;
try {
destination = JCoDestinationManager.getDestination(ABAP_AS_POOLED);
} catch (JCoException e) {
log.error("Connect SAP fault, error msg: " + e.toString());
}
return destination;
}
使用 sapjco 连接操作接口内容
public class SapTest {
/**
* 明确接口使用或为自主开发的时,使用该方式调用接口;
* 此方式可对接口中的方法和参数获取与赋值,进行对象化操作
* @param args
* @throws JCoException
*/
public static void main(String[] args) throws JCoException {
String bapiFunctionName = "qqCheckOnline";
//连接SAP,获取一个连接对象
JCoDestination destination = SapConnect.connect();
//将该函数的结构打印出来
JCoRepository repository = destination.getRepository(); //JCoFunction是一个接口,代表SAP系统的函数库
JCoFunction function = repository.getFunction(bapiFunctionName); // 从这个函数模板获得该SAP函数的对象
JCoParameterList input = function.getImportParameterList(); // 获得函数的import参数列表
input.setValue("参数key", "参数value");
function.execute(destination);
JCoParameterList output = function.getExportParameterList(); // 获得Export变量列表。
int value = output.getInt("qqCheckOnline");
System.out.println(value);
}
}
webservice 客户端调用方式很多中 ,本文介绍的都是不需要生成客户端代码,axis2 生成代码方式调用开发中不利于维护,请根据自己所需要调用的接口的类型分析出便于开发的调用方式,希望本文能够给大家一个帮助。
使用 QQ 状态接口测试实例,注:已测试成功。代码可直接使用运行。
/**
* Demo 示例为 qq 在线状态
* Cxf 模式为动态调用,使用静态调用和代码生成则不需要本类
* @param args
*/
public static void main(String[] args) {
//最简单的接口 url 用户验证:拼接&sap-user=username&sap-password=password
String wsdlUrl = "http://www.webxml.com.cn/webservices/qqOnlineWebService.asmx?wsdl";
String nameSpace = "http://WebXml.com.cn/";
String method = "qqCheckOnline";
//通过 Cxf 方式动态调用
CxfUtils cxfutils = new CxfUtils(wsdlUrl, nameSpace);
String restr = cxfutils.invoke("qqCheckOnline","1963424456");
logger.debug(restr);
//通过 soap ui 解析后的 xml 参数串
String xml = "\r\n" +
" \r\n" +
" \r\n" +
" \r\n" +
" \r\n" +
" 78123617 \r\n" +
" \r\n" +
" \r\n" +
" ";
//原生 HTTP 方式 url 请求调用
HTTPUtils.send(wsdlUrl,xml,nameSpace,method);
//使用插件 HTTPClient 调用
HTTPClientUtils.doHttpPostByHttpClient(wsdlUrl,xml,nameSpace,method);
}
文中所需 jar 包与代码地址:
链接:https://pan.baidu.com/s/1SZ4p_eawFVZrGzJllNVl5A .
提取码:793k