feiyu02
2025-08-22 b315032d126a640758d4a6fccf297acbab057772
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package com.flightfeather.uav.common.net
 
import com.flightfeather.uav.common.exception.BizException
import com.sun.xml.internal.ws.client.BindingProviderProperties
import com.sun.xml.internal.ws.developer.JAXWSProperties
import javax.xml.soap.*
import javax.xml.ws.Dispatch
import javax.xml.ws.Service
import org.w3c.dom.Document
import org.w3c.dom.NodeList
import java.net.URL
import javax.xml.namespace.QName
import javax.xml.ws.BindingProvider
import javax.xml.ws.BindingProvider.SOAPACTION_URI_PROPERTY
import javax.xml.ws.BindingProvider.SOAPACTION_USE_PROPERTY
import javax.xml.ws.soap.SOAPBinding
 
 
/**
 * soap客户端
 * @date 2024/8/22
 * @author feiyu02
 */
class SoapClient {
    var nameSpace = "" //wsdl的命名空间
    var wsdlUrl = "" //wsdl文档地址
    var serviceName = "" //服务的名字
    var portName = ""
    var responseName = "" //@WebResult:注解上的name值
    var elementName = "" //默认是要访问的方法名 如果@WebMethod属性name有值 则是该值,实际还是以wsdl文档为主
    var timeout = 20000
 
    /**
     * @param nameSpace
     * @param wsdlUrl
     * @param serviceName
     * @param portName
     * @param element
     * @param responseName
     */
    constructor(
        nameSpace: String, wsdlUrl: String,
        serviceName: String, portName: String, element: String,
        responseName: String,
    ) {
        this.nameSpace = nameSpace
        this.wsdlUrl = wsdlUrl
        this.serviceName = serviceName
        this.portName = portName
        elementName = element
        this.responseName = responseName
    }
 
    /**
     * @param nameSpace
     * @param wsdlUrl
     * @param serviceName
     * @param portName
     * @param element
     * @param responseName
     * @param timeOut      毫秒
     */
    constructor(
        nameSpace: String, wsdlUrl: String,
        serviceName: String, portName: String, element: String,
        responseName: String, timeOut: Int,
    ) {
        this.nameSpace = nameSpace
        this.wsdlUrl = wsdlUrl
        this.serviceName = serviceName
        this.portName = portName
        elementName = element
        this.responseName = responseName
        timeout = timeOut
    }
 
    @Throws(Exception::class)
    fun sendMessage(inMsg: Map<String?, String?>): NodeList? {
        // 创建URL对象
        var url: URL? = null
        url = try {
            URL(wsdlUrl)
        } catch (e: Exception) {
            throw BizException("soap:创建URL对象异常", e)
        }
        // 创建服务(Service)
        val sname = QName(nameSpace, serviceName)
        val service: Service = Service.create(url, sname)
 
        // 创建Dispatch对象
        var dispatch: Dispatch<SOAPMessage?>? = null
        dispatch = try {
            service.createDispatch(QName(nameSpace, portName), SOAPMessage::class.java, Service.Mode.MESSAGE)
        } catch (e: Exception) {
            throw BizException("soap:创建Dispatch对象异常", e)
        }
 
        // 创建SOAPMessage
        return try {
            //这句话很重要,否则报错服务器未能识别 HTTP 头 SOAPAction 的值
            dispatch?.requestContext?.put(SOAPACTION_URI_PROPERTY, nameSpace + elementName)
            dispatch?.requestContext?.put(SOAPACTION_USE_PROPERTY, true)
            dispatch?.requestContext?.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, wsdlUrl.replace("?wsdl", ""))
            val msg: SOAPMessage = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL).createMessage()
            msg.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, "UTF-8")
            val envelope: SOAPEnvelope = msg.getSOAPPart().getEnvelope()
 
 
            // 创建SOAPHeader(不是必需)
            // SOAPHeader header = envelope.getHeader();
            // if (header == null)
            // header = envelope.addHeader();
            // QName hname = new QName(nameSpace, "username", "nn");
            // header.addHeaderElement(hname).setValue("huoyangege");
 
 
            // 创建SOAPBody
            val body: SOAPBody = envelope.getBody()
            val ename = QName(nameSpace, elementName, "")
            val ele: SOAPBodyElement = body.addBodyElement(ename)
            // 增加Body元素和值
            inMsg.forEach { (key, value) ->
                ele.addChildElement(QName(nameSpace, key)).value = value
            }
 
            // 超时设置
            dispatch?.requestContext?.put(BindingProviderProperties.CONNECT_TIMEOUT, timeout)
            dispatch?.requestContext?.put(JAXWSProperties.REQUEST_TIMEOUT, timeout)
            // 通过Dispatch传递消息,会返回响应消息
            val response = dispatch?.invoke(msg)
 
            // 响应消息处理,将响应的消息转换为doc对象
            val doc = response?.soapPart?.envelope?.body?.extractContentAsDocument()
//            doc?.getElementsByTagName(responseName)?.item(0)?.textContent ?: ""
            doc?.getElementsByTagName(responseName)
        } catch (e: Exception) {
            throw BizException("soap:接口访问异常", e)
        }
    }
}