Java调用WebService接口----使用JAXBContent转化Bean与Xml

上一节使用SOAPMessage调用WebService接口,但是比较麻烦的是参数的拼装需要一个一个add,比较麻烦。此次介绍使用JAXBContent转化Bean与Xml,然后利用http请求(如Okhttp)发送Xml组装的报文。
本文demo代码:JAXBContent转换Bean与Xml

目标

先看一下请求与结果:
WebService请求

再看一下本demo最终的类结构
demo类结构

  • bean目录分为request和response,代表的分别是请求和相应。
  • 由于Xml有多层结点,造成Bean也会有多层嵌套。
  • NameSpace和package-info.java定义了命名空间,用于生成Xml和解析Xml。
  • HttpRequest使用Okhttp发送请求。
  • XmlUtil则封装了Bean转化为Xml、Xml转化为Bean两个方法。
  • Test类进行测试。

1.Bean To Xml

1.1 转化方法

Bean To Xml转化方法是XmlUtil中的一个方法。具体方法如下:

	/**
     * transfer bean to xml
     *
     * @param obj   待转化类对象
     * @param clazz 待转化类
     * @return 转化后的xml字符串
     * @throws JAXBException
     */
    public static String beanToXml(Object obj, java.lang.Class<?> clazz) throws JAXBException {
        String result = null;
        try {
            JAXBContext context = JAXBContext.newInstance(clazz);
            Marshaller marshaller = context.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            marshaller.setProperty(Marshaller.JAXB_ENCODING, "utf-8");
            StringWriter writer = new StringWriter();
            marshaller.marshal(obj, writer);
            result = writer.toString();
        } catch (JAXBException e) {
            e.printStackTrace();
            System.out.println("JAXBException happened.");
        }
        return result;
    }

有了转化方法,不代表转化就可以成功了。因为Xml是有一定格式的,转化的格式如何规定呢?这里可以使用@Xml类注解进行规定。

1.2 @XML类注解

@XmlRootElement 代表xml根节点
@XmlType 可以定义xml节点中元素的顺序
@XmlElement 表名是当前节点下的一个子节点
@XmlAttribute 表名是当前节点的属性
有的注解中可以定义name属性,指定其在Xml中的名称;namespace属性,指定其属于某一个命名空间。

1.3 定义命名空间

NameSpace中的内容如下

package cn.hewie.webService.bean.request;

public class NameSpace {
    public static final String BASIC_PREFIX = "soap";
    public static final String BASIC_URI = "http://www.w3.org/2003/05/soap-envelope";
    public static final String TEMP_URI = "http://tempuri.org/";
    public static final String TEMP_PREFIX = "tem";
}

package-info.java中的内容如下

@XmlSchema(
        xmlns = {
                @XmlNs(prefix = NameSpace.BASIC_PREFIX, namespaceURI = NameSpace.BASIC_URI),
                @XmlNs(prefix = NameSpace.TEMP_PREFIX, namespaceURI = NameSpace.TEMP_URI)
        })
package cn.hewie.webService.bean.request;

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

1.4 使用注解标识Bean

有了上述注解和命名空间基础后,就可以使用注解标识Bean了。例如上述请求中,最外层结点定位为RequestEntity对象,可以定义如下:

import cn.hewie.webService.bean.response.NameSpace;

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

@XmlRootElement(name = "Envelope", namespace = NameSpace.BASIC_URI)
@XmlType(propOrder = {"header", "body"})
public class RequestEntity {

    protected RequestHeader header;

    protected RequestBody body;

    @XmlElement(name = "Header", namespace = NameSpace.BASIC_URI)
    public RequestHeader getHeader() {
        return header;
    }

    public void setHeader(RequestHeader header) {
        this.header = header;
    }

    @XmlElement(name = "Body", namespace = NameSpace.BASIC_URI)
    public RequestBody getBody() {
        return body;
    }

    public void setBody(RequestBody body) {
        this.body = body;
    }
}

这样就标识了最外层的Envelope,还指定了其含有子节点header和body,并分别指定了命名空间。
由于header结点为空,我们可以直接创建一个对象即可。

package cn.hewie.webService.bean.request;

public class RequestHeader {
}

主要还是body节点,其中又包含了一个对象。

package cn.hewie.webService.bean.request;


import javax.xml.bind.annotation.XmlElement;

public class RequestBody {

    private IsWaybillExistsRequest isWaybillExistsRequest;

    @XmlElement(name = "IsWaybillExists", namespace = NameSpace.TEMP_URI)
    public IsWaybillExistsRequest getIsWaybillExistsRequest() {
        return isWaybillExistsRequest;
    }

    public void setIsWaybillExistsRequest(IsWaybillExistsRequest isWaybillExistsRequest) {
        this.isWaybillExistsRequest = isWaybillExistsRequest;
    }
}

依次类推
IsWaybillExistsRequest类如下

package cn.hewie.webService.bean.request;

import javax.xml.bind.annotation.*;

@XmlType(propOrder = {"clientInfo", "waybillNo"})
public class IsWaybillExistsRequest {

    private String waybillNo;
    private ClientInfo clientInfo;

    @XmlElement(name = "WaybillNo", namespace = NameSpace.TEMP_URI)
    public String getWaybillNo() {
        return waybillNo;
    }

    public void setWaybillNo(String waybillNo) {
        this.waybillNo = waybillNo;
    }

    @XmlElement(name = "ClientInfo", namespace = NameSpace.TEMP_URI)
    public ClientInfo getClientInfo() {
        return clientInfo;
    }

    public void setClientInfo(ClientInfo clientInfo) {
        this.clientInfo = clientInfo;
    }
}

ClientInfo.java如下

package cn.hewie.webService.bean.request;

import javax.xml.bind.annotation.XmlElement;

public class ClientInfo {

    private ClientAddress clientAddress;
    private String clientID;
    private String password;
    private String version;

    @XmlElement(name = "ClientAddress", namespace = NameSpace.TEMP_URI)
    public ClientAddress getClientAddress() {
        return clientAddress;
    }

    public void setClientAddress(ClientAddress clientAddress) {
        this.clientAddress = clientAddress;
    }

    @XmlElement(name = "ClientID", namespace = NameSpace.TEMP_URI)
    public String getClientID() {
        return clientID;
    }

    public void setClientID(String clientID) {
        this.clientID = clientID;
    }

    @XmlElement(name = "Password", namespace = NameSpace.TEMP_URI)
    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @XmlElement(name = "Version", namespace = NameSpace.TEMP_URI)
    public String getVersion() {
        return version;
    }

    public void setVersion(String version) {
        this.version = version;
    }
}

经过测试,该接口只需要节点IsWaybillExists下存在

<tem:ClientID></tem:ClientID>

就可以正确返回了(其他节点都有optional标示),为了简单起见,更下层的其他类我们就不列举出实现了(事实上demo中没有实现ClientContact类)。

2. Xml To Bean

将Xml转化为Bean与上述过程类似。

2.1 转化方法

XmlUtil中转化方法如下:

/**
     * transfer xml to bean
     *
     * @param xml 待转化的xml字符串
     * @param c 转化后的类
     * @param <T> 转化后类类型
     * @return 转化后的类对象
     */
    @SuppressWarnings("unchecked")
    public static <T> T xmlToBean(String xml, Class<T> c) {
        T t = null;
        try {
            JAXBContext context = JAXBContext.newInstance(c);
            Unmarshaller unmarshaller = context.createUnmarshaller();
            t = (T) unmarshaller.unmarshal(new StringReader(xml));
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return t;
    }

2.2 命名空间

与上述类似,但注意不要把命名空间与属性弄错。
NameSpace.java

package cn.hewie.webService.bean.response;

public class NameSpace {
    public static final String BASIC_PREFIX = "soap";
    public static final String BASIC_URI = "http://www.w3.org/2003/05/soap-envelope";

    public static final String TEMP_PREFIX = "";
    public static final String TEMP_URI = "http://tempuri.org/";

    public static final String XSI_PREFIX = "xsi";
    public static final String XSI_URI = "http://www.w3.org/2001/XMLSchema-instance";

    public static final String XSD_PREFIX = "xsd";
    public static final String XSD_URI = "http://www.w3.org/2001/XMLSchema";
}

package-info.java

@XmlSchema(
        xmlns = {
                @XmlNs(prefix = NameSpace.BASIC_PREFIX, namespaceURI = NameSpace.BASIC_URI),
                @XmlNs(prefix = NameSpace.XSI_PREFIX, namespaceURI = NameSpace.XSI_URI),
                @XmlNs(prefix = NameSpace.XSD_PREFIX, namespaceURI = NameSpace.XSD_URI)
        })
package cn.hewie.webService.bean.response;

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

2.3 使用注解标识Bean

与上述类似,这里不再赘述。

3. 发送请求

利用Okhttp发送请求类HttpRequest如下:

package cn.hewie.webService.client;

import okhttp3.*;

import java.io.IOException;

public class HttpRequest {
    public static String execute(String postBody) throws IOException {
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .post(RequestBody.create(MediaType.parse("application/soap+xml; charset=utf-8"), postBody))
                .url("https://infotrack.naqelexpress.com/NaqelAPIServices/NaqelAPIDemo/5.0/XMLShippingService.asmx")
                .build();
        Response response = client.newCall(request).execute();
        if (!response.isSuccessful()) {
            System.out.println("服务器错误:" + response);
        }

//        Headers responseHeaders = response.headers();
//        for (int i = 0; i < responseHeaders.size(); i++) {
//            System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
//        }

        String result = response.body().string();

        return result;
    }
}

1.6 测试

测试的时候只需要正确组装类的层级结构,然后调用相应接口,就可以正确处理了。
获得的结果进行转化后,即可获得正确的类结构。

public static void testHttpRequest() {
        ClientAddress clientAddress = new ClientAddress();
        clientAddress.setPhoneNumber("11111111111");
        clientAddress.setPOBox("aaa");
        clientAddress.setZipCode("111111");
        clientAddress.setFax("aaa");
        clientAddress.setFirstAddress("111");
        clientAddress.setLocation("111");
        clientAddress.setCountryCode("10200");
        clientAddress.setCityCode("22");

        ClientInfo clientInfo = new ClientInfo();
        clientInfo.setClientAddress(clientAddress);
        clientInfo.setClientID("1");
        clientInfo.setPassword("111");
        clientInfo.setVersion("1.0");

        IsWaybillExistsRequest isWaybillExistsRequest = new IsWaybillExistsRequest();
        isWaybillExistsRequest.setClientInfo(clientInfo);
        isWaybillExistsRequest.setWaybillNo("111");

        RequestBody requestBody = new RequestBody();
        requestBody.setIsWaybillExistsRequest(isWaybillExistsRequest);

        RequestHeader requestHeader = new RequestHeader();
        RequestEntity requestEntity = new RequestEntity();
        requestEntity.setHeader(requestHeader);
        requestEntity.setBody(requestBody);

        try {
            String body = XmlUtil.beanToXml(requestEntity, RequestEntity.class);
            System.out.println("==============Bean to Xml==============");
            System.out.println(body);

            String response = HttpRequest.execute(body);
            System.out.println("=============response body==============");
            System.out.println(response);

            ResponseEntity responseEntity = XmlUtil.xmlToBean(response, ResponseEntity.class);
            System.out.println("=============Xml to Bean================");
            System.out.println(responseEntity.getResponseBody().getIsWaybillExistsResponse().getWaybillExistsResult());
        } catch (JAXBException e) {
            e.printStackTrace();
            System.out.println("JAXBException happened.");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("unexpected error happened.");
        }
    }

运行后,测试结果如下:

==============Bean to Xml==============
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<soap:Envelope xmlns:tem="http://tempuri.org/" xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
    <soap:Header/>
    <soap:Body>
        <tem:IsWaybillExists>
            <tem:ClientInfo>
                <tem:ClientAddress>
                    <tem:PhoneNumber>11111111111</tem:PhoneNumber>
                    <tem:POBox>aaa</tem:POBox>
                    <tem:ZipCode>111111</tem:ZipCode>
                    <tem:Fax>aaa</tem:Fax>
                    <tem:FirstAddress>111</tem:FirstAddress>
                    <tem:Location>111</tem:Location>
                    <tem:CountryCode>10200</tem:CountryCode>
                    <tem:CityCode>22</tem:CityCode>
                </tem:ClientAddress>
                <tem:ClientID>1</tem:ClientID>
                <tem:Password>111</tem:Password>
                <tem:Version>1.0</tem:Version>
            </tem:ClientInfo>
            <tem:WaybillNo>111</tem:WaybillNo>
        </tem:IsWaybillExists>
    </soap:Body>
</soap:Envelope>

=============response body==============
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><IsWaybillExistsResponse xmlns="http://tempuri.org/"><IsWaybillExistsResult>true</IsWaybillExistsResult></IsWaybillExistsResponse></soap:Body></soap:Envelope>
=============Xml to Bean================
true
发布了136 篇原创文章 · 获赞 94 · 访问量 22万+

猜你喜欢

转载自blog.csdn.net/somehow1002/article/details/82988663
今日推荐