mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-12-08 01:59:14 +08:00
增加JakartaSoapClient(issue#4103@Github)
This commit is contained in:
parent
47c48b23b3
commit
5a3ad06601
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
### 🐣新特性
|
### 🐣新特性
|
||||||
* 【core 】 `ListUtil`增加`zip`方法(pr#4052@Github)
|
* 【core 】 `ListUtil`增加`zip`方法(pr#4052@Github)
|
||||||
|
* 【http 】 增加`JakartaSoapClient`(issue#4103@Github)
|
||||||
|
|
||||||
### 🐞Bug修复
|
### 🐞Bug修复
|
||||||
* 【jwt 】 修复verify方法在定义alg为`none`时验证失效问题(issue#4105@Github)
|
* 【jwt 】 修复verify方法在定义alg为`none`时验证失效问题(issue#4105@Github)
|
||||||
|
|||||||
@ -38,5 +38,11 @@
|
|||||||
<version>1.4.0</version>
|
<version>1.4.0</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>jakarta.xml.soap</groupId>
|
||||||
|
<artifactId>jakarta.xml.soap-api</artifactId>
|
||||||
|
<version>2.0.1</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@ -0,0 +1,654 @@
|
|||||||
|
package cn.hutool.http.webservice;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.io.IoUtil;
|
||||||
|
import cn.hutool.core.map.MapUtil;
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.core.util.XmlUtil;
|
||||||
|
import cn.hutool.http.HttpBase;
|
||||||
|
import cn.hutool.http.HttpGlobalConfig;
|
||||||
|
import cn.hutool.http.HttpRequest;
|
||||||
|
import cn.hutool.http.HttpResponse;
|
||||||
|
import jakarta.xml.soap.*;
|
||||||
|
|
||||||
|
import javax.xml.XMLConstants;
|
||||||
|
import javax.xml.namespace.QName;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SOAP客户端
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 此对象用于构建一个SOAP消息,并通过HTTP接口发出消息内容。
|
||||||
|
* SOAP消息本质上是一个XML文本,可以通过调用{@link #getMsgStr(boolean)} 方法获取消息体
|
||||||
|
* <p>
|
||||||
|
* 使用方法:
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* SoapClient client = SoapClient.create(url)
|
||||||
|
* .setMethod(methodName, namespaceURI)
|
||||||
|
* .setCharset(CharsetUtil.CHARSET_GBK)
|
||||||
|
* .setParam(param1, "XXX");
|
||||||
|
*
|
||||||
|
* String response = client.send(true);
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @author looly
|
||||||
|
* @since 5.8.42
|
||||||
|
*/
|
||||||
|
public class JakartaSoapClient extends HttpBase<JakartaSoapClient> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XML消息体的Content-Type
|
||||||
|
* soap1.1 : text/xml
|
||||||
|
* soap1.2 : application/soap+xml
|
||||||
|
* soap1.1与soap1.2区别: https://www.cnblogs.com/qlqwjy/p/7577147.html
|
||||||
|
*/
|
||||||
|
private static final String CONTENT_TYPE_SOAP11_TEXT_XML = "text/xml;charset=";
|
||||||
|
private static final String CONTENT_TYPE_SOAP12_SOAP_XML = "application/soap+xml;charset=";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求的URL地址
|
||||||
|
*/
|
||||||
|
private String url;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认连接超时
|
||||||
|
*/
|
||||||
|
private int connectionTimeout = HttpGlobalConfig.getTimeout();
|
||||||
|
/**
|
||||||
|
* 默认读取超时
|
||||||
|
*/
|
||||||
|
private int readTimeout = HttpGlobalConfig.getTimeout();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息工厂,用于创建消息
|
||||||
|
*/
|
||||||
|
private MessageFactory factory;
|
||||||
|
/**
|
||||||
|
* SOAP消息
|
||||||
|
*/
|
||||||
|
private SOAPMessage message;
|
||||||
|
/**
|
||||||
|
* 消息方法节点
|
||||||
|
*/
|
||||||
|
private SOAPBodyElement methodEle;
|
||||||
|
/**
|
||||||
|
* 应用于方法上的命名空间URI
|
||||||
|
*/
|
||||||
|
private final String namespaceURI;
|
||||||
|
/**
|
||||||
|
* Soap协议
|
||||||
|
* soap1.1 : text/xml
|
||||||
|
* soap1.2 : application/soap+xml
|
||||||
|
*/
|
||||||
|
private final SoapProtocol protocol;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建SOAP客户端,默认使用soap1.1版本协议
|
||||||
|
*
|
||||||
|
* @param url WS的URL地址
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public static JakartaSoapClient create(String url) {
|
||||||
|
return new JakartaSoapClient(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建SOAP客户端
|
||||||
|
*
|
||||||
|
* @param url WS的URL地址
|
||||||
|
* @param protocol 协议,见{@link SoapProtocol}
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public static JakartaSoapClient create(String url, SoapProtocol protocol) {
|
||||||
|
return new JakartaSoapClient(url, protocol);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建SOAP客户端
|
||||||
|
*
|
||||||
|
* @param url WS的URL地址
|
||||||
|
* @param protocol 协议,见{@link SoapProtocol}
|
||||||
|
* @param namespaceURI 方法上的命名空间URI
|
||||||
|
* @return this
|
||||||
|
* @since 4.5.6
|
||||||
|
*/
|
||||||
|
public static JakartaSoapClient create(String url, SoapProtocol protocol, String namespaceURI) {
|
||||||
|
return new JakartaSoapClient(url, protocol, namespaceURI);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造,默认使用soap1.1版本协议
|
||||||
|
*
|
||||||
|
* @param url WS的URL地址
|
||||||
|
*/
|
||||||
|
public JakartaSoapClient(String url) {
|
||||||
|
this(url, SoapProtocol.SOAP_1_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
*
|
||||||
|
* @param url WS的URL地址
|
||||||
|
* @param protocol 协议版本,见{@link SoapProtocol}
|
||||||
|
*/
|
||||||
|
public JakartaSoapClient(String url, SoapProtocol protocol) {
|
||||||
|
this(url, protocol, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
*
|
||||||
|
* @param url WS的URL地址
|
||||||
|
* @param protocol 协议版本,见{@link SoapProtocol}
|
||||||
|
* @param namespaceURI 方法上的命名空间URI
|
||||||
|
* @since 4.5.6
|
||||||
|
*/
|
||||||
|
public JakartaSoapClient(String url, SoapProtocol protocol, String namespaceURI) {
|
||||||
|
this.url = url;
|
||||||
|
this.namespaceURI = namespaceURI;
|
||||||
|
this.protocol = protocol;
|
||||||
|
init(protocol);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化
|
||||||
|
*
|
||||||
|
* @param protocol 协议版本枚举,见{@link SoapProtocol}
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public JakartaSoapClient init(SoapProtocol protocol) {
|
||||||
|
// 创建消息工厂
|
||||||
|
try {
|
||||||
|
this.factory = MessageFactory.newInstance(protocol.getValue());
|
||||||
|
// 根据消息工厂创建SoapMessage
|
||||||
|
this.message = factory.createMessage();
|
||||||
|
} catch (SOAPException e) {
|
||||||
|
throw new SoapRuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置SOAP客户端,用于客户端复用
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 重置后需调用serMethod方法重新指定请求方法,并调用setParam方法重新定义参数
|
||||||
|
*
|
||||||
|
* @return this
|
||||||
|
* @since 4.6.7
|
||||||
|
*/
|
||||||
|
public JakartaSoapClient reset() {
|
||||||
|
try {
|
||||||
|
this.message = factory.createMessage();
|
||||||
|
} catch (SOAPException e) {
|
||||||
|
throw new SoapRuntimeException(e);
|
||||||
|
}
|
||||||
|
this.methodEle = null;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置编码
|
||||||
|
*
|
||||||
|
* @param charset 编码
|
||||||
|
* @return this
|
||||||
|
* @see #charset(Charset)
|
||||||
|
*/
|
||||||
|
public JakartaSoapClient setCharset(Charset charset) {
|
||||||
|
return this.charset(charset);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JakartaSoapClient charset(Charset charset) {
|
||||||
|
super.charset(charset);
|
||||||
|
try {
|
||||||
|
this.message.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, this.charset());
|
||||||
|
this.message.setProperty(SOAPMessage.WRITE_XML_DECLARATION, "true");
|
||||||
|
} catch (SOAPException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置Webservice请求地址
|
||||||
|
*
|
||||||
|
* @param url Webservice请求地址
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public JakartaSoapClient setUrl(String url) {
|
||||||
|
this.url = url;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 增加SOAP头信息,方法返回{@link SOAPHeaderElement}可以设置具体属性和子节点
|
||||||
|
*
|
||||||
|
* @param name 头信息标签名
|
||||||
|
* @param actorURI 中间的消息接收者
|
||||||
|
* @param roleUri Role的URI
|
||||||
|
* @param mustUnderstand 标题项对于要对其进行处理的接收者来说是强制的还是可选的
|
||||||
|
* @param relay relay属性
|
||||||
|
* @return {@link SOAPHeaderElement}
|
||||||
|
* @since 5.4.4
|
||||||
|
*/
|
||||||
|
public SOAPHeaderElement addSOAPHeader(QName name, String actorURI, String roleUri, Boolean mustUnderstand, Boolean relay) {
|
||||||
|
final SOAPHeaderElement ele = addSOAPHeader(name);
|
||||||
|
try {
|
||||||
|
if (StrUtil.isNotBlank(roleUri)) {
|
||||||
|
ele.setRole(roleUri);
|
||||||
|
}
|
||||||
|
if (null != relay) {
|
||||||
|
ele.setRelay(relay);
|
||||||
|
}
|
||||||
|
} catch (SOAPException e) {
|
||||||
|
throw new SoapRuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StrUtil.isNotBlank(actorURI)) {
|
||||||
|
ele.setActor(actorURI);
|
||||||
|
}
|
||||||
|
if (null != mustUnderstand) {
|
||||||
|
ele.setMustUnderstand(mustUnderstand);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ele;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 增加SOAP头信息,方法返回{@link SOAPHeaderElement}可以设置具体属性和子节点
|
||||||
|
*
|
||||||
|
* @param localName 头节点名称
|
||||||
|
* @return {@link SOAPHeaderElement}
|
||||||
|
* @since 5.4.7
|
||||||
|
*/
|
||||||
|
public SOAPHeaderElement addSOAPHeader(String localName) {
|
||||||
|
return addSOAPHeader(new QName(localName));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 增加SOAP头信息,方法返回{@link SOAPHeaderElement}可以设置具体属性和子节点
|
||||||
|
*
|
||||||
|
* @param localName 头节点名称
|
||||||
|
* @param value 头节点的值
|
||||||
|
* @return {@link SOAPHeaderElement}
|
||||||
|
* @since 5.4.7
|
||||||
|
*/
|
||||||
|
public SOAPHeaderElement addSOAPHeader(String localName, String value) {
|
||||||
|
final SOAPHeaderElement soapHeaderElement = addSOAPHeader(localName);
|
||||||
|
soapHeaderElement.setTextContent(value);
|
||||||
|
return soapHeaderElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 增加SOAP头信息,方法返回{@link SOAPHeaderElement}可以设置具体属性和子节点
|
||||||
|
*
|
||||||
|
* @param name 头节点名称
|
||||||
|
* @return {@link SOAPHeaderElement}
|
||||||
|
* @since 5.4.4
|
||||||
|
*/
|
||||||
|
public SOAPHeaderElement addSOAPHeader(QName name) {
|
||||||
|
SOAPHeaderElement ele;
|
||||||
|
try {
|
||||||
|
ele = this.message.getSOAPHeader().addHeaderElement(name);
|
||||||
|
} catch (SOAPException e) {
|
||||||
|
throw new SoapRuntimeException(e);
|
||||||
|
}
|
||||||
|
return ele;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置请求方法
|
||||||
|
*
|
||||||
|
* @param name 方法名及其命名空间
|
||||||
|
* @param params 参数
|
||||||
|
* @param useMethodPrefix 是否使用方法的命名空间前缀
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public JakartaSoapClient setMethod(Name name, Map<String, Object> params, boolean useMethodPrefix) {
|
||||||
|
return setMethod(new QName(name.getURI(), name.getLocalName(), name.getPrefix()), params, useMethodPrefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置请求方法
|
||||||
|
*
|
||||||
|
* @param name 方法名及其命名空间
|
||||||
|
* @param params 参数
|
||||||
|
* @param useMethodPrefix 是否使用方法的命名空间前缀
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public JakartaSoapClient setMethod(QName name, Map<String, Object> params, boolean useMethodPrefix) {
|
||||||
|
setMethod(name);
|
||||||
|
final String prefix = useMethodPrefix ? name.getPrefix() : null;
|
||||||
|
final SOAPBodyElement methodEle = this.methodEle;
|
||||||
|
for (Entry<String, Object> entry : MapUtil.wrap(params)) {
|
||||||
|
setParam(methodEle, entry.getKey(), entry.getValue(), prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置请求方法<br>
|
||||||
|
* 方法名自动识别前缀,前缀和方法名使用“:”分隔<br>
|
||||||
|
* 当识别到前缀后,自动添加xmlns属性,关联到默认的namespaceURI
|
||||||
|
*
|
||||||
|
* @param methodName 方法名
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public JakartaSoapClient setMethod(String methodName) {
|
||||||
|
return setMethod(methodName, ObjectUtil.defaultIfNull(this.namespaceURI, XMLConstants.NULL_NS_URI));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置请求方法<br>
|
||||||
|
* 方法名自动识别前缀,前缀和方法名使用“:”分隔<br>
|
||||||
|
* 当识别到前缀后,自动添加xmlns属性,关联到传入的namespaceURI
|
||||||
|
*
|
||||||
|
* @param methodName 方法名(可有前缀也可无)
|
||||||
|
* @param namespaceURI 命名空间URI
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public JakartaSoapClient setMethod(String methodName, String namespaceURI) {
|
||||||
|
final List<String> methodNameList = StrUtil.split(methodName, ':');
|
||||||
|
final QName qName;
|
||||||
|
if (2 == methodNameList.size()) {
|
||||||
|
qName = new QName(namespaceURI, methodNameList.get(1), methodNameList.get(0));
|
||||||
|
} else {
|
||||||
|
qName = new QName(namespaceURI, methodName);
|
||||||
|
}
|
||||||
|
return setMethod(qName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置请求方法
|
||||||
|
*
|
||||||
|
* @param name 方法名及其命名空间
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public JakartaSoapClient setMethod(QName name) {
|
||||||
|
try {
|
||||||
|
this.methodEle = this.message.getSOAPBody().addBodyElement(name);
|
||||||
|
} catch (SOAPException e) {
|
||||||
|
throw new SoapRuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置方法参数,使用方法的前缀
|
||||||
|
*
|
||||||
|
* @param name 参数名
|
||||||
|
* @param value 参数值,可以是字符串或Map或{@link SOAPElement}
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public JakartaSoapClient setParam(String name, Object value) {
|
||||||
|
return setParam(name, value, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置方法参数
|
||||||
|
*
|
||||||
|
* @param name 参数名
|
||||||
|
* @param value 参数值,可以是字符串或Map或{@link SOAPElement}
|
||||||
|
* @param useMethodPrefix 是否使用方法的命名空间前缀
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public JakartaSoapClient setParam(String name, Object value, boolean useMethodPrefix) {
|
||||||
|
setParam(this.methodEle, name, value, useMethodPrefix ? this.methodEle.getPrefix() : null);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量设置参数,使用方法的前缀
|
||||||
|
*
|
||||||
|
* @param params 参数列表
|
||||||
|
* @return this
|
||||||
|
* @since 4.5.6
|
||||||
|
*/
|
||||||
|
public JakartaSoapClient setParams(Map<String, Object> params) {
|
||||||
|
return setParams(params, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量设置参数
|
||||||
|
*
|
||||||
|
* @param params 参数列表
|
||||||
|
* @param useMethodPrefix 是否使用方法的命名空间前缀
|
||||||
|
* @return this
|
||||||
|
* @since 4.5.6
|
||||||
|
*/
|
||||||
|
public JakartaSoapClient setParams(Map<String, Object> params, boolean useMethodPrefix) {
|
||||||
|
for (Entry<String, Object> entry : MapUtil.wrap(params)) {
|
||||||
|
setParam(entry.getKey(), entry.getValue(), useMethodPrefix);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取方法节点<br>
|
||||||
|
* 用于创建子节点等操作
|
||||||
|
*
|
||||||
|
* @return {@link SOAPBodyElement}
|
||||||
|
* @since 4.5.6
|
||||||
|
*/
|
||||||
|
public SOAPBodyElement getMethodEle() {
|
||||||
|
return this.methodEle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取SOAP消息对象 {@link SOAPMessage}
|
||||||
|
*
|
||||||
|
* @return {@link SOAPMessage}
|
||||||
|
* @since 4.5.6
|
||||||
|
*/
|
||||||
|
public SOAPMessage getMessage() {
|
||||||
|
return this.message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取SOAP请求消息
|
||||||
|
*
|
||||||
|
* @param pretty 是否格式化
|
||||||
|
* @return 消息字符串
|
||||||
|
*/
|
||||||
|
public String getMsgStr(boolean pretty) {
|
||||||
|
return JakartaSoapUtil.toString(this.message, pretty, this.charset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将SOAP消息的XML内容输出到流
|
||||||
|
*
|
||||||
|
* @param out 输出流
|
||||||
|
* @return this
|
||||||
|
* @since 4.5.6
|
||||||
|
*/
|
||||||
|
public JakartaSoapClient write(OutputStream out) {
|
||||||
|
try {
|
||||||
|
this.message.writeTo(out);
|
||||||
|
} catch (SOAPException | IOException e) {
|
||||||
|
throw new SoapRuntimeException(e);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置超时,单位:毫秒<br>
|
||||||
|
* 超时包括:
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* 1. 连接超时
|
||||||
|
* 2. 读取响应超时
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param milliseconds 超时毫秒数
|
||||||
|
* @return this
|
||||||
|
* @see #setConnectionTimeout(int)
|
||||||
|
* @see #setReadTimeout(int)
|
||||||
|
*/
|
||||||
|
public JakartaSoapClient timeout(int milliseconds) {
|
||||||
|
setConnectionTimeout(milliseconds);
|
||||||
|
setReadTimeout(milliseconds);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置连接超时,单位:毫秒
|
||||||
|
*
|
||||||
|
* @param milliseconds 超时毫秒数
|
||||||
|
* @return this
|
||||||
|
* @since 4.5.6
|
||||||
|
*/
|
||||||
|
public JakartaSoapClient setConnectionTimeout(int milliseconds) {
|
||||||
|
this.connectionTimeout = milliseconds;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置连接超时,单位:毫秒
|
||||||
|
*
|
||||||
|
* @param milliseconds 超时毫秒数
|
||||||
|
* @return this
|
||||||
|
* @since 4.5.6
|
||||||
|
*/
|
||||||
|
public JakartaSoapClient setReadTimeout(int milliseconds) {
|
||||||
|
this.readTimeout = milliseconds;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行Webservice请求,即发送SOAP内容
|
||||||
|
*
|
||||||
|
* @return 返回结果
|
||||||
|
*/
|
||||||
|
public SOAPMessage sendForMessage() {
|
||||||
|
final HttpResponse res = sendForResponse();
|
||||||
|
final MimeHeaders headers = new MimeHeaders();
|
||||||
|
for (Entry<String, List<String>> entry : res.headers().entrySet()) {
|
||||||
|
if (StrUtil.isNotEmpty(entry.getKey())) {
|
||||||
|
headers.setHeader(entry.getKey(), CollUtil.get(entry.getValue(), 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return this.factory.createMessage(headers, res.bodyStream());
|
||||||
|
} catch (IOException | SOAPException e) {
|
||||||
|
throw new SoapRuntimeException(e);
|
||||||
|
} finally {
|
||||||
|
IoUtil.close(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行Webservice请求,即发送SOAP内容
|
||||||
|
*
|
||||||
|
* @return 返回结果
|
||||||
|
*/
|
||||||
|
public String send() {
|
||||||
|
return send(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行Webservice请求,即发送SOAP内容
|
||||||
|
*
|
||||||
|
* @param pretty 是否格式化
|
||||||
|
* @return 返回结果
|
||||||
|
*/
|
||||||
|
public String send(boolean pretty) {
|
||||||
|
final String body = sendForResponse().body();
|
||||||
|
return pretty ? XmlUtil.format(body) : body;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------- Private method start
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送请求,获取异步响应
|
||||||
|
*
|
||||||
|
* @return 响应对象
|
||||||
|
*/
|
||||||
|
public HttpResponse sendForResponse() {
|
||||||
|
return HttpRequest.post(this.url)//
|
||||||
|
.setFollowRedirects(true)//
|
||||||
|
.setConnectionTimeout(this.connectionTimeout)
|
||||||
|
.setReadTimeout(this.readTimeout)
|
||||||
|
.contentType(getXmlContentType())//
|
||||||
|
.header(this.headers())
|
||||||
|
.body(getMsgStr(false))//
|
||||||
|
.executeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取请求的Content-Type,附加编码信息
|
||||||
|
*
|
||||||
|
* @return 请求的Content-Type
|
||||||
|
*/
|
||||||
|
private String getXmlContentType() {
|
||||||
|
switch (this.protocol){
|
||||||
|
case SOAP_1_1:
|
||||||
|
return CONTENT_TYPE_SOAP11_TEXT_XML.concat(this.charset.toString());
|
||||||
|
case SOAP_1_2:
|
||||||
|
return CONTENT_TYPE_SOAP12_SOAP_XML.concat(this.charset.toString());
|
||||||
|
default:
|
||||||
|
throw new SoapRuntimeException("Unsupported protocol: {}", this.protocol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置方法参数
|
||||||
|
*
|
||||||
|
* @param ele 方法节点
|
||||||
|
* @param name 参数名
|
||||||
|
* @param value 参数值
|
||||||
|
* @param prefix 命名空间前缀, {@code null}表示不使用前缀
|
||||||
|
* @return {@link SOAPElement}子节点
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
private static SOAPElement setParam(SOAPElement ele, String name, Object value, String prefix) {
|
||||||
|
final SOAPElement childEle;
|
||||||
|
try {
|
||||||
|
if (StrUtil.isNotBlank(prefix)) {
|
||||||
|
childEle = ele.addChildElement(name, prefix);
|
||||||
|
} else {
|
||||||
|
childEle = ele.addChildElement(name);
|
||||||
|
}
|
||||||
|
} catch (SOAPException e) {
|
||||||
|
throw new SoapRuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null != value) {
|
||||||
|
if (value instanceof SOAPElement) {
|
||||||
|
// 单个子节点
|
||||||
|
try {
|
||||||
|
ele.addChildElement((SOAPElement) value);
|
||||||
|
} catch (SOAPException e) {
|
||||||
|
throw new SoapRuntimeException(e);
|
||||||
|
}
|
||||||
|
} else if (value instanceof Map) {
|
||||||
|
// 多个字节点
|
||||||
|
Entry entry;
|
||||||
|
for (Object obj : ((Map) value).entrySet()) {
|
||||||
|
entry = (Entry) obj;
|
||||||
|
setParam(childEle, entry.getKey().toString(), entry.getValue(), prefix);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 单个值
|
||||||
|
childEle.setValue(value.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return childEle;
|
||||||
|
}
|
||||||
|
// -------------------------------------------------------------------------------------------------------- Private method end
|
||||||
|
}
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
package cn.hutool.http.webservice;
|
||||||
|
|
||||||
|
import jakarta.xml.soap.SOAPConstants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SOAP协议版本枚举
|
||||||
|
*
|
||||||
|
* @author looly
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public enum JakartaSoapProtocol {
|
||||||
|
/** SOAP 1.1协议 */
|
||||||
|
SOAP_1_1(SOAPConstants.SOAP_1_1_PROTOCOL),
|
||||||
|
/** SOAP 1.2协议 */
|
||||||
|
SOAP_1_2(SOAPConstants.SOAP_1_2_PROTOCOL);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
*
|
||||||
|
* @param value {@link SOAPConstants} 中的协议版本值
|
||||||
|
*/
|
||||||
|
JakartaSoapProtocol(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取版本值信息
|
||||||
|
*
|
||||||
|
* @return 版本值信息
|
||||||
|
*/
|
||||||
|
public String getValue() {
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,91 @@
|
|||||||
|
package cn.hutool.http.webservice;
|
||||||
|
|
||||||
|
import cn.hutool.core.exceptions.UtilException;
|
||||||
|
import cn.hutool.core.util.CharsetUtil;
|
||||||
|
import cn.hutool.core.util.XmlUtil;
|
||||||
|
|
||||||
|
import jakarta.xml.soap.SOAPException;
|
||||||
|
import jakarta.xml.soap.SOAPMessage;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SOAP相关工具类
|
||||||
|
*
|
||||||
|
* @author looly
|
||||||
|
* @since 4.5.7
|
||||||
|
*/
|
||||||
|
public class JakartaSoapUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建SOAP客户端,默认使用soap1.1版本协议
|
||||||
|
*
|
||||||
|
* @param url WS的URL地址
|
||||||
|
* @return {@link SoapClient}
|
||||||
|
*/
|
||||||
|
public static SoapClient createClient(String url) {
|
||||||
|
return SoapClient.create(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建SOAP客户端
|
||||||
|
*
|
||||||
|
* @param url WS的URL地址
|
||||||
|
* @param protocol 协议,见{@link SoapProtocol}
|
||||||
|
* @return {@link SoapClient}
|
||||||
|
*/
|
||||||
|
public static SoapClient createClient(String url, SoapProtocol protocol) {
|
||||||
|
return SoapClient.create(url, protocol);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建SOAP客户端
|
||||||
|
*
|
||||||
|
* @param url WS的URL地址
|
||||||
|
* @param protocol 协议,见{@link SoapProtocol}
|
||||||
|
* @param namespaceURI 方法上的命名空间URI
|
||||||
|
* @return {@link SoapClient}
|
||||||
|
* @since 4.5.6
|
||||||
|
*/
|
||||||
|
public static SoapClient createClient(String url, SoapProtocol protocol, String namespaceURI) {
|
||||||
|
return SoapClient.create(url, protocol, namespaceURI);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link SOAPMessage} 转为字符串
|
||||||
|
*
|
||||||
|
* @param message SOAP消息对象
|
||||||
|
* @param pretty 是否格式化
|
||||||
|
* @return SOAP XML字符串
|
||||||
|
*/
|
||||||
|
public static String toString(SOAPMessage message, boolean pretty) {
|
||||||
|
return toString(message, pretty, CharsetUtil.CHARSET_UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link SOAPMessage} 转为字符串
|
||||||
|
*
|
||||||
|
* @param message SOAP消息对象
|
||||||
|
* @param pretty 是否格式化
|
||||||
|
* @param charset 编码
|
||||||
|
* @return SOAP XML字符串
|
||||||
|
* @since 4.5.7
|
||||||
|
*/
|
||||||
|
public static String toString(SOAPMessage message, boolean pretty, Charset charset) {
|
||||||
|
final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
message.writeTo(out);
|
||||||
|
} catch (SOAPException | IOException e) {
|
||||||
|
throw new SoapRuntimeException(e);
|
||||||
|
}
|
||||||
|
String messageToString;
|
||||||
|
try {
|
||||||
|
messageToString = out.toString(charset.toString());
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
throw new UtilException(e);
|
||||||
|
}
|
||||||
|
return pretty ? XmlUtil.format(messageToString) : messageToString;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
package cn.hutool.http.webservice;
|
||||||
|
|
||||||
|
import cn.hutool.core.lang.Console;
|
||||||
|
import cn.hutool.core.util.CharsetUtil;
|
||||||
|
import jakarta.xml.soap.SOAPException;
|
||||||
|
import jakarta.xml.soap.SOAPMessage;
|
||||||
|
import org.junit.jupiter.api.Disabled;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SOAP相关单元测试
|
||||||
|
*
|
||||||
|
* @author looly
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class JakartaSoapClientTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Disabled
|
||||||
|
public void requestTest() {
|
||||||
|
JakartaSoapClient client = JakartaSoapClient.create("http://www.webxml.com.cn/WebServices/IpAddressSearchWebService.asmx")
|
||||||
|
.setMethod("web:getCountryCityByIp", "http://WebXml.com.cn/")
|
||||||
|
.setCharset(CharsetUtil.CHARSET_GBK)
|
||||||
|
.setParam("theIpAddress", "218.21.240.106");
|
||||||
|
|
||||||
|
Console.log(client.getMsgStr(true));
|
||||||
|
|
||||||
|
Console.log(client.send(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Disabled
|
||||||
|
public void requestForMessageTest() throws SOAPException {
|
||||||
|
JakartaSoapClient client = JakartaSoapClient.create("http://www.webxml.com.cn/WebServices/IpAddressSearchWebService.asmx")
|
||||||
|
.setMethod("web:getCountryCityByIp", "http://WebXml.com.cn/")
|
||||||
|
.setParam("theIpAddress", "218.21.240.106");
|
||||||
|
|
||||||
|
SOAPMessage message = client.sendForMessage();
|
||||||
|
Console.log(message.getSOAPBody().getTextContent());
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user