在垮平台通讯中有很多的接口方式,这里做个简单的webservice接口。发布webservice接口的方式也多种多样,这里做个基于CXF的webservice接口。
首先做点知识储备,javax.jws包中常用的注解,参考链接:http://blog.csdn.net/w410589502/article/details/51742004
下面开始,这里Spring用的4.2的,CXF用的3.2的,JDK是1.8的,这里只要是1.6及以后的就没问题了,主要是要用javax.jws的包
服务端webservice接口
package com.lovo.webservice;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
/**
* SOAP协议的webservice接口
* @author WZH
*服务器端,服务提供者
*/
/*
* @WebService 标记为一个webservice接口
* 1.targetNamespace:指定你想要的名称空间,默认认是使用接口实现类的包名的反缀,
* 但是在实际测试中发现cxf+spring编写webservice的时候,targetNamespace要指向
* 服务类的接口所在的包名而不是实现类的包名,否则,在客户端将不能识别可用的服务
* 2.serviceName: 对外发布的服务名,指定 Web Service 的服务名称:wsdl:service。
* 缺省值为 Java 类的简单名称 + Service。(字符串)
* 3.portName: wsdl:portName。缺省值为 WebService.name+Port。
*
* @SOAPBinding 消息绑定, 这个标记怎么说,我这里测试的时候加不加都无所谓,但是有同仁说过
* 不加这个有时候会出现客户端无法识别,有的人又报错,所以还是加上吧
* Exception in thread "main" com.sun.xml.internal.ws.model.RuntimeModelerException:
* runtime modeler error: Wrapper class org.soap.service.jaxws.Add is not found. Have you run APT to generate them?
*/
@WebService(targetNamespace ="http://webservice.lovo.com/",serviceName="HelloService",portName="HellowServicePort")
@SOAPBinding(style=Style.RPC)
public interface IHelloService {
/*
* @WebResult 注释用于定制从返回值至 WSDL 部件或 XML 元素的映射。将此注释应用于客户机或服务器服务端点接口(SEI)上的方法,
* 或者应用于 JavaBeans 端点的服务器端点实现类
* 1.name:当返回值列示在 WSDL 文件中并且在连接上的消息中找到该返回值时,指定该返回值的名称。对于 RPC 绑定,这是用于表示返回值的
* 2.targetNamespace:指定返回值的 XML 名称空间。仅当操作类型为 RPC 或者操作是文档类型并且参数类型为 BARE 时才使用此参数。(字符串)
*
* @WebMethod 注释表示作为一项 Web Service 操作的方法,将此注释应用于客户机或服务器服务端点接口(SEI)上的方法,
* 或者应用于 JavaBeans 端点的服务器端点实现类。
* 1.operationName:指定与此方法相匹配的wsdl:operation 的名称。缺省值为 Java 方法的名称。(字符串)
*
* @WebParam 注释用于定制从单个参数至 Web Service 消息部件和 XML 元素的映射
* 1.name :参数的名称。如果操作是远程过程调用(RPC)类型并且未指定partName 属性,
* 那么这是用于表示参数的 wsdl:part 属性的名称。如果操作是文档类型或者参数映射至某个头,那么 -name 是用于表示该参数的 XML 元素的局部名称。
* 如果操作是文档类型、参数类型为 BARE 并且方式为 OUT 或 INOUT,那么必须指定此属性。(字符串)
*/
@WebResult(name="helloRequest",targetNamespace="http://webservice.lovo.com/")
@WebMethod(operationName="sayHello1")
public String hello(@WebParam(name="msg")String message);
}
服务端接口实现类
package com.lovo.webservice.impl;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
import org.springframework.stereotype.Service;
import com.lovo.webservice.IHelloService;
/*
* endpointInterface: 服务接口全路径, 指定做SEI(Service EndPoint Interface)服务端点接口,简单的说就写接口的全路径
*/
@WebService(endpointInterface="com.lovo.webservice.IHelloService")
@SOAPBinding(style=Style.RPC)
public class HelloServiceImpl implements IHelloService {
@Override
public String hello(String message) {
return "你好" + message;
}
}
前面的两段代码只是简单的java加上一些注解,下面把代码整合入Spring的web工程
web.xml 配置
需在web.xml中配置CXF
cxf
org.apache.cxf.transport.servlet.CXFServlet
1
cxf
/webservice/*
完整的xml文件:
Spring
webAppRootKey
Spring.root
contextConfigLocation
/WEB-INF/classes/applicationContext.xml
log4jConfigLocation
/WEB-INF/log4j.xml
log4jRefreshInterval
60000
org.springframework.web.util.Log4jConfigListener
org.springframework.web.context.ContextLoaderListener
index.jsp
characterEncodingFilter
org.springframework.web.filter.CharacterEncodingFilter
encoding
UTF-8
forceEncoding
true
characterEncodingFilter
/*
cxf
org.apache.cxf.transport.servlet.CXFServlet
1
cxf
/webservice/*
Spring
org.springframework.web.servlet.DispatcherServlet
Spring
/
配置cxf的配置文件,这个也可以直接配置在Spring的配置文件中,看项目风格吧
在application.xml中引入cxf.xml
完整的application.xml
下面来测试下发布是否成功,我这里是tomcat 工程名是Spring,拦截的是webservice,所以访问的地址是:http://localhost:8080/Spring/webservice?wsdl
出现界面
右键连接地址可以下载wsdl
这样就发布了一个简单的webservice接口,下面在发布一个接口以便wsdl的时候做对比,然后再发布一个rest风格的接口
package com.lovo.webservice;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
/**
* SOAP协议的webservice接口
* @author WZH
*服务器端,服务提供者
*/
/*
* @WebService 标记为一个webservice接口
* 1.targetNamespace:指定你想要的名称空间,默认认是使用接口实现类的包名的反缀,
* 但是在实际测试中发现cxf+spring编写webservice的时候,targetNamespace要指向
* 服务类的接口所在的包名而不是实现类的包名,否则,在客户端将不能识别可用的服务
* 2.serviceName: 对外发布的服务名,指定 Web Service 的服务名称:wsdl:service。
* 缺省值为 Java 类的简单名称 + Service。(字符串)
* 3.portName: wsdl:portName。缺省值为 WebService.name+Port。
*
* @SOAPBinding 消息绑定, 这个标记怎么说,我这里测试的时候加不加都无所谓,但是有同仁说过
* 不加这个有时候会出现客户端无法识别,有的人又报错,所以还是加上吧
* Exception in thread "main" com.sun.xml.internal.ws.model.RuntimeModelerException:
* runtime modeler error: Wrapper class org.soap.service.jaxws.Add is not found. Have you run APT to generate them?
*/
@WebService(targetNamespace ="http://webservice.lovo.com/",serviceName="HelloService",portName="HellowServicePort")
@SOAPBinding(style=Style.RPC)
public interface IHelloService {
/*
* @WebResult 注释用于定制从返回值至 WSDL 部件或 XML 元素的映射。将此注释应用于客户机或服务器服务端点接口(SEI)上的方法,
* 或者应用于 JavaBeans 端点的服务器端点实现类
* 1.name:当返回值列示在 WSDL 文件中并且在连接上的消息中找到该返回值时,指定该返回值的名称。对于 RPC 绑定,这是用于表示返回值的
* 2.targetNamespace:指定返回值的 XML 名称空间。仅当操作类型为 RPC 或者操作是文档类型并且参数类型为 BARE 时才使用此参数。(字符串)
*
* @WebMethod 注释表示作为一项 Web Service 操作的方法,将此注释应用于客户机或服务器服务端点接口(SEI)上的方法,
* 或者应用于 JavaBeans 端点的服务器端点实现类。
* 1.operationName:指定与此方法相匹配的wsdl:operation 的名称。缺省值为 Java 方法的名称。(字符串)
*
* @WebParam 注释用于定制从单个参数至 Web Service 消息部件和 XML 元素的映射
* 1.name :参数的名称。如果操作是远程过程调用(RPC)类型并且未指定partName 属性,
* 那么这是用于表示参数的 wsdl:part 属性的名称。如果操作是文档类型或者参数映射至某个头,那么 -name 是用于表示该参数的 XML 元素的局部名称。
* 如果操作是文档类型、参数类型为 BARE 并且方式为 OUT 或 INOUT,那么必须指定此属性。(字符串)
*/
@WebResult(name="helloRequest",targetNamespace="http://webservice.lovo.com/")
@WebMethod(operationName="sayHello1")
public String hello(@WebParam(name="msg")String message);
@WebResult(name="loginRequest",targetNamespace="http://webservice.lovo.com/")
@WebMethod(operationName="login")
public String login(@WebParam(name="userName")String userName,@WebParam(name="password")String password);
}
这里需要特别注意,targetNamespace中路径结尾需写反斜杠/不然会出现问题
package com.lovo.webservice.impl;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
import org.springframework.stereotype.Service;
import com.lovo.webservice.IHelloService;
/*
* endpointInterface: 服务接口全路径, 指定做SEI(Service EndPoint Interface)服务端点接口,简单的说就写接口的全路径
*/
@WebService(endpointInterface="com.lovo.webservice.IHelloService")
@SOAPBinding(style=Style.RPC)
public class HelloServiceImpl implements IHelloService {
@Override
public String hello(String message) {
return "你好" + message;
}
@Override
public String login(String userName, String password) {
String req = null;
//这里做个假的登录验证
if("小明".equals(userName)&&"123456".equals(password))
{
req = "登录成功";
}else
{
req = "登录失败";
}
return req;
}
}
这个时候再访问wsdl的网址就看见有两个方法了
下载wsdl
阅读wsdl的方法
详细的阅读方式方式可以看这篇文章:http://blog.csdn.net/liuchunming033/article/details/41210151
拿到一个wsdl,个人一般是先看最后,也就是wsdl:service部分。
wsdl:service:存放接口名和接口地址
然后再看binding部分,也就是wsdl:binding
wsdl:binding:每个端口定义消息格式和协议细节
再看portType部分,wsdl:portType
wsdl:portType:描述webservice可被执行的操作,以及相关的消息,通过binding指向portType
在看message,wsdl:message
wsdl:message:定义一个操作(方法)的数据参数(可有多个参数)
最后还是需要看看开始部分
这么一个简单的xml就解析完了
完整的xml文档
wsdl阅读完成了,需要的参数都明白了,下面就可以做个简单的客户端进行调用,webService客户端调用的方法有很多,我们这里简单的做几个。
一:Service编程方式
特点:可以自定义关键元素,方便以后维护,是一种标准的开发方式
首先写一个客户端调用对象
package com.lovo.client;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
/**
* 客户端调用者,根据wsdl初始化接口对象
* @author WZH
*
*targetNamespace 对应wsdl抬头 targetNamespace,serviceName和portName分别对应wsdl结尾的wsdl:service name="HelloService"
*和wsdl:port binding="tns:HelloServiceSoapBinding" name="HellowServicePort">
*因为wsdl文档中有指定SOAP类型,所以需书写类型
*/
@WebService(targetNamespace="http://webservice.lovo.com/",serviceName="HelloService",portName="HellowServicePort")
@SOAPBinding(style=Style.RPC)
public interface HellowService {
/**
* 方法名对应wsdl wsdl:operation name="login"
* @param username 参数名对应 wsdl:part name="userName" type="xsd:string"
* @param password
* @return
*
* 方法名映射
* 地址映射
* 参数映射:
*/
@WebResult(name="login",targetNamespace="http://webservice.lovo.com/")
@WebMethod(operationName = "login")
public String login(@WebParam(name = "userName")String username , @WebParam(name = "password")String password);
@WebResult(name="helloRequest",targetNamespace="http://webservice.lovo.com/")
@WebMethod(operationName="sayHello1")
public String hello(@WebParam(name="msg")String msg);
}
这里需要特别注意,targetNamespace中路径结尾需写反斜杠/不然会出现问题
准备工作做好了,可以做个客户端的调用了
package com.lovo.client;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import javax.xml.ws.soap.SOAPBinding;
public class wsClient {
/**
* XML 类 第一个参数表示地址,第二个参数表示端口名
* 这里第一个参数是wsdl 表头targetNamespace
* 第二个参数是service name
*/
private static final QName SERVICE_NAME = new QName("http://webservice.lovo.com/", "HelloService");
private static final QName PORT_NAME = new QName("http://webservice.lovo.com/", "HellowServicePort");
//编程方式一 begin -----------------------
public static void testSayHello()
{
try {
//创建Serivce业务类
Service service = Service.create(SERVICE_NAME);
//连接地址
String endPointAddress = "http://localhost:8080/Spring/webservice/HelloService";
//配置业务访问参数 portName, bindingId, endpointAddress,
//这里因为是SOPA11的所有配置11,SOAP现在有11和12两种 可通过xmlns:ns1="http://schemas.xmlsoap.org/soap/http" 判断
service.addPort(PORT_NAME, SOAPBinding.SOAP11HTTP_BINDING, endPointAddress);
//把本地客户端的接口与网络上的WSDL连接起来
HellowService hs = service.getPort(HellowService.class);
System.out.println(hs.hello("小明"));
} catch (Exception e) {
e.printStackTrace();
}
}
//end-------------------------------------
//编程方式二 begin 不知道为什么 Service.create报错,可能是jar原因-----------------------
public static void testSayHello2()
{
try
{
//创建WSDL的URL,注意不是服务地址
URL url = new URL("http://localhost:8080/Spring/webservice?wsdl");
//创建服务名,代码有写成了静态常量,这里直接引用
//创建服务视图
javax.xml.ws.Service service = Service.create(url, SERVICE_NAME);
//获取服务实例
HellowService hs = service.getPort(new QName("http://webservice.lovo.com/", "HellowServicePort"), HellowService.class);
System.out.println(hs.hello("小明"));
} catch (Exception e)
{
e.printStackTrace();
}
}
//end-------------------------------------
public static void main(String[] args) {
//testSayHello();
testSayHello2();
}
}
剩下的等有空的再完善