使用CXF发布WebService
这里普及一下WebService和cxf的知识、关于webservice和cxf:
WebService: 简单来说是一种远端方法调用(暴露本地的方法接口给外部,客户端可以通过远端调用的方式调用)
SOA (面向服务架构): IBM提倡面向服务的架构, 希望以-组装电脑-的形式开发软件
SOA:1、各种提供服务的组件
2、企业总线、通讯总线(ESB)
CXF:是一个SOA框架,Axis和XFire是原生态的WebService框架,由此可见,CXF是优秀与后两者的
SOAP(简单对象访问协议):包含了两个标签,header和body,header是由程序员添加的,可以没有,
但是body标签是必须的。
body标签分为两种情况:1.当WebService调用成功的时候,由WSDL控制。
2.当WebService调用失败的时候,会生成fault元素,而fault元素又
包含两个部分:2.1错误码;2.2错误信息
html+xml脚本片段
-------------------------------------------------------------------------------
CXF环境变量配置
将CXF的bin目录放到path环境变量
wsdl2java --检测cxf环境配置是否成功
cxf对jdk的要求是1.6.17或以上
-------------------------------------------------------------------------------
WebService之间至少需要两个部分:接口和实现类
CXF自动携带了一个Jetty web Server,但是实际中并不使用它,多数使用Tomcat或WebLogic
-------------------------------------------------------------------------------
使用XCF开发WebService的服务端
1.开发一个WebService的业务接口,并且该接口使用@WebService修饰
2.开发接口的实现类,该实现类也需要采用@WebService修饰
3.发布WebService并且对外暴露WSDL,采用EndPoint类的静态方法publish发布,该类由java提供
-------------------------------------------------------------------------------
客户端调用WebService服务
1.使用CXF提供的wsdl2java命令生成远端代理
2.找到生成的代理类中的一个继承了service的类可以作为工厂使用,调用service子类中的一个叫getXXXport的方法
得到远端接口服务代理对象
3.远端代理调用
使用wsdl2java http://127.0.0.1/firstcxf?wsdl执行远端代码,生成java文件,生成的java文件会有错误,
原因是:javax.xml.ws.Service类中没有Service(wsdlLocation,SERVICE,features); 构造器。
解决方法是:导入一个geronimo-javax_2.2_spec-1.1.jar提供最新版本的Service类,但是这个方法不建议(移植性差)
可以使用:wsdl2java -frontend http://127.0.0.1/firstcxf?wsdl
SOA (面向服务架构): IBM提倡面向服务的架构, 希望以-组装电脑-的形式开发软件
SOA:1、各种提供服务的组件
2、企业总线、通讯总线(ESB)
CXF:是一个SOA框架,Axis和XFire是原生态的WebService框架,由此可见,CXF是优秀与后两者的
SOAP(简单对象访问协议):包含了两个标签,header和body,header是由程序员添加的,可以没有,
但是body标签是必须的。
body标签分为两种情况:1.当WebService调用成功的时候,由WSDL控制。
2.当WebService调用失败的时候,会生成fault元素,而fault元素又
包含两个部分:2.1错误码;2.2错误信息
html+xml脚本片段
-------------------------------------------------------------------------------
CXF环境变量配置
将CXF的bin目录放到path环境变量
wsdl2java --检测cxf环境配置是否成功
cxf对jdk的要求是1.6.17或以上
-------------------------------------------------------------------------------
WebService之间至少需要两个部分:接口和实现类
CXF自动携带了一个Jetty web Server,但是实际中并不使用它,多数使用Tomcat或WebLogic
-------------------------------------------------------------------------------
使用XCF开发WebService的服务端
1.开发一个WebService的业务接口,并且该接口使用@WebService修饰
2.开发接口的实现类,该实现类也需要采用@WebService修饰
3.发布WebService并且对外暴露WSDL,采用EndPoint类的静态方法publish发布,该类由java提供
-------------------------------------------------------------------------------
客户端调用WebService服务
1.使用CXF提供的wsdl2java命令生成远端代理
2.找到生成的代理类中的一个继承了service的类可以作为工厂使用,调用service子类中的一个叫getXXXport的方法
得到远端接口服务代理对象
3.远端代理调用
使用wsdl2java http://127.0.0.1/firstcxf?wsdl执行远端代码,生成java文件,生成的java文件会有错误,
原因是:javax.xml.ws.Service类中没有Service(wsdlLocation,SERVICE,features); 构造器。
解决方法是:导入一个geronimo-javax_2.2_spec-1.1.jar提供最新版本的Service类,但是这个方法不建议(移植性差)
可以使用:wsdl2java -frontend http://127.0.0.1/firstcxf?wsdl
实际上,webservice就相当与云计算的概念,暴露一个本地的方法接口到web上,就可以给任何人调用,只要提供相应的wsdl。而客户端只需要传递相应的参数就可以实现对webservice的调用,最终可以对返回的结果进行相应的处理。
服务端的代码实现如下:
1.首先创建一个供外界访问的接口:
1 package com.ws; 2 import javax.jws.WebMethod; 3 import javax.jws.WebParam; 4 import javax.jws.WebService; 5 /** 6 * interface 7 * 8 * @author Administrator 9 * 10 */ 11 @WebService 12 public interface HelloWorld { 13 @WebMethod(operationName="sayHi") 14 public String sayHi(@WebParam(name="name")String name); 15 } 16 17 18 2.然后,设计一个类实现该接口,注意头部要添加@WebService注解,其中,endpointInterface的值为接口的完整名称,serviceName为暴露给外界访问的服务名称。 19 20 21 package com.ws.impl; 22 import javax.jws.WebService; 23 import com.ws.HelloWorld; 24 /** 25 * endpointInterface:实现接口的完全路径 26 * serviceName:server名称 27 * 28 * @author Administrator 29 * 30 * WebService 的目的是便于其他的编程语言调用 31 * 32 */ 33 @WebService(endpointInterface="com.ws.HelloWorld",serviceName="Hello") 34 public class HelloWorldImpl implements HelloWorld { 35 @Override 36 public String sayHi(String name) { 37 System.out.println("client called webservice..."); 38 if(name == null){ 39 return "Who are you?"; 40 } 41 return "Hello , "+name; 42 } 43 } 44 45 3.使用Endpoint.publish方法发布WebService到互联网 46 47 48 package com.srv; 49 import javax.xml.ws.Endpoint; 50 import com.ws.HelloWorld; 51 import com.ws.impl.HelloWorldImpl; 52 public class ServerMain { 53 54 /** 55 * 发布webservice 56 * 57 * @param args 58 */ 59 public static void main(String[] args) { 60 //第一种方式:非CXF方法 61 HelloWorld hw = new HelloWorldImpl(); 62 Endpoint.publish("http://127.0.0.1:8888/firstcxf", hw); 63 System.out.println("webservice publish successed!"); 64 65 //System.exit(0); 66 67 68 69 70 //第二种方法(CXF发布),需要导入cxf 的jar包 71 HelloWorldImpl impl = new HelloWorldImpl(); 72 JaxWsServerFactoryBean factoryBean = new JaxWsServerFactoryBean(); 73 factoryBean.setAddress("http://127.0.0.1:8888/firstcxf");//发布地址 74 factoryBean.setServiceClass(HelloWorld.class);//接口类 75 factoryBean.setServiceBean(impl);//发布接口的实现类的实例 76 factoryBean.create(); 77 System.out.println("WS发布成功!"); 78 } 79 }
创建一个WebService客户端的步骤如下:有两种方式:
第一种:
先在客户端编译wsdl,生成对应的java文件,然后根据生成的java通过远端调用的方式调用WebService。
第一步:
进入工程的src目录,执行wsdl2java http://127.0.0.1/firstcxf?wsdl 命令,
生成对应的java文件。
第二步:然后可以根据生成的java文件通过远端调用的方式调用WebService。
下面是第一种方式调用的几种常用方法:
1 package com.client; 2 import java.net.MalformedURLException; 3 import java.net.URL; 4 import javax.xml.namespace.QName; 5 import javax.xml.ws.Service; 6 import javax.xml.ws.soap.SOAPBinding; 7 import org.apache.cxf.jaxws.JaxWsProxyFactoryBean; 8 import com.ws.HelloWorld; 9 import com.ws.impl.Hello; 10 public class ClientMain { 11 /** 12 * 远端调用WebService 13 * 14 * @param args 15 */ 16 public static void main(String[] args) { 17 // 第一种方式,不需要导入cxf包 18 // // 注意。此处http://impl.ws.com/ 来源于wsdl文件中targetNamespace 19 // QName qName = new QName("http://impl.ws.com/", "Hello"); 20 // Hello hello; 21 // try { 22 // hello = new Hello(new URL("http://127.0.0.1:8888/firstcxf?wsdl"), 23 // qName); 24 // HelloWorld service = hello.getPort(HelloWorld.class); 25 // System.out.println(service.sayHi("niha")); 26 // } catch (MalformedURLException e) { 27 // e.printStackTrace(); 28 // } 29 30 31 // 第二种方法 (无需导入cxf包) 32 // Hello service = new Hello(); 33 // //service.getXXXPort返回的是远端接口代理对象 34 // HelloWorld hw = service.getHelloWorldImplPort(); 35 // //远端调用 36 // System.out.println(hw.sayHi("Handle")); 37 38 39 // //第三种方法:采用CXF方法 (需要导入cxf包) 40 // JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(); 41 // //1.设置WebService接口 42 // factory.setServiceClass(HelloWorld.class); 43 // //2.设置wsdl的暴露地址 44 // factory.setAddress("http://127.0.0.1:8888/firstcxf"); 45 // 46 // HelloWorld hw = (HelloWorld) factory.create(); 47 // System.out.println(hw.sayHi(null)); 48 49 // 50 // (不可用) 51 // String endpointAddress = "http://127.0.0.1:8888/firstcxf"; 52 // Service service = Service.create(Hello.SERVICE); 53 // service.addPort(Hello.HelloWorldImplPort, 54 // SOAPBinding.SOAP11HTTP_BINDING, endpointAddress); 55 // HelloWorld helloS = service.getPort(HelloWorld.class); 56 // helloS.sayHi("nihao"); 57 } 58 }
这种方式由于需要显式调用暴露方法的接口来生成一个实例,因此该方法适用于服务器端与客户端处于同一个应用的相同服务下的应用程序。
第二种方式:
可以隐式的调用远端方法,只需要提供相应的字符串参数
1 package com.test; 2 import javax.xml.namespace.QName; 3 import org.apache.cxf.endpoint.Client; 4 import org.apache.cxf.endpoint.Endpoint; 5 import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory; 6 import org.apache.cxf.service.model.BindingInfo; 7 import org.apache.cxf.service.model.BindingOperationInfo; 8 public class Test3 { 9 public static void main(String[] args) { 10 //第一种,知道方法名一定存在直接调用 11 JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance(); 12 Client client = dcf.createClient("http://127.0.0.1:8888/firstcxf?wsdl"); 13 try { 14 QName opName = new QName("http://ws.com/", "sayHi");//设置限定名 15 Object[] result = client.invoke(opName, "lisi"); 16 System.out.println(result[0].toString()); 17 } catch (Exception e) { 18 e.printStackTrace(); 19 } 20 21 22 //第二种方法,较为动态的查找需要调用的方法 23 24 // String wsdl = "http://127.0.0.1:8888/firstcxf?wsdl"; 25 // String operation = "sayHi"; 26 // 27 // JaxWsDynamicClientFactory factory = JaxWsDynamicClientFactory.newInstance(); 28 // Client client = factory.createClient(wsdl); 29 // 30 // // 下面一段处理 WebService接口和实现类namespace不同的情况 31 // // CXF动态客户端在处理此问题时,会报No operation was found with the name的异常 32 // Endpoint endpoint = client.getEndpoint(); 33 // QName opName = new QName(endpoint.getService().getName().getNamespaceURI(), operation); 34 // BindingInfo bindingInfo = endpoint.getEndpointInfo().getBinding(); 35 // if (bindingInfo.getOperation(opName) == null) { 36 // for (BindingOperationInfo operationInfo : bindingInfo.getOperations()) { 37 // if (operation.equals(operationInfo.getName().getLocalPart())) { 38 // opName = operationInfo.getName(); 39 // break; 40 // } 41 // } 42 // } 43 // 44 // String realParams = "Li si"; 45 // try { 46 // Object[] res = client.invoke(opName, realParams); 47 // System.out.println(res[0].toString()); 48 // } catch (Exception e) { 49 // e.printStackTrace(); 50 // } 51 } 52 }
这种方法的好处是只需要知道相关的暴露接口中的方法名,既可以隐式调用,适合于发布的服务器和调用的客户端不处于同一应用,同一服务下的应用程序。
注意:
http://localhost:8080/WSCXF/helloService //为暴露的接口的名称
?wsdl 必须要添加,这个是接口解析成的xml文件