模拟webservice接口,分别用动态客户端方式和利用WSDL文档通过http两种方式进行调用

前言

最近由于甲方那边想要一个在JAVA代码里面调用webservice实例的小demo,于是乎便接触到了这一块。主要是由于我们项目架了KONG网关并限定了请求方式的影响,导致平常的动态客户端方式无法成功调用webservice实例,因此便花了半天多时间研究了下webservice服务这一块,并利用soap协议通过http成功调用,虽然有局限性,但是至少提供了个思路。

问题

在这里插入图片描述这里甲方写了两种方式进行接口调用,但是由于我们KONG网关限定了请求方式,导致怎么都调用不成功。
在这里插入图片描述
利用PostMan调用的时候,返回的是webservice的wsdl文档。

在这里插入图片描述这里是动态调用的报错信息。

解决过程

一、创建webservice接口

这里主要是利用Apache提供的cxf包来模拟客户端调用webservice接口。
首先创建一个webservice接口端的工程

这是工程需要用到的依赖

	 <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
        </dependency>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.6</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-bundle</artifactId>
            <version>2.7.18</version>
        </dependency>
    </dependencies>

创建IWebService接口

package src;

import src.dao.Info;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;

/**
 * @author LinZS
 * @description
 * @date 2020/11/17 17:17
 */
@WebService
public interface IWebService
{
    @WebMethod
    public String excute(@WebParam(name="param") String s);

    @WebMethod
    public String testString(Info param);
}

创建IWebService实现类

package src.impl;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import src.IWebService;
import src.dao.Info;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;

/**
 * @author LinZS
 * @description
 * @date 2020/11/17 17:22
 */
@WebService
public class WebServiceImpl implements IWebService {
    @WebMethod
    @Override
    public String excute(@WebParam(name="param") String param)
    {
        System.out.println(param);
        Gson json = new Gson();//需要引入Gson包
        Info info = json.fromJson(param, new TypeToken<Info>(){}.getType());
        Integer id = info.getId();
        System.out.println(id);
        return "服务端成功接收消息";
    }

    @WebMethod
    @Override
    public String testString(Info param)
    {
        return "dddd";
    }
}


创建Info实体类

package src.dao;

import lombok.Data;

/**
 * @author LinZS
 * @description
 * @date 2020/11/17 17:55
 */
@Data
public class Info {
    private Integer id;

    private String key;

    private String result;
}

创建服务端启动类

package src;

import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
import src.impl.WebServiceImpl;

/**
 * @author LinZS
 * @description
 * @date 2020/11/17 17:25
 */
public class Launcher {
    public static void main(String[] args)
    {
        JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();
        factory.setServiceClass(IWebService.class);
        // 发布接口
        factory.setAddress("http://localhost:9000/ws/" + IWebService.class.getSimpleName());
        factory.setServiceBean(new WebServiceImpl());
        factory.create();
    }
}

至此,服务端接口就模拟完成了。

二、模拟客户端调用webservice

接下来让我们另起一个工程模拟客户端,来试验我们的接口能否使用。
maven依赖的引入是和服务端工程一样的。
并且同样创建一个Info实体类,和IWebService接口类,创建完成后,创建工程启动类。

package src;

import com.google.gson.Gson;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import src.dao.Info;
import java.security.NoSuchAlgorithmException;
/**
 * @author LinZS
 * @description
 * @date 2020/11/17 17:41
 */
public class TestImpl {
    public static void main(String[] args) throws NoSuchAlgorithmException
    {

        Gson gson = new Gson();
        Info info = new Info();
        info.setId(123);
        info.setResult("中国");
        String s = gson.toJson(info);
          //创建动态客户端
        JaxWsProxyFactoryBean factoryBean=new JaxWsProxyFactoryBean();
        /*factoryBean.getInInterceptors().add(new LoggingInInterceptor());
        factoryBean.getOutInterceptors().add(new LoggingOutInterceptor());  */
        factoryBean.setServiceClass(IWebService.class);
        factoryBean.setAddress("http://localhost:9000/ws/IWebService?wsdl");

        IWebService webService=(IWebService) factoryBean.create();
        System.out.println(webService.excute(s));
    }
}

创建完成之后,我们先启动接口类,再启动客户端类,如果没有问题的话,服务端打印如下:

在这里插入图片描述
客户端打印如下
在这里插入图片描述至此,模拟客户端调用webservice接口的demo,就完成了。

三、复现甲方问题

由于我们工程是利用Kong网关做的资源转发,因此甲方在提供webservice实例的时候限定了GET请求,我在这就复现了一下。
在这里插入图片描述

结果很明显,和甲方一样的报错,因此我判断,应该是请求方式导致调用不成功。
因为我们的网关将资源转发出去后,适用的是HTTP请求,而webservice客户端用的是WSDL报文,两者的请求方式是不同的,而且我们Kong网关还加上了权限,需要在请求头的Authorization项带上Token,这也就间接导致了客户端方式直接调用不成功的问题。

四、改用Http请求调用webservice实例

首先在pom文件里添加上HttpClient需要的依赖

 		<dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpcore</artifactId>
            <version>4.4.1</version>
        </dependency>

然后在我们客户端的启动类里,改用以下方式调用webservice。

 		//返回体接收类
        ResponseHandler<String> responseHandler = new ResponseHandler<String>() {
            public String handleResponse(
                    final HttpResponse response) throws ClientProtocolException, IOException {
                int status = response.getStatusLine().getStatusCode();
                if (status >= 200 && status < 300) {
                    HttpEntity entity = response.getEntity();
                    if(null!=entity){
                        String result= EntityUtils.toString(entity);
                        return result;
                    }else{
                        return null;
                    }
                } else {
                    throw new ClientProtocolException("Unexpected response status: " + status);
                }
            }
        };
        CloseableHttpClient httpclient = HttpClientBuilder.create().build();
        //注意此处的ip要与webservice接口端的ip一致
        HttpGet httpget = new HttpGet("http://192.168.124.9:8000/server/OvSR9h5V6w?WSDL");
        httpget.setHeader("Authorization", "Basic djJ4YmRlbXBsb3lUb3pSVFZxVTokMmEkMTAkU0pweDE5Z1Y5TW9WdERCYnV2Nm5OTzRqTFFNOHZ5TjlsM3dKZ3k4NC55VmdWbDNXa1BvRmE=");

        // 执行get请求.
        String response = null;
        try {
            response = httpclient.execute(httpget,responseHandler);
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("接收到的数据"+response);

改用http请求方式之后,我们没办法直接将想要发送的参数,传给服务端,并且由于限定了Get请求,服务端直接反馈了WSDL文档,无法正确调用。

在这里插入图片描述

在网上查阅了相关资料之后,发现大部分利用http对webservice的请求方式,都用的是POST,而非GET,我们这边GET请求只能获取WSDL报文的话,那我们将报文转成SOAP协议,问题不就迎刃而解了吗?

五、Http利用SOAP协议调用webservice

此时,我们已经有了WSDL文档,只要将它转成SOAP协议,我们就可以利用POST请求,成功调用被Kong网关转发的webservice实例了。
首先,我们需要它
在这里插入图片描述
这里附上下载链接
SoapUI 5.2.1下载地址

下载安装之后,右键project新建。
在这里插入图片描述
然后继续右键ADD WSDL
在这里插入图片描述

在这里插入图片描述
选择之后,会生成两个SOAP协议
在这里插入图片描述
因为我们刚才写的是excute请求方式,所以我们选择第一个。
客户端启动类代码改用如下:

		Gson gson = new Gson();
        Info info = new Info();
        info.setId(123);
        info.setResult("中国");
        String s = gson.toJson(info);
        String retStr = "";
        //SOAP消息格式
        String soapXml = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:src=\"http://src/\">\n" +
                "   <soapenv:Header/>\n" +
                "   <soapenv:Body>\n" +
                "      <src:excute>\n" +
                "         <!--Optional:-->\n" +
                "         <param>"+s+"</param>\n" +
                "      </src:excute>\n" +
                "   </soapenv:Body>\n" +
                "</soapenv:Envelope>";
        CloseableHttpClient closeableHttpClient = HttpClientBuilder.create().build();
        //创建httpPost
//        HttpPost httpPost = new HttpPost("http://192.168.124.9:8000/server/OvSR9h5V6w?WSDL");
        HttpPost httpPost = new HttpPost("http://192.168.124.9:8000/server/AQt0kTuF6r4?WSDL");
        RequestConfig requestConfig = RequestConfig.custom()
                .setSocketTimeout(30000)
                .setConnectTimeout(30000).build();
        httpPost.setConfig(requestConfig);
        httpPost.setHeader("Authorization", "Basic djJ4YmRlbXBsb3lUb3pSVFZxVTokMmEkMTAkU0pweDE5Z1Y5TW9WdERCYnV2Nm5OTzRqTFFNOHZ5TjlsM3dKZ3k4NC55VmdWbDNXa1BvRmE=");
        httpPost.setHeader("User-Agent",
                "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.111 Safari/537.36");
        httpPost.setHeader("Content-Type", "text/xml;charset=UTF-8");
        httpPost.setHeader("SOAPAction", "");
        try {
            StringEntity data = new StringEntity(soapXml,
                    Charset.forName("UTF-8"));
            httpPost.setEntity(data);
            CloseableHttpResponse response = closeableHttpClient
                    .execute(httpPost);
            HttpEntity httpEntity = response.getEntity();
            if (httpEntity != null) {
                // 打印响应内容
                retStr = EntityUtils.toString(httpEntity, "UTF-8");
                System.out.println("response:" + retStr);
            }
            // 释放资源
            closeableHttpClient.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

改用SOAP协议的方式,我们成功利用Http请求调用了被Kong网关转发的webservice实例。
在这里插入图片描述

总结

甲方的demo要求解决了,虽然有局限性,需要事先得到WSDL文档,但是作为webservice实例的提供方,提供WSDL文档,或者说提供SOAP消息格式都是轻轻松松的事情,无伤大雅。
这次的问题解决,主要学到了以下几点:
1.客户端的请求方式和Http请求方式在请求头和请求体上的协议区别
2.HttpGet请求webservice实例由于无法将特定参数带过去,导致我们只能请求到WSDL文档。
3.在HttpPost请求里加上SOAP消息格式,并将所需参数放入消息格式中一起放入Entity里面,便可以成功调用webservice实例。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Apache CXF是一个开源的WebService框架,可以帮助用户快速、简便地开发和部署WebService应用程序。它提供了多种方式调用WebService接口,下面介绍几种常用的方式: 1. 使用JAX-WS API:CXF实现了JAX-WS API,可以直接使用JAX-WS提供的API来调用WebService。示例代码如下: ```java HelloWorldService service = new HelloWorldService(); HelloWorld port = service.getHelloWorldPort(); String result = port.sayHello("CXF"); ``` 2. 使用代理方式:CXF可以根据WebService WSDL文件自动生成代理类,然后通过调用代理类的方法来调用WebService接口。示例代码如下: ```java JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(); factory.setServiceClass(HelloWorld.class); factory.setAddress("http://localhost:8080/HelloWorld"); HelloWorld client = (HelloWorld) factory.create(); String result = client.sayHello("CXF"); ``` 3. 使用Spring配置文件:CXF提供了Spring配置文件方式来实现WebService接口调用。用户可以在Spring配置文件中配置WebService客户端,然后通过Spring容器来获取WebService客户端实例。示例代码如下: ```xml <jaxws:client id="helloClient" serviceClass="com.example.HelloWorld" address="http://localhost:8080/HelloWorld"/> ``` ```java ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml"); HelloWorld client = (HelloWorld) context.getBean("helloClient"); String result = client.sayHello("CXF"); ``` 以上是几种常用的调用WebService接口方式,可以根据具体情况选择适合自己的方式
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值