前言
计算机语言分类有很多,如C、C++、C#、Java、PHP、Python等等,她们有各自的特性及擅长的领域,但她们各自又不是全能的。在一个稍微大型一点的项目都会用到多种语言共同完成,那么这些编程语言如何进行通信呢。什么意思呢,就是比如说我Java写的一个方法,其他编程语言要怎么去调用呢?这就是本文要探讨的问题了。
一般来说,方法层面的编程语言通信用的是网络接口形式,只暴露出形参和结果供别人调用。接口一般分为接口定义者和接口调用者,定义者可以规定接收参数的类型及返回形式,而接口定义者则只能完全按照接口定义者规定的参数进行访问。就叫是我们所说的webService(网络服务)。
以前的做法是利用XML作接口格式定义,然后通过Http做通讯和请求,如大名鼎鼎的SOAP,其实现在也是的,只不过现在流行RestFul风格的Rest接口形式,但用的还是XML+HTTP,那这两者有啥区别呢?最大的区别就是SOAP返回的主要是XML格式,有时还需要附带一些辅助文件,而Rest则还可以返回JSON类型的字符串,减少了很多繁乱的XML标签。
由于这篇文章之前是转载的,比较乱,在这里说声抱歉!!!!!
现在重新写一下,见谅。
一、接口给外部调用(举例)
1.我们的CURD暴露到Controller层,让前端调用。外部项目调用一般通过HttpClient/OkHttp等直接调用。这种方式是比较多的。
2.WebService
3.服务间调用(注册中心等等)
......
这里就以WebService示例,服务端如何暴露接口,客户端如何调用。
二、WebService
1.定义
WebService是一种远程调用技术,也叫XML Web Service WebService,是一种可以接收从Internet或者Internet上的其他系统中传递过来的请求,轻量级的独立的通信技术。是通过SOAP在Web上提供的软件服务,使用WSDL文件进行说明,并通过UDDI进行注册。
SOAP:全名为(Simple Object Access Protocol)简单对象存取协议。是XML Web Service的通信协议。当用户通过UDDI找到你的WSDL描述文档后,他可以通过SOAP调用你建立的Web服务中的一个或多个操作。SOAP是XML 文档形式的调用方法的规范,他可以支持不同的底层接口,像HTTP/HTTPS或者SMTP。
XML:(Extensible Markup Language)扩展型可标记语言。面向短期的临时数据处理、面向万维网(WWW), 是SAOP的基础。
WSDL:(Web Services Description Language)WSDL是用于说明一组SOAP消息以及如何交换这些消息 的XML文档。
2.实现方式
2.1.Jdk方式
1.服务端 定义接口类 接口实现类 发布类
2.main方法运行(发布)
3.cmd 命令 执行 wsimport -s 生成文件路径 -keep 你的wsdl Url
wsimport -s D:\YlDream\WorkSpace\springbootDevelop\springboot-test\src\client -keep http://localhost:8019/api_server/webservice?wsdl
4.客户端调用
WebService服务端
定义WebService 接口
package com.yl.springboottest.api.webservice.server;
import javax.jws.WebMethod;
import javax.jws.WebService;
/**
* 描述: 定义WebService 接口
*
* @WebService 表示此类是一个元数据注释(JSR 181) 关于JSR181本文不做涉及
* @WebMethod 表示表示此方法是要被发布出去的方法,
* 仅支持在使用@WebService注解标注的类中使用@WebMethod注解
*
* @author: yanglin
* @Date: 2020-11-19-10:19
* @Version: 1.0
*/
@WebService
public interface IWebService {
@WebMethod
String firstWebServiceApi(String name);
}
WebService 接口实现
package com.yl.springboottest.api.webservice.server;
import lombok.extern.slf4j.Slf4j;
import javax.jws.WebService;
/**
* 描述: WebService 接口实现
*
* @author: yanglin
* @Date: 2020-11-19-10:19
* @Version: 1.0
*/
@Slf4j
@WebService
public class WebServiceImpl implements IWebService{
@Override
public String firstWebServiceApi(String name) {
name = "你好,"+name+",这是我的第一个WebService";
log.info("firstWebServiceApi start {}", name);
return name;
}
}
WebService 服务端发布
三种发布方式
1.main方法运行(测试)
2.使用ServletContextListener监听器发布WebService
3.使用Servlet发布WebService
package com.yl.springboottest.api.webservice.server;
import lombok.extern.slf4j.Slf4j;
import javax.xml.ws.Endpoint;
/**
* 描述: WebService 操作 服务端
* 1.main方法运行(测试)
* @author: yanglin
* @Date: 2020-11-19-10:15
* @Version: 1.0
*/
@Slf4j
public class WebServiceServerT1 {
public static void main(String[] args) {
/**
* 1.定义一个WebService的发布地址(暴露出来,让外界访问)
*/
String webAddress = "http://localhost:8019/api_server/webservice";
/**
* 2.使用Endpoint类提供的publish方法发布WebService,发布时确保端口没有被占用
*/
Endpoint.publish(webAddress, new WebServiceImpl());
log.info("WebService 发布成功,URL= {}", webAddress+"?wsdl");
}
}
package com.yl.springboottest.api.webservice.server;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import javax.xml.ws.Endpoint;
/**
* 描述: 2.用于发布WebService的监听器
* 使用Servlet3.0提供的@WebListener注解将实现了ServletContextListener接口的
* WebServicePublishListener类标注为一个Listener
*
* @author: yanglin
* @Date: 2020-11-19-10:52
* @Version: 1.0
*/
@Slf4j
@WebListener
public class WebServicePublishListener implements ServletContextListener {
@Override
public void contextDestroyed(ServletContextEvent sce) {
log.info("contextDestroyed start ");
}
@Override
public void contextInitialized(ServletContextEvent sce) {
/**
* 1.定义一个WebService的发布地址(暴露出来,让外界访问)
*/
String webAddress = "http://localhost:8019/api_server/webservice";
/**
* 2.使用Endpoint类提供的publish方法发布WebService,发布时确保端口没有被占用
*/
Endpoint.publish(webAddress, new WebServiceImpl());
log.info("WebServicePublishListener WebService 发布成功,URL= {}", webAddress+"?wsdl");
}
}
package com.yl.springboottest.api.webservice.server;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.xml.ws.Endpoint;
/**
* 描述: 3.用于发布WebService的Servlet
*
* 使用Servlet3.0提供的@WebServlet注解将继承HttpServlet类的普通Java类标注为一个Servlet
*
* 将value属性设置为空字符串,这样WebServicePublishServlet就不提供对外访问的路径
* loadOnStartup属性设置 WebServicePublishServlet的初始化时机
*
* @author: yanglin
* @Date: 2020-11-19-10:55
* @Version: 1.0
*/
@Slf4j
@WebServlet(value = "", loadOnStartup = 0)
public class WebServicePublishServlet extends HttpServlet {
/**
* 在WebServicePublishServlet初始化时发布WebService
* @throws ServletException
*/
@Override
public void init() throws ServletException {
/**
* 1.定义一个WebService的发布地址(暴露出来,让外界访问)
*/
String webAddress = "http://localhost:8019/api_server/webservice";
/**
* 2.使用Endpoint类提供的publish方法发布WebService,发布时确保端口没有被占用
*/
Endpoint.publish(webAddress, new WebServiceImpl());
log.info("WebServicePublishServlet WebService 发布成功,URL= {}", webAddress+"?wsdl");
}
}
main方法启动成功(监听器/Servlet则是项目启动成功),访问定义的地址
http://localhost:8019/api_server/webservice?wsdl
一定要记得加?wsdl
WebService客户端
通过wsdl生成对应的客户端文件,复制到项目所在目录
新建测试类-客户端调用
package com.yl.springboottest.api.webservice.client;
import lombok.extern.slf4j.Slf4j;
/**
* 描述: WebService 操作 客户端 直接调用
*
* @author: yanglin
* @Date: 2020-11-19-10:45
* @Version: 1.0
*/
@Slf4j
public class WebServiceClientT1 {
public static void main(String[] args) {
WebServiceImplService factory = new WebServiceImplService();
WebServiceImpl serviceImpl = factory.getWebServiceImplPort();
String result = serviceImpl.firstWebServiceApi("张三");
log.info("WebServiceClientT1 result {}", result);
}
}
2.2.CXF方式操作WebService
maven pom
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-spring-boot-starter-jaxws</artifactId>
<version>3.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-core</artifactId>
<version>3.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>3.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>3.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>3.2.5</version>
</dependency>
Cxf服务端
package com.yl.springboottest.api.webservice.server.cxf;
import javax.jws.WebMethod;
import javax.jws.WebService;
/**
* 描述: CXF 方式操作WebService
*
* @author: yanglin
* @Date: 2020-11-19-11:02
* @Version: 1.0
*/
@WebService(targetNamespace = "http://yldream.com/" ,name = "cxfPortType")
public interface ICXFWebService {
/**
* 获取全部用户信息
*/
@WebMethod(operationName = "getCxfApi")
String cxfWebServiceApi(String name);
}
package com.yl.springboottest.api.webservice.server.cxf;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.jws.WebService;
/**
* 描述: XF 方式操作WebService
*
* @author: yanglin
* @Date: 2020-11-19-11:05
* @Version: 1.0
*/
@Slf4j
@Service
@WebService(
targetNamespace = "http://yldream.com/", //wsdl命名空间
name = "cxfPortType", //portType名称 客户端生成代码时 为接口名称
serviceName = "cxfWebService", //服务name名称
portName = "cxfPortName", //port名称
endpointInterface = "com.yl.springboottest.api.webservice.server.cxf.ICXFWebService")//指定发布webservcie的接口类,此类也需要接入@WebService注解
public class CXFWebServiceImpl implements ICXFWebService{
@Override
public String cxfWebServiceApi(String name) {
name = "你好,"+name+",这是我的第一个WebService";
log.info("cxfWebServiceApi start {}", name);
return name;
}
}
package com.yl.springboottest.api.webservice.server.cxf;
import org.apache.cxf.Bus;
import org.apache.cxf.bus.spring.SpringBus;
import org.apache.cxf.jaxws.EndpointImpl;
import org.apache.cxf.transport.servlet.CXFServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.xml.ws.Endpoint;
/**
* 描述: springboot cxf 操作WebService
*
* 配置成功,URL访问 http://localhost:8019/api_server/api?wsdl
*
* @author: yanglin
* @Date: 2020-11-19-11:07
* @Version: 1.0
*/
@Configuration
public class CxfWebServiceConfig {
/**
* 这里需要注意 由于springmvc 的核心类 为DispatcherServlet
* 此处若不重命名此bean的话 原本的mvc就被覆盖了。可查看配置类:DispatcherServletAutoConfiguration
* 一种方法是修改方法名称 或者指定bean名称
* 这里需要注意 若beanName命名不是 cxfServletRegistration 时,会创建两个CXFServlet的。
* 具体可查看下自动配置类:Declaration org.apache.cxf.spring.boot.autoconfigure.CxfAutoConfiguration
* 也可以不设置此bean 直接通过配置项 cxf.path 来修改访问路径的
* @return
*/
@Bean("cxfServletRegistration")
public ServletRegistrationBean dispatcherServlet(){
return new ServletRegistrationBean(new CXFServlet(),"/api_server/*");
}
/**
* 申明业务处理类 当然也可以直接 在实现类上标注 @Service
*/
@Bean
public ICXFWebService cxfService() {
return new CXFWebServiceImpl();
}
/**
* 非必要项
* @return
*/
@Bean(name = Bus.DEFAULT_BUS_ID)
public SpringBus springBus() {
SpringBus springBus = new SpringBus();
return springBus;
}
/**
* 发布endpoint
* @return
*/
@Bean
public Endpoint endpoint1( ) {
EndpointImpl endpoint = new EndpointImpl(springBus(), cxfService());
// 发布地址
endpoint.publish("/api");
return endpoint;
}
}
启动项目,访问URL http://localhost:8019/api_server/api?wsdl
Cxf客户端
通过cxf-codegen-plugin插件生成客户端文件
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-spring-boot-starter-jaxws</artifactId>
<version>3.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-core</artifactId>
<version>3.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>3.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>3.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>3.2.5</version>
</dependency>
<!-- cxf-codegen-plugin -->
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>3.2.5</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<sourceRoot>${project.build.directory}/generated/cxf</sourceRoot>
<wsdlOptions>
<wsdlOption>
<wsdl>src/main/resources/wsdl/api.wsdl</wsdl>
<wsdlLocation>classpath:wsdl/api.wsdl</wsdlLocation>
</wsdlOption>
</wsdlOptions>
</configuration>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
</plugin>
客户端调用代码
package com.yl.springboottest.api.webservice.client.cxf;
import lombok.extern.slf4j.Slf4j;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
/**
* 描述: CXF 方式Client调用WebService 直接调用
*
* @author: yanglin
* @Date: 2020-11-19-13:11
* @Version: 1.0
*/
@Slf4j
public class CXFWebServiceClientT1 {
public static void main(String[] args) {
// 动态调用
JaxWsDynamicClientFactory dcflient = JaxWsDynamicClientFactory.newInstance();
Client client=dcflient.createClient("http://localhost:8019/api_server/api?wsdl");
try{
Object[] objects = client.invoke("getCxfApi","ylDream");
log.info("CXFWebServiceClientT1 getCxfApi 调用结果:{}", objects[0].toString());
}catch (Exception e){
e.printStackTrace();
}
}
}
调用结果