WebService最优方案选择

需求

最近,接触到了一个java对接C#的项目,使用WebService技术开发。项目已经快告一段落了,经过这几个月接触和使用。我有了一个清晰的认识,之前也调研了互联网上大部分实现的通讯,他们的优缺点,我都有一定的了解,我认为的最好解决方案是 wsimport生成的代码,让我们看看这几种方式的优缺点吧。

WebService是什么

WebService是一种跨编程语言和跨操作系统平台的远程调用技术。

WebService使用场景

WebService可用于调用第三方系统API。

WebService创建方式

引入依赖

    <dependencies>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-spring-boot-starter-jaxws</artifactId>
            <version>3.5.3</version>
<!--            <exclusions>-->
<!--                <exclusion>-->
<!--                    <groupId>org.apache.cxf</groupId>-->
<!--                    <artifactId>cxf-rt-frontend-jaxws</artifactId>-->
<!--                </exclusion>-->
<!--            </exclusions>-->
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http</artifactId>
            <version>3.5.3</version>
        </dependency>

        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http-jetty</artifactId>
            <version>3.5.3</version>
        </dependency>


    </dependencies>

创建bean

package com.hikktn;
 
import javax.jws.WebMethod;
import javax.jws.WebService;
 
@WebService
public interface IUserService {
 
    @WebMethod
    //返回一个字符串
    String getStr(String str);
}

实现接口

@WebService
public class UserServiceImpl implements IUserService{
 
    @WebMethod
    @Override
    public String getStr(String str) {
        String str2 = null;
        try {
            str2 = new String("处理后的字符串:".getBytes(),"UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        return str2 + str;
    }
}

第一种服务端

import org.apache.cxf.interceptor.Interceptor;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.jaxws.EndpointImpl;
import org.apache.cxf.message.Message;

import javax.xml.ws.Endpoint;
import java.util.List;

public class TestServer {

    private static String PATH = "http://127.0.0.1:7777/WebService_Server/jdk";

    //浏览器输入以上地址访问不到,但是http://127.0.0.1:7777/WebService_Server/jdk?wsdl这个地址可以查看到xml文件
    //相对路径随便写
    public static void main(String[] args) {
        //获取一个EndPoint实例
        EndpointImpl endpoint = (EndpointImpl) Endpoint.publish(PATH, new UserServiceImpl());
        //服务器端获取输入拦截器
        List<Interceptor<? extends Message>> inInterceptors = endpoint.getInInterceptors();
        //添加接受信息日志拦截器
        inInterceptors.add(new LoggingInInterceptor());
        System.out.println("成功发布!");
    }
}

第二种服务端

import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;

/**
 * @author killian
 * @since 2022-11-04 14:54
 */
public class TestServer2 {

    public static void main(String[] args) {

        //以下是编译wsdl文件的另一种方法,这种方法使用CXF的JaxWsServerFactoryBean类中的方法创建
        System.out.println("启动服务器...");
        //创建地址
        String address = "http://127.0.0.1:7777/WebService_Server/cxf";
        //创建一个服务器工厂实例
        JaxWsServerFactoryBean jaxWsServerFactoryBean = new JaxWsServerFactoryBean();
        //设置暴露地址
        jaxWsServerFactoryBean.setAddress(address);
        //设置接口类
        jaxWsServerFactoryBean.setServiceClass(IUserService.class);
        //设置实现类
        jaxWsServerFactoryBean.setServiceBean(uSerService);
        //添加日志拦截器
        jaxWsServerFactoryBean.getInInterceptors().add(new LoggingInInterceptor());
        //创建服务器
        jaxWsServerFactoryBean.create();
        System.out.println("服务器成功启动!");
    }

}

启动服务后,下载Soap软件测试
在这里插入图片描述

放入url
http://127.0.0.1:7777/WebService_Server/jdk?wsdl
就可以测试
在这里插入图片描述

客户端调用(不建议)

public class TestXml {

    public static void main(String[] args) {
        try {
            StringWriter writer = new StringWriter();
            JAXBContext jc = JAXBContext.newInstance(Student.class);
            Marshaller ms = jc.createMarshaller();
            Student st = new Student("zhang", "w", "h", 11);
            ms.marshal(st, writer);
            String xmlStr = writer.toString();
            System.out.println(xmlStr);
        } catch (JAXBException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

这种在网络上都是入门级别,玩玩demo可以。但是你要拿到项目中,就恼火了。
首先,这样的调用方式是完全不管命名空间的调用,而国外的超多API都是有很多嵌套的命名空间xml。
可以说这个是非常致命的缺点,无法生成有效的XML。

hutool调用WebService(简单场景)

具体大家看这篇博客,它有非常详细的教程。
Java使用Hutool调用WebService接口详解
优点:不用写HttpURLConnection通讯,简单的接口可以使用这个来开发。
缺点:代码繁多,没有更加优化的工具类,要去处理返回的XML,处理方式只有转换为Map,非常不利于后续维护和代码编写。

HttpURLConnection原生请求WebService(简单场景)

public class SoapSendUtil {

    /**
     * 默认连接超时
     */
    private static final int connectionTimeout = 60 * 1000;
    /**
     * 默认读取超时
     */
    private static final int readTimeout = 60 * 1000;

    /**
     * 发送请求
     *
     * @param SapPiUrl soap协议url
     * @param xmlStr   soap协议的xml
     * @param action   请求接口url
     * @return 响应报文
     * @throws IOException IO异常
     */
    public static String sendRequest(String SapPiUrl, String xmlStr, String action) throws IOException {
        //创建一个支持HTTP特定功能的URLConnection
        HttpURLConnection httpConn = null;
        //创建一个输出流对象
        OutputStream out = null;
        String returnXml = "";
        //打开链接
        httpConn = (HttpURLConnection) new URL(SapPiUrl).openConnection();
        //设置内容和字符格式
        httpConn.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
        //设置请求和xml
        httpConn.setRequestProperty("SOAPAction", action);
        //设置请求为post亲求
        httpConn.setRequestMethod("POST");
        httpConn.setDoOutput(true);
        httpConn.setDoInput(true);
        httpConn.setConnectTimeout(connectionTimeout);
        httpConn.setReadTimeout(readTimeout);

        httpConn.connect();
        out = httpConn.getOutputStream(); // 获取输出流对象

        httpConn.getOutputStream().write(xmlStr.getBytes()); // 将要提交服务器的SOAP请求字符流写入输出流
        out.flush();
        out.close();
        int code = httpConn.getResponseCode(); // 用来获取服务器响应状态
        System.out.println(code);
        String tempString = null;
        StringBuffer sb1 = new StringBuffer();
        //如果响应状态为ok,就读取http内容
        if (code == HttpURLConnection.HTTP_OK) {
            BufferedReader reader = new BufferedReader(new InputStreamReader(httpConn.getInputStream(), StandardCharsets.UTF_8));
            while ((tempString = reader.readLine()) != null) {
                sb1.append(tempString);
            }
            if (null != reader) {
                reader.close();
            }
        } else {
            BufferedReader reader = new BufferedReader(new InputStreamReader(httpConn.getErrorStream(), StandardCharsets.UTF_8));
            // 一次读入一行,直到读入null为文件结束
            while ((tempString = reader.readLine()) != null) {
                sb1.append(tempString);
            }
            if (null != reader) {
                reader.close();
            }
        }
        // 响应报文
        returnXml = sb1.toString();
        return returnXml;
    }
}
import org.springframework.util.StringUtils;

import javax.xml.bind.*;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.namespace.QName;
import java.io.File;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.Collection;

/**
 * 使用Jaxb2.0实现XMLJava Object的Binder.
 * <p>
 * 特别支持Root对象是List的情形.
 */
public class JaxbBinderUtil {

    /**
     * 多线程安全的Context.
     */
    private JAXBContext jaxbContext;

    /**
     * @param types 所有需要序列化的Root对象的类型.
     */
    public JaxbBinderUtil(Class... types) {
        try {
            jaxbContext = JAXBContext.newInstance(types);
        } catch (JAXBException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Java Object->Xml.
     */
    public String toXml(Object root, String encoding) {
        try {
            StringWriter writer = new StringWriter();
            createMarshaller(encoding).marshal(root, writer);
            return writer.toString();
        } catch (JAXBException e) {
            throw new RuntimeException(e);
        }
    }

    public String toXml(Object root) {
        try {
            StringWriter writer = new StringWriter();
            createMarshaller(StandardCharsets.UTF_8.toString()).marshal(root, writer);
            return writer.toString();
        } catch (JAXBException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Java Object->Xml, 特别支持对Root Element是Collection的情形.
     */
    public String toXml(Collection root, String rootName, String encoding) {
        try {
            CollectionWrapper wrapper = new CollectionWrapper();
            wrapper.collection = root;
            JAXBElement wrapperElement = new JAXBElement(new QName(rootName),
                    CollectionWrapper.class, wrapper);
            StringWriter writer = new StringWriter();
            createMarshaller(encoding).marshal(wrapperElement, writer);
            return writer.toString();
        } catch (JAXBException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Xml->Java Object.
     */
    public Object fromXml(String xml) {
        try {
            StringReader reader = new StringReader(xml);
            return createUnmarshaller().unmarshal(reader);
        } catch (JAXBException e) {
            throw new RuntimeException(e);

        }
    }

    /**
     * 创建Marshaller, 设定encoding(可为Null).
     */
    public Marshaller createMarshaller(String encoding) {
        try {
            Marshaller marshaller = jaxbContext.createMarshaller();
            // 去除XML头
            marshaller.setProperty("com.sun.xml.bind.xmlDeclaration", Boolean.FALSE);
            // 指定是否使用换行和缩排对已编组 XML 数据进行格式化的属性名称
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

            if (StringUtils.isEmpty(encoding)) {
                marshaller.setProperty(Marshaller.JAXB_ENCODING, encoding);
            }
            return marshaller;
        } catch (JAXBException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 创建UnMarshaller.
     */
    public Unmarshaller createUnmarshaller() {
        try {
            return jaxbContext.createUnmarshaller();
        } catch (JAXBException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 封装Root Element 是 Collection的情况.
     */

    public static class CollectionWrapper {

        @XmlAnyElement
        protected Collection collection;

    }

    public Object fromXML(String fileName) {
        return fromXML(new File(fileName));
    }

    public Object fromXML(File file) {
        try {
            Unmarshaller unmarshaller = createUnmarshaller();
            return unmarshaller.unmarshal(file);
        } catch (JAXBException e) {
            throw new RuntimeException(e);
        }
    }

    public Object fromXML(InputStream stream) {
        try {
            Unmarshaller unmarshaller = createUnmarshaller();
            return unmarshaller.unmarshal(stream);
        } catch (JAXBException e) {
            throw new RuntimeException(e);
        }
    }
}

这两个工具类也是由大佬提供,他们需要结合起来编写。
具体使用
对象转 soap_使用jaxb 实现对象与xml之间的转换
优点:解决了上面的返回对象只能转Map的问题
缺点:需要为每个接口的入参和结果集,封装一层SoapBody和SoapHeader,并且要在package-info.java编写命名空间。java版本低一点就没有package-info.java了。

什么事命名空间?

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://server.hikktn.com/">
   <soapenv:Header/>
   <soapenv:Body>
      <ser:getArticle>
         <!--Optional:-->
         <arg0>
            <!--Optional:-->
            <guid>123</guid>
            <!--Optional:-->
            <name>true</name>
         </arg0>
      </ser:getArticle>
   </soapenv:Body>
</soapenv:Envelope>

xmlns后面跟着就是命令空间,它会为下面的xml标签加上一个小前缀。
package-info.java

@XmlSchema(xmlns = {
        @XmlNs(namespaceURI = "http://server.hikktn.com/", prefix = "ser"),
        @XmlNs(namespaceURI = "http://schemas.xmlsoap.org/soap/envelope/", prefix = "soapenv")
})
package com.eci.tbms.memoq.domain.vo;

import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlSchema;

cxf方式

首先,我们需要去下载Apache CXF
CXF官方下载地址
然后解压,cmd打开对应路径。
该方案适用于json格式发送请求。
可以生成去除该字段类型的 客户端代码 ; 比如 JAXBElement 可以变成 String 类型
XML
复制代码

<jaxb:bindings version="2.0"    
               xmlns:jaxb="http://java.sun.com/xml/ns/jaxb">    
    <jaxb:bindings>    
        <jaxb:globalBindings generateElementProperty="false"/>    
    </jaxb:bindings>    
</jaxb:bindings>  

第二步 : 生成客户端代码
LaTeX
复制代码

wsimport -encoding utf-8 -b remove.xml -Xnocompile http://xxxxxxxx?WSDL

-encoding utf-8 表示 编码
-Xnocompile 表示生成java代码, 不加的话, 将会 只生成class 文件
-b 表示绑定指定文件
此时生成的客户端代码中 , 原先的JAXBElement 字段类型 , 就会变成 String 类型;
controller
在controller层使用,会因为各种webservice生成的代码问题,造成一部分问题。
优点:完美的解决了各种xml转换问题。用JSON格式传输。
缺点:就是API生成了所有的API,代码厚重。并不能直接调用,还是需要编写controller。

这个方案我用stackoverflow的例子:
CheckTinService.java:

import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import javax.xml.ws.WebEndpoint;
import javax.xml.ws.WebServiceClient;
import javax.xml.ws.WebServiceException;
import javax.xml.ws.WebServiceFeature;


/**
 * This class was generated by the JAX-WS RI.
 * JAX-WS RI 2.2.4-b01
 * Generated source version: 2.2
 * 
 */
@WebServiceClient(name = "checkTinService", targetNamespace = "urn:ec.europa.eu:taxud:tin:services:checkTin", wsdlLocation = "https://ec.europa.eu/taxation_customs/tin/checkTinService.wsdl")
public class CheckTinService
    extends Service
{

    private final static URL CHECKTINSERVICE_WSDL_LOCATION;
    private final static WebServiceException CHECKTINSERVICE_EXCEPTION;
    private final static QName CHECKTINSERVICE_QNAME = new QName("urn:ec.europa.eu:taxud:tin:services:checkTin", "checkTinService");

    static {
        URL url = null;
        WebServiceException e = null;
        try {
            url = new URL("https://ec.europa.eu/taxation_customs/tin/checkTinService.wsdl");
        } catch (MalformedURLException ex) {
            e = new WebServiceException(ex);
        }
        CHECKTINSERVICE_WSDL_LOCATION = url;
        CHECKTINSERVICE_EXCEPTION = e;
    }

    public CheckTinService() {
        super(__getWsdlLocation(), CHECKTINSERVICE_QNAME);
    }

    public CheckTinService(WebServiceFeature... features) {
        super(__getWsdlLocation(), CHECKTINSERVICE_QNAME);
    }

    public CheckTinService(URL wsdlLocation) {
        super(wsdlLocation, CHECKTINSERVICE_QNAME);
    }

    public CheckTinService(URL wsdlLocation, WebServiceFeature... features) {
        super(wsdlLocation, CHECKTINSERVICE_QNAME);
    }

    public CheckTinService(URL wsdlLocation, QName serviceName) {
        super(wsdlLocation, serviceName);
    }

    public CheckTinService(URL wsdlLocation, QName serviceName, WebServiceFeature... features) {
        super(wsdlLocation, serviceName);
    }

    /**
     * 
     * @return
     *     returns CheckTinPortType
     */
    @WebEndpoint(name = "checkTinPort")
    public CheckTinPortType getCheckTinPort() {
        return super.getPort(new QName("urn:ec.europa.eu:taxud:tin:services:checkTin", "checkTinPort"), CheckTinPortType.class);
    }

    /**
     * 
     * @param features
     *     A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy.  Supported features not in the <code>features</code> parameter will have their default values.
     * @return
     *     returns CheckTinPortType
     */
    @WebEndpoint(name = "checkTinPort")
    public CheckTinPortType getCheckTinPort(WebServiceFeature... features) {
        return super.getPort(new QName("urn:ec.europa.eu:taxud:tin:services:checkTin", "checkTinPort"), CheckTinPortType.class, features);
    }

    private static URL __getWsdlLocation() {
        if (CHECKTINSERVICE_EXCEPTION!= null) {
            throw CHECKTINSERVICE_EXCEPTION;
        }
        return CHECKTINSERVICE_WSDL_LOCATION;
    }

}

CheckTinPortType.java

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.ws.Holder;
import javax.xml.ws.RequestWrapper;
import javax.xml.ws.ResponseWrapper;
import eu.europa.ec.taxud.tin.services.checktin.types.ObjectFactory;


/**
 * This class was generated by the JAX-WS RI.
 * JAX-WS RI 2.2.4-b01
 * Generated source version: 2.2
 * 
 */
@WebService(name = "checkTinPortType", targetNamespace = "urn:ec.europa.eu:taxud:tin:services:checkTin")
@XmlSeeAlso({
    ObjectFactory.class
})
public interface CheckTinPortType {


    /**
     * 
     * @param tinNumber
     * @param countryCode
     * @param validStructure
     * @param requestDate
     * @param validSyntax
     */
    @WebMethod
    @RequestWrapper(localName = "checkTin", targetNamespace = "urn:ec.europa.eu:taxud:tin:services:checkTin:types", className = "eu.europa.ec.taxud.tin.services.checktin.types.CheckTin")
    @ResponseWrapper(localName = "checkTinResponse", targetNamespace = "urn:ec.europa.eu:taxud:tin:services:checkTin:types", className = "eu.europa.ec.taxud.tin.services.checktin.types.CheckTinResponse")
    public void checkTin(
        @WebParam(name = "countryCode", targetNamespace = "urn:ec.europa.eu:taxud:tin:services:checkTin:types", mode = WebParam.Mode.INOUT)
        Holder<String> countryCode,
        @WebParam(name = "tinNumber", targetNamespace = "urn:ec.europa.eu:taxud:tin:services:checkTin:types", mode = WebParam.Mode.INOUT)
        Holder<String> tinNumber,
        @WebParam(name = "requestDate", targetNamespace = "urn:ec.europa.eu:taxud:tin:services:checkTin:types", mode = WebParam.Mode.OUT)
        Holder<XMLGregorianCalendar> requestDate,
        @WebParam(name = "validStructure", targetNamespace = "urn:ec.europa.eu:taxud:tin:services:checkTin:types", mode = WebParam.Mode.OUT)
        Holder<Boolean> validStructure,
        @WebParam(name = "validSyntax", targetNamespace = "urn:ec.europa.eu:taxud:tin:services:checkTin:types", mode = WebParam.Mode.OUT)
        Holder<Boolean> validSyntax);

}

ObjectFactory.java:

import com.exiqon.core.eu.europa.ec.taxud.tin.services.checktin.types.CheckTin;
import com.exiqon.core.eu.europa.ec.taxud.tin.services.checktin.types.CheckTinResponse;

import javax.xml.bind.annotation.XmlRegistry;


/**
 * This object contains factory methods for each 
 * Java content interface and Java element interface 
 * generated in the eu.europa.ec.taxud.tin.services.checktin.types package. 
 * <p>An ObjectFactory allows you to programatically 
 * construct new instances of the Java representation 
 * for XML content. The Java representation of XML 
 * content can consist of schema derived interfaces 
 * and classes representing the binding of schema 
 * type definitions, element declarations and model 
 * groups.  Factory methods for each of these are 
 * provided in this class.
 * 
 */
@XmlRegistry
public class ObjectFactory {


    /**
     * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: eu.europa.ec.taxud.tin.services.checktin.types
     * 
     */
    public ObjectFactory() {
    }

    /**
     * Create an instance of {@link eu.europa.ec.taxud.tin.services.checktin.types.CheckTin }
     * 
     */
    public CheckTin createCheckTin() {
        return new CheckTin();
    }

    /**
     * Create an instance of {@link CheckTinResponse }
     * 
     */
    public CheckTinResponse createCheckTinResponse() {
        return new CheckTinResponse();
    }

}

CheckTinResponse.java:

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSchemaType;
import javax.xml.bind.annotation.XmlType;
import javax.xml.datatype.XMLGregorianCalendar;


/**
 * <p>Java class for anonymous complex type.
 * 
 * <p>The following schema fragment specifies the expected content contained within this class.
 * 
 * <pre>
 * &lt;complexType>
 *   &lt;complexContent>
 *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       &lt;sequence>
 *         &lt;element name="countryCode" type="{http://www.w3.org/2001/XMLSchema}string"/>
 *         &lt;element name="tinNumber" type="{http://www.w3.org/2001/XMLSchema}string"/>
 *         &lt;element name="requestDate" type="{http://www.w3.org/2001/XMLSchema}date"/>
 *         &lt;element name="validStructure" type="{http://www.w3.org/2001/XMLSchema}boolean"/>
 *         &lt;element name="validSyntax" type="{http://www.w3.org/2001/XMLSchema}boolean" minOccurs="0"/>
 *       &lt;/sequence>
 *     &lt;/restriction>
 *   &lt;/complexContent>
 * &lt;/complexType>
 * </pre>
 * 
 * 
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "countryCode",
    "tinNumber",
    "requestDate",
    "validStructure",
    "validSyntax"
})
@XmlRootElement(name = "checkTinResponse")
public class CheckTinResponse {

    @XmlElement(required = true)
    protected String countryCode;
    @XmlElement(required = true)
    protected String tinNumber;
    @XmlElement(required = true)
    @XmlSchemaType(name = "date")
    protected XMLGregorianCalendar requestDate;
    protected boolean validStructure;
    protected Boolean validSyntax;

    /**
     * Gets the value of the countryCode property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getCountryCode() {
        return countryCode;
    }

    /**
     * Sets the value of the countryCode property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setCountryCode(String value) {
        this.countryCode = value;
    }

    /**
     * Gets the value of the tinNumber property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getTinNumber() {
        return tinNumber;
    }

    /**
     * Sets the value of the tinNumber property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setTinNumber(String value) {
        this.tinNumber = value;
    }

    /**
     * Gets the value of the requestDate property.
     * 
     * @return
     *     possible object is
     *     {@link XMLGregorianCalendar }
     *     
     */
    public XMLGregorianCalendar getRequestDate() {
        return requestDate;
    }

    /**
     * Sets the value of the requestDate property.
     * 
     * @param value
     *     allowed object is
     *     {@link XMLGregorianCalendar }
     *     
     */
    public void setRequestDate(XMLGregorianCalendar value) {
        this.requestDate = value;
    }

    /**
     * Gets the value of the validStructure property.
     * 
     */
    public boolean isValidStructure() {
        return validStructure;
    }

    /**
     * Sets the value of the validStructure property.
     * 
     */
    public void setValidStructure(boolean value) {
        this.validStructure = value;
    }

    /**
     * Gets the value of the validSyntax property.
     * 
     * @return
     *     possible object is
     *     {@link Boolean }
     *     
     */
    public Boolean isValidSyntax() {
        return validSyntax;
    }

    /**
     * Sets the value of the validSyntax property.
     * 
     * @param value
     *     allowed object is
     *     {@link Boolean }
     *     
     */
    public void setValidSyntax(Boolean value) {
        this.validSyntax = value;
    }

}

CheckTin.java:

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;


/**
 * <p>Java class for anonymous complex type.
 * 
 * <p>The following schema fragment specifies the expected content contained within this class.
 * 
 * <pre>
 * &lt;complexType>
 *   &lt;complexContent>
 *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       &lt;sequence>
 *         &lt;element name="countryCode" type="{http://www.w3.org/2001/XMLSchema}string"/>
 *         &lt;element name="tinNumber" type="{http://www.w3.org/2001/XMLSchema}string"/>
 *       &lt;/sequence>
 *     &lt;/restriction>
 *   &lt;/complexContent>
 * &lt;/complexType>
 * </pre>
 * 
 * 
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "countryCode",
    "tinNumber"
})
@XmlRootElement(name = "checkTin")
public class CheckTin {

    @XmlElement(required = true)
    protected String countryCode;
    @XmlElement(required = true)
    protected String tinNumber;

    /**
     * Gets the value of the countryCode property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getCountryCode() {
        return countryCode;
    }

    /**
     * Sets the value of the countryCode property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setCountryCode(String value) {
        this.countryCode = value;
    }

    /**
     * Gets the value of the tinNumber property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getTinNumber() {
        return tinNumber;
    }

    /**
     * Sets the value of the tinNumber property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setTinNumber(String value) {
        this.tinNumber = value;
    }

}

例子:
Im not sure if i got the question right, but i think i had your same problem a couple of months ago, so here is my solution:

First you need a HeaderHandler class , wich creates the soap header element, it should look like this:

import javax.xml.namespace.QName;
    import javax.xml.soap.SOAPElement;
    import javax.xml.soap.SOAPEnvelope;
    import javax.xml.soap.SOAPHeader;
    import javax.xml.ws.handler.MessageContext;
    import javax.xml.ws.handler.soap.SOAPHandler;
    import javax.xml.ws.handler.soap.SOAPMessageContext;


    public class HeaderHandler implements SOAPHandler<SOAPMessageContext> {

        public boolean handleMessage(SOAPMessageContext smc) {
            Boolean outboundProperty = (Boolean) smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
            String AUTH_TK = "http://www.myurl.com:port/subdir/etc/";
            String NOPREFIX="";//no prefix
            String PREFIX_XMLNS="xmlns";
            String value =  "123456";
            if (outboundProperty.booleanValue()) {
                try {
                    SOAPEnvelope envelope = smc.getMessage().getSOAPPart().getEnvelope();
                    SOAPHeader header = envelope.addHeader();
                    //<AuthorizationToken xmlns="http://www.myurl.com:port/subdir/etc/">
                    SOAPElement authorizationToken = header.addChildElement("AuthorizationToken", PREFIX_XMLNS, AUTH_TK);
                    //<Token>value</Token>
                    SOAPElement usernameToken =
                        authorizationToken.addChildElement("Token", NOPREFIX);
                        usernameToken.addTextNode(value);
                        //<Token>value</Token>
                    SOAPElement usernameToken =
                        authorizationToken.addChildElement("Token", PREFIX);
                        usernameToken.addTextNode(value);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return outboundProperty;
        }


        public Set<QName> getHeaders() {
            return null;
        }

        public void close(MessageContext arg0) {

        }

        public boolean handleFault(SOAPMessageContext arg0) {
            return false;
        }
    }

After that you create a HeaderHandlerResolver to handle the header creation and insert it in a handler chain:

 import java.util.ArrayList;
    import java.util.List;
    import javax.xml.ws.handler.Handler;
    import javax.xml.ws.handler.HandlerResolver;
    import javax.xml.ws.handler.PortInfo;

    public class HeaderHandlerResolver implements HandlerResolver {

    @SuppressWarnings("unchecked")
    public List<Handler> getHandlerChain(PortInfo portInfo) {
          List<Handler> handlerChain = new ArrayList<Handler>();
          HeaderHandler hh = new HeaderHandler();
          handlerChain.add(hh);
          return handlerChain;
       }
    }

After that, you add in the Client:

public class WsTest {

    public static void main(String[] args) {
        try {
            CheckTinService checkTinService = new CheckTinService();
            checkTinService.setHandlerResolver(new HeaderHandlerResolver());
            CheckTinPortType portType = checkTinService.getPort(CheckTinPortType.class);
            Holder<String> code = new Holder<String>("DE");
            Holder<String> tin = new Holder<String>("12346789");
            Holder<XMLGregorianCalendar> requestDate = new Holder<>();
            Holder<Boolean> validStructure = new Holder<>();
            Holder<Boolean> validSyntax = new Holder<>();
            portType.checkTin(code, tin, requestDate, validStructure, validSyntax);

            System.out.println("requestDate : " + requestDate.value);
            System.out.println("validStructure : " + validStructure.value);
            System.out.println("validSyntax : " + validSyntax.value);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

当然,如果只是简单的单体项目,你甚至可以直接注入Bean,那样非常方便使用。

题外话

关于WebService的超时问题

请参照这篇博客:Future 接口调用超时时间

参考链接

https://stackoverflow.com/questions/12459859/java-web-service-soap-how-do-i-add-a-soap-handler-on-the-client-side-and-e
https://stackoverflow.com/questions/29897160/how-to-use-code-generated-soap-client

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hikktn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值