前面简单介绍了一下webservice ,这里快速建立一个例子学习。
这是我用到的jar:可能版本有差异,主要包括 cxf,jetty 服务 io http util ,xml规范等
cxf 可以去:http://cxf.apache.org/download.html 下载,注意版本匹配
cxf-2.3.11.jar
jetty-continuation-7.4.5.v20110725.jar
jetty-http-7.4.5.v20110725.jar
jetty-io-7.4.5.v20110725.jar
jetty-server-7.4.5.v20110725.jar
jetty-util-7.4.5.v20110725.jar
wsdl4j-1.6.2.jar
XmlSchema-1.4.7.jar
一、 业务场景:
假设我系统需要提供一个接口让另外的系统可以登录,相当于第三方访问,有点像单点登录。
我们的方法是提供一个接口,接受第三方传来的用户名和密码,通过接口在我方系统进行调用,然后返回一个布尔值,判定登录是否成功。
二、开发步骤
假设我们的web 项目叫webservice,然后建立一个登录的接口,并且实现它。
import javax.jws.WebParam;
import javax.jws.WebService;
// 单点登录的接口
// @WebService 这表是需要暴露出这个接口,也是所谓的(SEI)
@WebService
public interface ILoginService {
// 加入@WebParam 表示强制指定参数名字,不加生成出来的方法参数默认会是arg0..
public boolean login(@WebParam(name="name") String name,@WebParam(name="password")String password);
}
下面是业务逻辑,这里临时写得很简单。
import javax.jws.WebService;
// endpointInterface 限定接口位置
@WebService(endpointInterface="com.user.ILoginService")
public class LoginServiceImpl implements ILoginService{
public boolean login(String name, String password) {
// 数据临时写死
if("admin".equals(name)&&"1234".equals(password)){
return true;
}
return false;
}
}
下面是发布:
import javax.xml.ws.Endpoint;
// 这是一种发布方式
public class WebServer {
public static void main(String[] args) {
System.out.println("Starting Server");
// 实现类
ILoginService implementor = new LoginServiceImpl();
// 地址
String address = "http://localhost:8080/login";
// 发布
Endpoint.publish(address, implementor);
System.out.println("publish over");
}
}
运行这个类,不报错的话,在浏览器输入http://localhost:8080/login?wsdl 出现xml 就算成功了。
你可以将上面的页面保存下来,后缀用wsdl,那么这个wsdl 就能生产客户端,让别人访问了。
下面我们将保存下来的wdsl 文件拿到,看如何生产客户端和服务器端。
三、场景2:别人给你了一个wdsl 文件,或者比如:http://localhost:8080/login?wsdl 这个地址,要让你生成 客户端,去调用别人的接口。
我这里是用cxf 命令,进行生成的,首先要下一个cxf 的源文件,和jdk 的差不多,含有bin 目录,你可以通过配置环境变量配置进去,当然我是没有配置,直接通过cmd 命令进入bin目录,然后命令生成。
我的cxf 目录: D:\MMS文件\cxf-axis-jar\apache-cxf-2.3.11\bin
我的wdsl 目录:D:\MMS文件\cxf-axis-jar\apache-cxf-2.3.11\bin\wsdl\login.wsdl
在doc 下,进入该目录:D:\MMS文件\cxf-axis-jar\apache-cxf-2.3.11\bin>
wsdl2java -p com.user.client -d d:/ -client D:\MMS文件\cxf-axis-jar\apache-cxf-2.3.11\bin\wsdl\login.wsdl
这样你就可就在d:/ 盘下生成了,包名是com.user.client 的Java 文件。
更多命令 参考 http://blog.csdn.net/pengchua/article/details/2740565
生成的service 构造有错,不影响,版本有点差异,按默认的改就行了
生成主要包含几个部分文件:
1.service 和 serviceImpl 也就是接口以及实现。
2.xxxx_client,这里是负责你测试调用的,它和平时你调用的业务方法类似
3.xxxReponse ,这里面主要是返回值,定义的返回对象,上面接口返回的就是boolean,可以返回集合
4.ObjectFactory ,package-info 这里面是一些限制,暂时不用
5.如果参数和返回值 包含很多实体,那么都可以生成,文件相对较多,暂时不用管。
下面我们主要来看ServiceImpl 和 client 方法。
@WebServiceClient(name = "LoginServiceImplService",
wsdlLocation = "file:/D:/MMS文件/cxf-axis-jar/apache-cxf-2.3.11/bin/wsdl/login.wsdl",
targetNamespace = "http://user.com/")
public class LoginServiceImplService extends Service {
public final static URL WSDL_LOCATION;
public final static QName SERVICE = new QName("http://user.com/", "LoginServiceImplService");
public final static QName LoginServiceImplPort = new QName("http://user.com/", "LoginServiceImplPort");
static {
URL url = null;
try {
url = new URL("file:/D:/MMS文件/cxf-axis-jar/apache-cxf-2.3.11/bin/wsdl/login.wsdl");
} catch (MalformedURLException e) {
java.util.logging.Logger.getLogger(LoginServiceImplService.class.getName())
.log(java.util.logging.Level.INFO,
"Can not initialize the default wsdl from {0}", "file:/D:/MMS文件/cxf-axis-jar/apache-cxf-2.3.11/bin/wsdl/login.wsdl");
}
WSDL_LOCATION = url;
}
// ......下面的代码略
上面的实现类,可以看出仅仅是注解了一些属性,已经没有 login方法了,他通过url 地址(因为这里我没有根据ip 生成,因此是绝对路径),继承Service 接口,当我们调用的时候实际是通过消息代理,将我们要执行的操作发送到服务器端进行执行。下面我看client 的调用。
我们可以建一个新项目,表示是远程调用。
/**
* Please modify this class to meet your needs
* This class is not complete
*/
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.namespace.QName;
/**
* This class was generated by Apache CXF 2.3.11
* 2013-11-07T15:40:01.015+08:00
* Generated source version: 2.3.11
*
*/
public final class ILoginService_LoginServiceImplPort_Client {
private static final QName SERVICE_NAME = new QName("http://user.com/", "LoginServiceImplService");
private ILoginService_LoginServiceImplPort_Client() {
}
// 主函数
public static void main(String args[]) throws java.lang.Exception {
// 获得实现类的url
URL wsdlURL = LoginServiceImplService.WSDL_LOCATION;
// 这代码,一般我都删除了
if (args.length > 0) {
File wsdlFile = new File(args[0]);
try {
if (wsdlFile.exists()) {
wsdlURL = wsdlFile.toURI().toURL();
} else {
wsdlURL = new URL(args[0]);
}
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
// 这是主要逻辑代码 获得 service 和端口。
LoginServiceImplService ss = new LoginServiceImplService(wsdlURL, SERVICE_NAME);
ILoginService port = ss.getLoginServiceImplPort();
// 下面就是调用了,我们实际开发中 主要就是参考着两段代码进行
{
System.out.println("Invoking login...");
java.lang.String _login_name = "admin";
java.lang.String _login_password = "1234";
boolean _login__return = port.login(_login_name, _login_password);
System.out.println("login.result=" + _login__return);
}
System.exit(0);
}
}
小结:
1.例子很简单,仅仅先了解一个过程。
2.自动生成的代码只有主要逻辑,对各种异常的处理,我们要特殊处理。
3.代码省略的很多注解,加上肯定更加规范,这里暂时不介绍了。
4.实际开发中,这些有SOA部门封装,定义一个统一的wsdl 进行。
其他:可以尝试一个复杂点的,参数和返回值 都是对象,然后完善注解