之前系统中使用到了webservice进行第三方通信,这里总结一下常见的5种客户端调用方式。

在此之前我们先简单搭建一个webservice服务端项目,发布一个webservice服务。我这里使用springboot快速搭建一个,项目结构如下:

创建一个springboot项目,导入maven依赖:

<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional>
</dependency>
<dependency><groupId>org.apache.cxf</groupId><artifactId>cxf-spring-boot-starter-jaxws</artifactId><version>3.3.5</version>
</dependency>

创建一个数据传输对象:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserDto {private String name;private int age;private Sex sex;
}

这里声明一个性别的枚举类型:

public enum Sex {MALE("male"), FEMALE("female");String value;private Sex(String value) {this.value = value;}public String value() {return value;}
}

创建一个接口,作为服务发布的接口类,为了简单只声明一个方法:

/*** 创建webservice服务接口*/
@WebService(targetNamespace = "http://webservice.simplewebserviceserver.learn.com"/*一般把包名倒着写*/,name = "userService")
public interface UserService {/*** 通过用户名获取用户** @param userName* @return*/@WebMethod(operationName = "getUserByName")UserDto getUserByName(@WebParam(name = "userName") String userName);}

创建接口的实现类:

@WebService(targetNamespace = "http://webservice.simplewebserviceserver.learn.com"/*wsdl命名空间*/,name = "UserService"/*portType名称 客户端生成代码时 为接口名称*/,serviceName = "userService"/*服务name名称*/,portName = "userPortName"/*port名称*/,endpointInterface = "com.learn.simplewebserviceserver.webservice.UserService"/*指定发布webservcie的接口类,此类也需要接入@WebService注解*/)
public class UserServiceImpl implements UserService {@Overridepublic UserDto getUserByName(String userName) {return new UserDto(userName, 23, Sex.MALE);}
}

增加一个webservice的配置类:

@Configuration
public class CxfWebServiceConfig {// 这里需要注意 若beanName命名不是 cxfServletRegistration 时,会创建两个CXFServlet的。// 具体可查看下自动配置类:Declaration// org.apache.cxf.spring.boot.autoconfigure.CxfAutoConfiguration// 也可以不设置此bean 直接通过配置项 cxf.path 来修改访问路径的@Bean("cxfServletRegistration")public ServletRegistrationBean<CXFServlet> cxfServletRegistration() {// 注册servlet 拦截/ws 开头的请求 不设置 默认为:/services/*return new ServletRegistrationBean<CXFServlet>(new CXFServlet(), "/ws/*");}/*** 申明业务处理类 当然也可以直接 在实现类上标注 @Service**/@Beanpublic UserService userService() {return new UserServiceImpl();}/** 非必要项*/@Bean(name = Bus.DEFAULT_BUS_ID)public SpringBus springBus() {SpringBus springBus = new SpringBus();return springBus;}/** 发布endpoint*/@Beanpublic Endpoint endpoint(UserService userService) {EndpointImpl endpoint = new EndpointImpl(springBus(), userService);endpoint.publish("/user");// 发布地址return endpoint;}
}

到此一个简单的webservice服务端项目就搭建完成了,这里我在application.properties文件中把端口改成8081:

server.port=8081

启动项目,访问http://127.0.0.1:8081/ws/user?wsdl,如果出现以下内容则表示启动成功了:

下面介绍一下webservice客户端如何调用服务端发布的服务:

方式一:使用jdk原生代码实现调用
必要条件:
1.webservice服务端发布地址
2.webservice服务发布的接口类
3.参数和返回值实体类
创建一个maven项目,结构如下:

其中Sex,UserDto,UserService同服务端的代码,导入maven依赖:

     <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.12</version><scope>provided</scope></dependency><dependency><groupId>org.apache.cxf</groupId><artifactId>cxf-core</artifactId><version>3.3.5</version></dependency>

核心调用代码:

public class UserClient {public static void main(String[] args) throws MalformedURLException {URL url = new URL("http://127.0.0.1:8081/ws/user?wsdl");// 指定命名空间和服务名称QName qName = new QName("http://webservice.simplewebserviceserver.learn.com", "userService");Service service = Service.create(url, qName);// 通过getPort方法返回指定接口UserService myServer = service.getPort(new QName("http://webservice.simplewebserviceserver.learn.com", "userPortName"), // 绑定端口名称UserService.class);// 调用方法 获取返回值UserDto userDto = myServer.getUserByName("张三");System.out.println(userDto);}
}

方式二:使用wsimport 命令,生成客户端代码然后再调用
wsimport -keep -d D:\temp\d -s D:\temp\s -p com.map -verbose http://127.0.0.1:8081/ws/user?wsdl
将生成的代码导入项目中正常使用即可,网上资料很多,这里不做赘述。

方法三:动态调用,根据发布地址动态生成客户端然后调用方法
必要条件:
1.webservice服务端发布地址
2.调用方法使用的参数和返回值
3.如果参数或返回值是实体类,需要根据指定的namespace创建实体类
创建一个maven项目,结构如下:

其中Sex,UserDto,UserService同服务端的代码,注意这里的实体类的包名是有限制的必须和服务端中的targetNamespace属性值一样,否则会报错,导入maven依赖:

     <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.12</version><scope>provided</scope></dependency><dependency><groupId>org.apache.cxf</groupId><artifactId>cxf-core</artifactId><version>3.3.5</version></dependency><dependency><groupId>org.apache.cxf</groupId><artifactId>cxf-rt-transports-http</artifactId><version>3.3.5</version></dependency><dependency><groupId>org.apache.cxf</groupId><artifactId>cxf-rt-frontend-jaxws</artifactId><version>3.3.5</version></dependency>

核心调用代码:

public class UserClient {// 创建动态客户端private static Client client = null;static {JaxWsDynamicClientFactory factory = JaxWsDynamicClientFactory.newInstance();client = factory.createClient("http://127.0.0.1:8081/ws/user?wsdl");// 需要密码的情况需要加上用户名和密码// client.getOutInterceptors().add(new// ClientLoginInterceptor(USER_NAME,PASS_WORD));HTTPConduit conduit = (HTTPConduit) client.getConduit();HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();httpClientPolicy.setConnectionTimeout(2000); // 连接超时httpClientPolicy.setAllowChunking(false); // 取消块编码httpClientPolicy.setReceiveTimeout(120000); // 响应超时conduit.setClient(httpClientPolicy);}public static void main(String[] args) {// client.getOutInterceptors().addAll(interceptors);//设置拦截器try {Object[] objects = null;// invoke("方法名",参数1,参数2,参数3....);objects = client.invoke("getUserByName", "李四");System.out.println((UserDto) objects[0]);} catch (Exception e) {e.printStackTrace();}System.out.println(client);}
}

方式四:代理工厂的方式
必要条件:
1.webservice服务端发布地址
2.webservice服务发布的接口类
3.参数和返回值实体类
创建一个maven项目,结构如下:

其中Sex,UserDto,UserService同服务端的代码,导入maven依赖:

     <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.12</version><scope>provided</scope></dependency><dependency><groupId>org.apache.cxf</groupId><artifactId>cxf-core</artifactId><version>3.3.5</version></dependency><dependency><groupId>org.apache.cxf</groupId><artifactId>cxf-rt-transports-http</artifactId><version>3.3.5</version></dependency><dependency><groupId>org.apache.cxf</groupId><artifactId>cxf-rt-frontend-jaxws</artifactId><version>3.3.5</version></dependency>

核心调用代码:

public class UserClient {public static void main(String[] args) throws MalformedURLException {JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();factory.setServiceClass(UserService.class);factory.setAddress("http://127.0.0.1:8081/ws/user?wsdl");UserService service = (UserService) factory.create();// 通过代理对象获取本地客户端Client client = ClientProxy.getClient(service);// 需要密码的情况需要加上用户名和密码// client.getOutInterceptors().add(new// ClientLoginInterceptor(USER_NAME,PASS_WORD));HTTPConduit conduit = (HTTPConduit) client.getConduit();HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();httpClientPolicy.setConnectionTimeout(2000); // 连接超时httpClientPolicy.setAllowChunking(false); // 取消块编码httpClientPolicy.setReceiveTimeout(120000); // 响应超时conduit.setClient(httpClientPolicy);// client.getOutInterceptors().addAll(interceptors);//设置拦截器try {UserDto user = service.getUserByName("王五");System.out.println("返回数据:" + user);} catch (Exception e) {e.printStackTrace();}}
}

方法五:使用httpClient的方式调用,需要借助第三方工具SoapUI获取请求xml数据格式的内容,同时请求响应内容是xml格式内容,需要自己解析。
创建一个maven项目,导入maven依赖:

     <dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.11</version></dependency>

这里主要的是需要借助SoapUi工具,SoapUi的安装和使用网上教程有很多,这里不再赘述,总之我们借助SoapUi是为了得到请求的xml格式数据,核心调用代码:

public class UserClient {public static void main(String[] args) {// soap服务地址String url = "http://127.0.0.1:8081/ws/user?wsdl";StringBuilder soapBuilder = new StringBuilder(64);soapBuilder.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");soapBuilder.append("<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:web=\"http://webservice.simplewebserviceserver.learn.com\">");soapBuilder.append("   <soapenv:Header/>");soapBuilder.append("   <soapenv:Body>");soapBuilder.append("      <web:getUserByName>");soapBuilder.append("        <!--Optional:-->");soapBuilder.append("         <userName>").append("王大力").append("</userName>");soapBuilder.append("      </web:getUserByName>");soapBuilder.append("   </soapenv:Body>");soapBuilder.append("</soapenv:Envelope>");// 创建httpcleint对象CloseableHttpClient httpClient = HttpClients.createDefault();// 创建http Post请求HttpPost httpPost = new HttpPost(url);// 构建请求配置信息RequestConfig config = RequestConfig.custom().setConnectTimeout(1000) // 创建连接的最长时间.setConnectionRequestTimeout(500) // 从连接池中获取到连接的最长时间.setSocketTimeout(3 * 1000) // 数据传输的最长时间10s.build();httpPost.setConfig(config);CloseableHttpResponse response = null;try {// 采用SOAP1.1调用服务端,这种方式能调用服务端为soap1.1和soap1.2的服务httpPost.setHeader("Content-Type", "text/xml;charset=UTF-8");// 采用SOAP1.2调用服务端,这种方式只能调用服务端为soap1.2的服务// httpPost.setHeader("Content-Type", "application/soap+xml;charset=UTF-8");StringEntity stringEntity = new StringEntity(soapBuilder.toString(), Charset.forName("UTF-8"));httpPost.setEntity(stringEntity);response = httpClient.execute(httpPost);// 判断返回状态是否为200if (response.getStatusLine().getStatusCode() == 200) {String content = EntityUtils.toString(response.getEntity(), "UTF-8");System.out.println(content);} else {System.out.println("调用失败!");}} catch (Exception e) {e.printStackTrace();} finally {if (null != response) {try {response.close();} catch (IOException e) {e.printStackTrace();}}if (null != httpClient) {try {httpClient.close();} catch (IOException e) {e.printStackTrace();}}}}
}

返回内容:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:getUserByNameResponse xmlns:ns2="http://webservice.simplewebserviceserver.learn.com"><return><age>23</age><name>王大力</name><sex>MALE</sex></return></ns2:getUserByNameResponse></soap:Body>
</soap:Envelope>

到此,常用的webservice客户端调用方式就介绍完了,我自己还是比较建议使用代理工厂的方式方式进行webservice方法调用,这种方式简单快捷,也方便跟springboot项目整合,当然具体使用哪种方法应该根据实际工作出发。

经过测试发现,服务端和客户端的参数实体类中字段不必完全一样,只要保证任一接收端的参数实体中字段可以完全覆盖发送端的参数实体类中的有效字段即可。

例如,发送端实体类:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserDto {private String name;private Integer age;private Integer id;private String message;}

接收端实体类:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserDto {private String name;// private Integer age;// private Integer id;// private String message;}

调用:

     UserDto userDto = new UserDto();userDto.setName("张三");userDto.setAge(null);userDto.setId(null);objects = client.invoke("getUser", userDto);

由于此时有效字段只有name,所以这样调用,系统也可以正常运行。

WebService客户端调用常见5种方式相关推荐

  1. Git 分支管理常见三种方式

    Git 分支管理常见三种方式 TBD(Trunk-based development.单主干) GitHub flow git-flow 1. TBD 所有团队成员都在单个主干分支上进行开发. 发布时 ...

  2. spring-cloud调用服务两种方式

    spring-cloud调用服务有两种方式,一种是Ribbon+RestTemplate, 另外一种是Feign. Ribbon是一个基于HTTP和TCP客户端的负载均衡器,其实feign也使用了ri ...

  3. Dubbo 同步、异步调用的几种方式

    我们知道,Dubbo 缺省协议采用单一长连接,底层实现是 Netty 的 NIO 异步通讯机制:基于这种机制,Dubbo 实现了以下几种调用方式: 同步调用 异步调用 参数回调 事件通知 同步调用 同 ...

  4. 替代反射调用的几种方式及性能测试

    园子里和这个话题的相关文章比较多,本文是旧话重提,外加个小的总结.主要因为近期看到很多同事.朋友都已经使用 VS2012 进行 .NET 4.5 开发了,却还在大量使用反射,不知道用新的方式.或有所了 ...

  5. delphi 异步 调用 带参数_Dubbo 关于同步/异步调用的几种方式

    我们知道,Dubbo 缺省协议采用单一长连接,底层实现是 Netty 的 NIO 异步通讯机制:基于这种机制,Dubbo 实现了以下几种调用方式: 同步调用 异步调用 参数回调 事件通知 同步调用 同 ...

  6. 【我是初学者】关于获取配置文件.properties的常见三种方式--只是常见的方式,欢迎牛神来加瓦

    首先所谓的获取,肯定跟位置有一定的关系,智商在80的人应该都能理解,那我们的配置文件在项目结构中的三个基本的常见位置是: 因为配置文件通常都是用map键值对来实现的一种方式,所以要拿到根据键去拿到配置 ...

  7. DLL 文件调用的2种方式

    一个共享库导出给用户使用的类,符号,函数等都需要使用宏Q_DECL_EXPORT来定义导出, 一个使用共享库的应用程序需要通过定义Q_DECL_IMPORT 导入共享库里的可用对象. WIN32 平台 ...

  8. python和c语言相通吗_python和C语言互相调用的几种方式

    1 2 3 4 5 6 7 8 9 版权申明:本文为博主窗户(Colin Cai)原创,欢迎转帖.如要转贴,必须注明原文网址 http://www.cnblogs.com/Colin-Cai/p/75 ...

  9. python和C语言互相调用的几种方式

    Python这些年风头一直很盛,占据了很多领域的位置,Web.大数据.人工智能.运维均有它的身影,甚至图形界面做的也很顺,乃至full-stack这个词语刚出来的时候,似乎就是为了描述它. Pytho ...

最新文章

  1. 《数据结构》学习笔记一:绪论
  2. WinForm 曲线图控件
  3. 024_Jedis连接池
  4. Zoj 3201 Tree of Tree
  5. Java反射机制的适用场景及其利与弊 ***
  6. Django项目与中间件与celery
  7. java arp 攻击_用JAVA代码实现ARP攻击 | 学步园
  8. Git入门教程(一)
  9. 『无聊透顶』一篇很无聊的文章
  10. Zookeeper Tutorial 2 -- Programmer's Guide
  11. Mongodb 备份 还原 导出 导入 等批量操作
  12. (14) ZYNQ AXI4-Lite总线简介(学无止境)
  13. 程序猿的每日单词(一)
  14. 从牛顿定律到飞行器动力学
  15. 字符串查找函数和错误信息报告函数
  16. 使用PHP环境一键安装包快速搭建PHP开发环境
  17. 实验2:天气查询小程序
  18. 基于劈窗算法的地表温度反演算法
  19. 虚幻4蓝图快速入门(一)
  20. 前台替换用户名部分转换为*显示

热门文章

  1. 自定义tag打包Bootstrap模态对话框并动态加载传值
  2. 探寻C++读取文件最快的方式
  3. 佰家当:盘活万亿民间资产,国内首家资产流通平台横空出世
  4. Nginx+Vue.js+Tornado前后端分离架构环境实践(1)
  5. 关于CPU寄存器的那些事儿(5)——指令寄存器
  6. 阳光养猪场的套路有哪些?
  7. 关联规则FpGrowth算法 Java实现
  8. 使用IDEA进行项目复制迁移
  9. 分布式专题-分布式消息通信之ActiveMQ03-ActiveMQ原理分析(下)
  10. 基于51单片机的MQ-5天然气监测报警系统设计