记录一次springboot工程调用webservice

一序

   随着技术的发展,之前的webservice已经被rpc跟restful  json替代了。因为业务需要,调用第三方的webservice接口。网上一搜,基本上都是10年前的文章了。而且好多人是遇到了问题,不知道怎么解决。因为问题多样,仅供参考。

   说这个话题暴露年龄了,网上看java调用的框架无非是:axis、axis2、cxf、xFire等,做服务端与客户端都行,我们要做的事客户端,所以尽量少去引用一堆jar.

二 问题 401

   想尝试使用httpClient来调用,帖子很多,不贴了。

报错: HTTP/1.1 401 Unauthorized

我加上了授权的用户名、密码。

httpPost.addHeader(new BasicHeader("Authorization", "Basic " + Base64.getEncoder().encodeToString((username+":"+password).getBytes())));

这样能解决校验,因为我的参数是自定义对象,所以我传了json.

直接返回500.内部错误了。

所以我理解需要确定xml报文格式了。

三 AXis2

1RPC方式,不生成客户端代码,引入相应的axis2的jar包

2应用document方式调用 ,也就是org.apache.axis2.client.ServiceClient类进行远程调用web服务,不生成客户端

3用wsdl2java工具,生成客户端方式调用webservice服务(不推荐啊)

下面是我的调试之路:

3.1 rpc

为什么我开始选择这种方式呢?

因为我要传参,看上去相对简单些:

https://blog.csdn.net/menghuanzhiming/article/details/78489527?utm_source=blogkpcl4

这篇文章有详细的介绍:

贴一下我关注的点:

    // 使用RPC方式调用WebService
            RPCServiceClient serviceClient = new RPCServiceClient();
            // 创建WSDL的URL,注意不是服务地址
            String url = "http://hiepa.heliteq.com/WebServices/TestWebService.asmx?wsdl";
            // 指定调用WebService的URL
            EndpointReference targetEPR = new EndpointReference(url);
            Options options = serviceClient.getOptions();
            // 确定目标服务地址
            options.setTo(targetEPR);
            options.setAction("http://tempuri.org/Test");
      
           // 指定方法的参数值
            Object[] parameters = new Object[] {"parama", "paramb","paramc"};

            // 创建服务名称
            // 1.namespaceURI - 命名空间地址 (wsdl文档中的targetNamespace)
            // 2.localPart - 服务视图名 
            QName qname = new QName("http://WebXml.com.cn/", "XXaction");


            // 调用方法一 传递参数,调用服务,获取服务返回结果集
            OMElement element = serviceClient.invokeBlocking(qname, parameters);

这个对比下来还是简单些。但是调用接口提示: 

<Status>102</Status><Message>接口异常:未将对象引用设置到对象的实例

虽然我已经设置了

options.setAction("http://WebXml.com.cn/XXaction");

就在这时,我发现了

<soap:operation soapAction="http://tempuri.org/XXaction" style="document"/>

这种方式搜了下,不支持RPC的。所以放弃了。

教训:看这些webservice,不管你喜欢不喜欢,还是要去扫盲下基本概念的。因为这个方法参数多,几十个。一折通半天就过去了,而且对方是ASP。不是一个技术栈,没有Java调用的demo.只有wsdl能看。

3.2  document

先看下wsdl文档:

网上也有很多文章,先看下官网:

public class TestClient {
    private static EndpointReference targetEPR =
        new EndpointReference(
               "http://localhost:8080/axis2/services/SpringAwareService");

    /**
     * Simple axis2 client.
     *
     * @param args Main
     */
    public static void main(String[] args) {
        try {
            OMFactory factory = OMAbstractFactory.getOMFactory();
            OMNamespace omNs = factory.createOMNamespace(
                        "http://springExample.org/example1", "example1");

            OMElement method = factory.createOMElement("getValue", omNs);
            OMElement value = factory.createOMElement("Text", omNs);
            value.addChild(factory.createOMText(value, "Some String "));
            method.addChild(value);

            ServiceClient serviceClient = new ServiceClient();

            Options options = new Options();
            serviceClient.setOptions(options);
            options.setTo(targetEPR);

            //Blocking invocation
            OMElement result = serviceClient.sendReceive(method);

            StringWriter writer = new StringWriter();
            result.serialize(XMLOutputFactory.newInstance()
                    .createXMLStreamWriter(writer));
            writer.flush();

            System.out.println("Response: " + writer.toString());
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
} 

关于传参数,遇到坑了,看上面的wsdl也知道,普通的String类型的,对方能收到,对于复合类型的SDSendOrder。接收不到。

网上看了下,OMElement和Java对象之间的转换。


    public static OMElement object2OMElement(Object[] oArray,String type){
        OMElement omElement=
                BeanUtil.getOMElement(new QName("SDSendOrder"),oArray,new QName(type),false,null);
        return omElement;
    }

    public static OMElement object2OMElement_pull(Object obj){
        XMLStreamReader reader = BeanUtil.getPullParser(obj);
        StreamWrapper parser = new StreamWrapper(reader);
        OMXMLParserWrapper stAXOMBuilder = OMXMLBuilderFactory.createStAXOMBuilder(OMAbstractFactory.getOMFactory(), parser);
        OMElement element = stAXOMBuilder.getDocumentElement();
        return element;
    }

还是不行,传JSON也不行。甚至尝试了jaxb的去传。

这里的经验是,要想快速调:最好借助于可视化工具:soapUI等。找到要发送的报文。

我折腾一下午,终于把这几十个参数报文拼上了,就是理解的歧义,文档上说的传数组,以为外面包一层SDSendOrder,实际上不要直接拼下面的属性就行。

找到报文了。再切回去httpclient.

也行了:状态:HTTP/1.1 200 OK

结果提示:无法连接到远程服务器,那就对方有调用三方服务器。这个需要人工协调了,不是程序的事了,成了一半了。

*******************

总结:

对接三方,这个真的有一些客观制约条件。尤其是非主流的技术栈,需要时间去探索下。

就是:如果你要使用axis2这种框架,那么得关注繁琐的webservice框架,要熟悉下基本概念。反过来:如果确认好报文,那么还是推荐httpclient.

回忆性网上google了前面的一堆文章,留言说:401 怎么办?未将对象引用设置到对象的实例 ?

还有类似的错误,都是很少有回答的,时间几年过去了,我觉得应该早就解决了。

我把我遇到的坑分享一下,如果对你有所帮助,就OK了。

猜你喜欢

转载自blog.csdn.net/bohu83/article/details/106734517
今日推荐