Java调用WebService方法总结(2)--JAX-WS调用WebService

用JAX-WS(Java API for XML Web Services)调用WebService不需要引入其他框架,都是JDK自带的;文中所使用到的软件版本:Java 1.8.0_191。

1、准备

参考Java调用WebService方法总结(1)--准备工作

2、调用

2.1、Dispatch方式

Dispatch又有Payload方式和Message两种方式。

2.1.1、Payload方式

在payload方式中,只需传入SOAP消息中的body部分。

/**
 * dispatch Payload方式调用WebService
 * @param portName 端口名称
 * @param param 参数
 */
public static void dispatchPayload(String portName, String param) {
    try {
        StringBuffer source = new StringBuffer();
        source.append("<web:toTraditionalChinese xmlns:web=\"" + targetNamespace + "\">");
        source.append("<web:sText>").append(param).append("</web:sText>");
        source.append("</web:toTraditionalChinese>");
        StreamSource xmlSource = new StreamSource(new StringReader(source.toString()));
        
        URL wsdlURL = new URL(url);
        QName serviceQName = new QName(targetNamespace, "TraditionalSimplifiedWebService");
        Service service = Service.create(wsdlURL, serviceQName);
        QName portQName = new QName(targetNamespace, portName);
        Dispatch<Source> dispatch = service.createDispatch(portQName, Source.class, Service.Mode.PAYLOAD);
        
        //.NET的服务端Soap1.1需要,不加会报错误:服务器未能识别 HTTP 头 SOAPAction 的值
        Map<String, Object> requestContext = dispatch.getRequestContext();
        requestContext.put(BindingProvider.SOAPACTION_USE_PROPERTY, Boolean.TRUE);
        requestContext.put(BindingProvider.SOAPACTION_URI_PROPERTY, "http://webxml.com.cn/toTraditionalChinese");
        
        Source orderSource = dispatch.invoke(xmlSource);
        StreamResult result = new StreamResult(new ByteArrayOutputStream());
        Transformer trans = TransformerFactory.newInstance().newTransformer();
        trans.transform(orderSource, result);
        ByteArrayOutputStream baos = (ByteArrayOutputStream) result.getOutputStream();
        String responseContent = new String(baos.toByteArray());
        System.out.println(responseContent);

        Reader file = new StringReader(responseContent);
        SAXReader reader = new SAXReader();
        Document dc = reader.read(file);
        Element root = dc.getRootElement();
        String r = root.elementText("toTraditionalChineseResult").trim();
        System.out.println(r);

    } catch (Exception e) {
        e.printStackTrace();
    }
}

2.1.2、Message方式

在Message方式中,需传入整个Soap消息。

/**
 * dispatch Payload方式调用WebService
 * @param soapNamespace soap消息整个消息体的命名空间,Soap1.1和Soap1.2不一样
 * @param portName 端口名称
 * @param param 参数
 */
public static void dispatchMessage(String soapNamespace, String portName, String param) {
    try {
        StringBuffer source = new StringBuffer();
        source.append("<soapenv:Envelope xmlns:soapenv=\"" + soapNamespace + "\" xmlns:web=\"" + targetNamespace + "\">");
        source.append("<soapenv:Header/>");
        source.append("<soapenv:Body>");
        source.append("<web:toTraditionalChinese>");
        source.append("<web:sText>").append(param).append("</web:sText>");
        source.append("</web:toTraditionalChinese>");
        source.append("</soapenv:Body>");
        source.append("</soapenv:Envelope>");
        StreamSource xmlSource = new StreamSource(new StringReader(source.toString()));
        
        URL wsdlURL = new URL(url);
        QName serviceQName = new QName(targetNamespace, "TraditionalSimplifiedWebService");
        Service service = Service.create(wsdlURL, serviceQName);
        QName portQName = new QName(targetNamespace, portName);
        Dispatch<Source> dispatch = service.createDispatch(portQName, Source.class, Service.Mode.MESSAGE);
        
        //.NET的服务端Soap1.1需要,不加会报错误:服务器未能识别 HTTP 头 SOAPAction 的值
        Map<String, Object> requestContext = dispatch.getRequestContext();
        requestContext.put(BindingProvider.SOAPACTION_USE_PROPERTY, Boolean.TRUE);
        requestContext.put(BindingProvider.SOAPACTION_URI_PROPERTY, "http://webxml.com.cn/toTraditionalChinese");
        
        Source orderSource = dispatch.invoke(xmlSource);
        StreamResult result = new StreamResult(new ByteArrayOutputStream());
        Transformer trans = TransformerFactory.newInstance().newTransformer();
        trans.transform(orderSource, result);
        ByteArrayOutputStream baos = (ByteArrayOutputStream) result.getOutputStream();
        String responseContent = new String(baos.toByteArray());
        System.out.println(responseContent);

        Reader file = new StringReader(responseContent);
        SAXReader reader = new SAXReader();
        Document dc = reader.read(file);
        //节点名称为toTraditionalChineseResult 命名空间为http://webxml.com.cn/
        String r = dc.selectSingleNode("//*[local-name()='toTraditionalChineseResult' and namespace-uri()='http://webxml.com.cn/']").getText().trim();
        System.out.println(r);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

2.1.3、完整代码

代码中的设置的信息都可以在准备工作中查询到,或WSDL中或Soap消息中,这里就不一一解释了。完整代码如下:

package com.abc.ws;

import java.io.ByteArrayOutputStream;
import java.io.Reader;
import java.io.StringReader;
import java.net.URL;
import java.util.Map;

import javax.xml.namespace.QName;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
 * JAX-WS Dispatch方式调用WebService样例
 * @author wuyy
 *
 */
public class JaxWsDispatch {
    private static String url = "http://www.webxml.com.cn/WebServices/TraditionalSimplifiedWebService.asmx?wsdl";
    private static String targetNamespace = "http://webxml.com.cn/";
    /**
     * dispatch Payload方式调用WebService
     * @param portName 端口名称
     * @param param 参数
     */
    public static void dispatchPayload(String portName, String param) {
        try {
            StringBuffer source = new StringBuffer();
            source.append("<web:toTraditionalChinese xmlns:web=\"" + targetNamespace + "\">");
            source.append("<web:sText>").append(param).append("</web:sText>");
            source.append("</web:toTraditionalChinese>");
            StreamSource xmlSource = new StreamSource(new StringReader(source.toString()));
            
            URL wsdlURL = new URL(url);
            QName serviceQName = new QName(targetNamespace, "TraditionalSimplifiedWebService");
            Service service = Service.create(wsdlURL, serviceQName);
            QName portQName = new QName(targetNamespace, portName);
            Dispatch<Source> dispatch = service.createDispatch(portQName, Source.class, Service.Mode.PAYLOAD);
            
            //.NET的服务端Soap1.1需要,不加会报错误:服务器未能识别 HTTP 头 SOAPAction 的值
            Map<String, Object> requestContext = dispatch.getRequestContext();
            requestContext.put(BindingProvider.SOAPACTION_USE_PROPERTY, Boolean.TRUE);
            requestContext.put(BindingProvider.SOAPACTION_URI_PROPERTY, "http://webxml.com.cn/toTraditionalChinese");
            
            Source orderSource = dispatch.invoke(xmlSource);
            StreamResult result = new StreamResult(new ByteArrayOutputStream());
            Transformer trans = TransformerFactory.newInstance().newTransformer();
            trans.transform(orderSource, result);
            ByteArrayOutputStream baos = (ByteArrayOutputStream) result.getOutputStream();
            String responseContent = new String(baos.toByteArray());
            System.out.println(responseContent);

            Reader file = new StringReader(responseContent);
            SAXReader reader = new SAXReader();
            Document dc = reader.read(file);
            Element root = dc.getRootElement();
            String r = root.elementText("toTraditionalChineseResult").trim();
            System.out.println(r);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /**
     * dispatch Payload方式调用WebService
     * @param soapNamespace soap消息整个消息体的命名空间,Soap1.1和Soap1.2不一样
     * @param portName 端口名称
     * @param param 参数
     */
    public static void dispatchMessage(String soapNamespace, String portName, String param) {
        try {
            StringBuffer source = new StringBuffer();
            source.append("<soapenv:Envelope xmlns:soapenv=\"" + soapNamespace + "\" xmlns:web=\"" + targetNamespace + "\">");
            source.append("<soapenv:Header/>");
            source.append("<soapenv:Body>");
            source.append("<web:toTraditionalChinese>");
            source.append("<web:sText>").append(param).append("</web:sText>");
            source.append("</web:toTraditionalChinese>");
            source.append("</soapenv:Body>");
            source.append("</soapenv:Envelope>");
            StreamSource xmlSource = new StreamSource(new StringReader(source.toString()));
            
            URL wsdlURL = new URL(url);
            QName serviceQName = new QName(targetNamespace, "TraditionalSimplifiedWebService");
            Service service = Service.create(wsdlURL, serviceQName);
            QName portQName = new QName(targetNamespace, portName);
            Dispatch<Source> dispatch = service.createDispatch(portQName, Source.class, Service.Mode.MESSAGE);
            
            //.NET的服务端Soap1.1需要,不加会报错误:服务器未能识别 HTTP 头 SOAPAction 的值
            Map<String, Object> requestContext = dispatch.getRequestContext();
            requestContext.put(BindingProvider.SOAPACTION_USE_PROPERTY, Boolean.TRUE);
            requestContext.put(BindingProvider.SOAPACTION_URI_PROPERTY, "http://webxml.com.cn/toTraditionalChinese");
            
            Source orderSource = dispatch.invoke(xmlSource);
            StreamResult result = new StreamResult(new ByteArrayOutputStream());
            Transformer trans = TransformerFactory.newInstance().newTransformer();
            trans.transform(orderSource, result);
            ByteArrayOutputStream baos = (ByteArrayOutputStream) result.getOutputStream();
            String responseContent = new String(baos.toByteArray());
            System.out.println(responseContent);

            Reader file = new StringReader(responseContent);
            SAXReader reader = new SAXReader();
            Document dc = reader.read(file);
            //节点名称为toTraditionalChineseResult 命名空间为http://webxml.com.cn/
            String r = dc.selectSingleNode("//*[local-name()='toTraditionalChineseResult' and namespace-uri()='http://webxml.com.cn/']").getText().trim();
            System.out.println(r);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) {
        //Soap1.1对应的portName为TraditionalSimplifiedWebServiceSoap,Soap1.2对应的portName为TraditionalSimplifiedWebServiceSoap12
        dispatchPayload("TraditionalSimplifiedWebServiceSoap", "小学");
        dispatchPayload("TraditionalSimplifiedWebServiceSoap12", "大学");
        
        //Soap1.1对应的soapNamespace为http://schemas.xmlsoap.org/soap/envelope/,Soap1.1对应的soapNamespace为http://www.w3.org/2003/05/soap-envelope
        dispatchMessage("http://schemas.xmlsoap.org/soap/envelope/", "TraditionalSimplifiedWebServiceSoap", "小学");
        dispatchMessage("http://www.w3.org/2003/05/soap-envelope", "TraditionalSimplifiedWebServiceSoap12", "大学");
    }
}
JaxWsDispatch

2.2、Proxy方式

该方式代码很简洁,需把接口类ITestService拷贝到客户端工程里。调用本地服务如下:

package com.abc.ws;

import java.net.URL;

import javax.xml.namespace.QName;
import javax.xml.ws.Service;

import com.abc.ws.ITestService;

/**
 * JAX-WS Proxy调用 ,需把接口类拷贝到客户端
 *
 */
public class JaxWsProxy {
    private static String url = "http://10.49.196.10:9006/myservice/TestService?wsdl";
    private static String targetNamespace = "http://ws.abc.com/";
    
    public static void proxy(String param) {
        try {
            QName qname = new QName(targetNamespace, "TestService");
            Service service = Service.create(new URL(url), qname);
            ITestService testService = service.getPort(ITestService.class);
            System.out.println(testService.hello(param));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) {
        proxy("大学");
    }
}

2.3、RPC方式

RPC方式已不被推荐使用了,但JAX-WS依然支持。改方式与Proxy有点相似,也需把接口类ITestService拷贝到客户端工程里面;与Proxy方式不同的是:接口类还需继承java.rmi.Remote接口,使用的类是javax.xml.rpc包下

package com.abc.ws;

import java.net.URL;

import javax.xml.namespace.QName;
import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceFactory;

import com.abc.ws.ITestService;

/**
 * JAX-WS RPC调用 ,需把接口类拷贝到客户端,接口类需继承java.rmi.Remote接口
 *
 */
public class JaxWsRpc {
    private static String url = "http://10.49.196.10:9006/myservice/TestService?wsdl";
    private static String targetNamespace = "http://ws.abc.com/";
    
    public static void rpc(String param) {
        try {
            ServiceFactory serviceFactory = ServiceFactory.newInstance();
            Service service = serviceFactory.createService(new URL(url), new QName(targetNamespace, "TestService"));
            ITestService testService = (ITestService) service.getPort(ITestService.class);
            String result = testService.hello(param);
            System.out.println(result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) {
        rpc("大学");
    }
}

3、JDK9+ 版本处理

JDK9 及更高版本把 JAX-WS 相关包移除了,如需使用可添加如下包:

<dependency>
    <groupId>com.sun.xml.ws</groupId>
    <artifactId>jaxws-rt</artifactId>
    <version>2.3.7</version>
</dependency>

 

posted @ 2019-11-13 16:43  且行且码  阅读(5779)  评论(8编辑  收藏  举报