CXF框架:代码优先的开发和契约优先的webservice
https://www.cnblogs.com/decarl/archive/2012/05/15/2502074.html 这个博客对于cxf的开发流程写的比较详细:
他们的核心是服务端和客户端之间传输的报文是wsdl报文:格式是固定的
服务端和客户端之间的报文格式固定,这和socket和http不一样的是交互的报文格式固定。而socket和http报文可以是string ,json xml
客户端向服务端发送的报文:
Josen
服务端返回给客户端的报文:
hi Josen
Cxf框架的内容就是封装发送请求和解析报文的细节:垃圾框架,弄的注解太多太复杂,还不如socket交互,没啥软用。
框架使用的复杂度其实还不如自己去写socket
为什么需要命名空间: 客户端需要命名空间去识别服务端的服务?? 什么狗屁?? 服务端的ip 端口,服务名不能识别码?命名空间是为了防止同个服务器下服务名字相同的服务可以被客户端识别。
为了说明为什么要有命名空间,这里举个生活中的例子。
假如你是研发部的员工,你们部门有个人叫张伟。你和他玩的特别好,天天中午你都会说,张伟我们吃饭去。就这样日子过得挺
平淡的,终于到了过年的时候了,公司开年会,到了抽奖环节的时候这个叫张伟的运气特别好中了一等奖。主持人说,恭喜张伟获得
本次年会一等奖,有请张伟上台领奖!突然站起来2个人。卧槽,当时主持人就懵B了。然后主持人很机智的说,你们猜猜是哪个部门
的张伟?研发部?销售部?最终原来闹了一个笑话,是销售部的。
QName
的值包含名称空间 URI、本地部分和前缀。 QNAme的作用是客户端去访问服务端。
https://www.cnblogs.com/decarl/archive/2012/05/15/2502074.html
代码优先和契约优先: 我靠契约优先就是TM一个坑啊、
Socket 通讯服务基于socket只是远程消息传递,但是webservice实现的不仅仅是消息传递,而是方法调用,远程方法调用,仅仅是消息传递这样是最简单的socket比如qq之类的通讯工具,但是基于远程方法调用就在socket上加了一层,因为是远程方法调用,就需要远程的ip,端口,服务方法名和参数,当然为了唯一服务,还需要一个命名空间,mybatis的对接口的命名空间也是这个意思,为了给方法名一个唯一的标记。
当这个接口有了唯一标记,webservice的服务端就能更好的确定一个唯一的服务。
下面写cxf的流程:
- 先导入jar包,这个tm脑壳疼: 一开始下了很多cxf和jetty的包,但是各种错,于是换了http://www.apache.org/dyn/closer.lua/cxf/3.2.5/apache-cxf-3.2.5.zip 这个地址,啥都有
- 之后就是服务端的代码编写
- 在接口上添加Annotation @WebService,在接口里定义两个方法
-
- package org.decarl.service;
-
- import javax.jws.WebService;
-
- @WebService
- public interface IMyservice {
- public int add (int a, int b);
- public int minus (int a, int b);
- }
-
- 1.2 创建实现类 MyServiceImpl
- 重点注意在类定义上面加上Annotation
-
- @WebService(endpointInterface = "org.decarl.service.IMyservice")
-
- 其中endpointInterface指的是对外提供服务的接口
-
-
- 代码实现如下:
-
-
- package org.decarl.service;
-
- import javax.jws.WebService;
-
- @WebService(endpointInterface = "org.decarl.service.IMyservice")
- public class MyServiceImpl implements IMyservice {
-
- @Override
- public int add(int a, int b) {
- System.out.println(a + "+" + b + "=" + (a + b) );
- return a + b;
- }
-
- @Override
- public int minus(int a, int b) {
- System.out.println(a + "-" + b + "=" + (a - b) );
- return a - b;
- }
- }
-
-
- 1.3 创建服务(开启服务)
- package org.decarl.service;
- import javax.xml.ws.Endpoint;
- public class MyService {
- public static void main(String[] args) {
- String address = "http://localhost:8888/ns";
-
- //第二个参数:要发布这个接口的哪一个实现类
- Endpoint.publish(address, new MyServiceImpl());
-
- //SEI Service Endpoint Interface 服务提供的接口:IMyService
- //SIB Service Implements Bean 服务实现的Bean:MyServiceImpl
- }
- }
- 1.4、建立一个TestClient进行测试
- package org.decarl.service;
-
- import java.net.MalformedURLException;
- import java.net.URL;
- import javax.xml.namespace.QName;
- import javax.xml.ws.Service;
-
- public class TestClient {
- public static void main(String[] args) {
- try {
- //创建访问wsdl服务地址的URL
- URL url = new URL("http://localhost:8888/ns?wsdl");
- //通过QName指明服务的具体信息
- QName sName = new QName("http://service.decarl.org/", "MyServiceImplService");
- //创建服务
- Service service = Service.create(url, sName);
- //实现接口
- IMyservice ms = service.getPort(IMyservice.class);
- System.out.println(ms.add(12, 13));
-
- //以上服务有问题,依然依赖于IMyservice接口
-
- } catch (MalformedURLException e) {
- e.printStackTrace();
- }
- }
- }
-
- 也可以用命令生成代码,前提是有wsdl文件:
wsimport -d D:/wsimport/ -keep -verbose http://localhost:8888/ns?wsdl 前提是你这个服务要开通,不然这个命令会报错的
wsimport -d D:/wsimport/ -p test -verbose http://localhost:8888/ns?wsdl
wsimport -d D:/wsimport/ -p test -verbose D:\wsimport\wsdl.xml 这个命令后边要是wsdl文件在本地也可以使用命令生成,这就是wsdl根据约定开发的一种方式。
这种错误就是服务开启失败。命令无法生成代码
这个是生成的文件代码:
Cxf的客户端调用比较烦,需要服务端同名的类:但是使用HttpClient就不需要了。但是httpclient需要自己组装soap。这也是为什么需要命令去生成上面这些类了,需要上面这些类作为客户端调用,让远程调用看起来像本地调用
其实并不是本地调用,只是cxf这框架使用了代理,对调用的那个方法实现了代理,里面封住了socket请求和报文的组装。