引入maven依赖:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
HttpUtils.java
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustAllStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import java.nio.charset.Charset;
/**
* @author linxz
* @version 1.0
* @date 2021/1/25 17:04
*/
@Slf4j
public class HttpUtils {
// 池化管理
private static PoolingHttpClientConnectionManager poolConnManager = null;
/**
* 连接目标超时时间
*/
private static final int defaultcCnnectionTimeOut =3000;
/**
* 从连接池中获取可用连接超时
*/
private static final int defaultRequestTimeOut =1000;
/**
* 等待响应超时
*/
private static final int defaultSocketTimeOut =30000;
/**
* 重试次数
*/
private static final int defaultRequestRetryCount =3;
/**
* 最多连接数
*/
private static final int defaultMaxTotal =800;
/**
* 最大路由
*/
private static final int defaultMaxPerRoute =200;
static {
try {
SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(null, TrustAllStrategy.INSTANCE);
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build());
// 配置同时支持 HTTP 和 HTPPS
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", sslsf).build();
// 初始化连接管理器
poolConnManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
// 同时最多连接数
poolConnManager.setMaxTotal(defaultMaxTotal);
// 设置最大路由
poolConnManager.setDefaultMaxPerRoute(defaultMaxPerRoute);
// 此处解释下MaxtTotal和DefaultMaxPerRoute的区别:
// 1、MaxtTotal是整个池子的大小;
// 2、DefaultMaxPerRoute是根据连接到的主机对MaxTotal的一个细分;比如:
// MaxtTotal=400 DefaultMaxPerRoute=200
// 而我只连接到http://www.abc.com时,到这个主机的并发最多只有200;而不是400;
// 而我连接到http://www.bac.com 和
// http://www.ccd.com时,到每个主机的并发最多只有200;即加起来是400(但不能超过400);所以起作用的设置是DefaultMaxPerRoute
} catch (Exception e){
log.error("HttpClient连接池初始化失败",e);
}
}
public static CloseableHttpClient getConnection() {
return getConnection(defaultcCnnectionTimeOut, defaultRequestTimeOut, defaultSocketTimeOut, defaultRequestRetryCount);
}
public static CloseableHttpClient getConnection(int connTimeOut,int requestTimeOut,int socketTimeOut,int retryCount) {
RequestConfig config = RequestConfig.custom().setConnectTimeout(connTimeOut)
.setConnectionRequestTimeout(requestTimeOut)
.setSocketTimeout(socketTimeOut)
.build();
CloseableHttpClient httpClient = HttpClients.custom()
// 设置连接池管理
.setConnectionManager(poolConnManager)
.setDefaultRequestConfig(config)
// 设置重试次数
.setRetryHandler(new DefaultHttpRequestRetryHandler(retryCount, false)).build();
return httpClient;
}
/**
* 发送post请求,使用默认设置
* @param httpPost
* @return
*/
public static String post(HttpPost httpPost){
return executeHttpReq(httpPost);
}
/**
* 发送get请求,使用默认设置
* @param httpGet
* @return
*/
public static String get(HttpGet httpGet){
return executeHttpReq(httpGet);
}
/**
* 发送post请求,自定义超时时间与重试次数
* @param httpPost
* @param connTimeOut
* @param requestTimeOut
* @param socketTimeOut
* @param retryCount
* @return
*/
public static String post(HttpPost httpPost,int connTimeOut,int requestTimeOut,int socketTimeOut,int retryCount, Charset charset){
return executeHttpReq(httpPost,connTimeOut,requestTimeOut,socketTimeOut,retryCount,charset);
}
/**
* 发送get请求,自定义超时时间与重试次数
* @param httpGet
* @param connTimeOut
* @param requestTimeOut
* @param socketTimeOut
* @param retryCount
* @return
*/
public static String get(HttpGet httpGet,int connTimeOut,int requestTimeOut,int socketTimeOut,int retryCount, Charset charset){
return executeHttpReq(httpGet,connTimeOut,requestTimeOut,socketTimeOut,retryCount,charset);
}
/**
* 发送http请求,使用默认设置
* @param httpRequest
* @return
*/
public static String executeHttpReq(HttpUriRequest httpRequest){
return executeHttpReq(httpRequest, defaultcCnnectionTimeOut, defaultRequestTimeOut, defaultSocketTimeOut, defaultRequestRetryCount,CommonConstant.DEFAULT_CHARSET);
}
/**
* 发送http请求,自定义超时时间与重试次数
* @param httpRequest
* @param connTimeOut
* @param requestTimeOut
* @param socketTimeOut
* @param retryCount
* @return
*/
public static String executeHttpReq(HttpUriRequest httpRequest, int connTimeOut, int requestTimeOut, int socketTimeOut, int retryCount, Charset charset){
CloseableHttpClient httpClient=getConnection(connTimeOut,requestTimeOut,socketTimeOut,retryCount);
try(CloseableHttpResponse httpResponse=httpClient.execute(httpRequest)){
return EntityUtils.toString(httpResponse.getEntity(), charset);
}catch (Exception e){
log.error("http请求失败",e);
}
return null;
}
public static void main(String[] args) throws JsonProcessingException {
//测试get接口
HttpGet getRequest=new HttpGet("https://www.baidu.com");
System.out.println(get(getRequest));
//测试post接口
HttpPost postRequest = new HttpPost("http://localhost:8888/api/user/getUserInfo");
postRequest.addHeader("authToken","JhgziUt2Q/k8NbYzns8OlQ==");
StringEntity params = new StringEntity("", "UTF-8");
postRequest.addHeader("content-type", "application/json");
postRequest.setEntity(params);
System.out.println(post(postRequest));
//测试webservice接口
HttpPost soapRequest=new HttpPost("http://www.webxml.com.cn/WebServices/IpAddressSearchWebService.asmx");
soapRequest.addHeader("Content-Type","text/xml;charset=UTF-8");
soapRequest.setEntity(new StringEntity("<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:web=\"http://WebXml.com.cn/\">\n" +
" <soapenv:Header/>\n" +
" <soapenv:Body>\n" +
" <web:getCountryCityByIp>\n" +
" <!--Optional:-->\n" +
" <web:theIpAddress>144.144.144.1</web:theIpAddress>\n" +
" </web:getCountryCityByIp>\n" +
" </soapenv:Body>\n" +
"</soapenv:Envelope>",CommonConstant.DEFAULT_CHARSET));
System.out.println(post(soapRequest));
}
}
SoapUtils.java
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicHeader;
import javax.xml.soap.*;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
/**
* @author linxz
* @version 1.0
* @date 2021/1/25 17:04
*/
@Slf4j
public class SoapUtils {
/**
* 使用SOAP1.1发送消息
*
* @param url 为访问的wsdl地址(登陆后wsdl文件中的soap:address)
* @param soapXml
* @param soapAction
* @param userpass 认证用户密码格式:username:password(如:admin:123456)
* @return
*/
public static String doPostSoap1_1(String url, String soapXml, String soapAction, String userpass) {
return doPostSoapByDefaultHttpSetting(url,soapXml,soapAction,userpass,"text/xml;charset=UTF-8");
}
/**
* 使用SOAP1.2发送消息
*
* @param url 为访问的wsdl地址(登陆后wsdl文件中的soap:address)
* @param soapXml
* @param soapAction
* @param userpass 认证用户密码格式:username:password(如:admin:123456)
* @return
*/
public static String doPostSoap1_2(String url, String soapXml, String soapAction, String userpass) {
return doPostSoapByDefaultHttpSetting(url,soapXml,soapAction,userpass,"application/soap+xml;charset=UTF-8");
}
/**
* 发送SOAP消息,使用默认的http请求设置
* @param url
* @param soapXml
* @param soapAction
* @param userpass
* @param contentType
* @return
*/
public static String doPostSoapByDefaultHttpSetting(String url, String soapXml, String soapAction, String userpass, String contentType){
String result = null;
result=HttpUtils.post(createPostRequest(url, soapXml, soapAction, userpass, contentType));
// 打印响应内容
log.debug("soap响应:{}", result);
return result;
}
/**
* 使用SOAP1.1发送消息
*
* @param url 为访问的wsdl地址(登陆后wsdl文件中的soap:address)
* @param soapXml
* @param soapAction
* @param userpass 认证用户密码格式:username:password(如:admin:123456)
* @return
*/
public static String doPostSoap1_1(String url, String soapXml, String soapAction, String userpass
, int connTimeOut, int requestTimeOut, int socketTimeOut, int retryCount, Charset charset) {
return doPostSoapByCustomerHttpSetting(url,soapXml,soapAction,userpass,"text/xml;charset=UTF-8",
connTimeOut,requestTimeOut,socketTimeOut,retryCount,charset);
}
/**
* 使用SOAP1.2发送消息
*
* @param url 为访问的wsdl地址(登陆后wsdl文件中的soap:address)
* @param soapXml
* @param soapAction
* @param userpass 认证用户密码格式:username:password(如:admin:123456)
* @return
*/
public static String doPostSoap1_2(String url, String soapXml, String soapAction, String userpass
, int connTimeOut, int requestTimeOut, int socketTimeOut, int retryCount, Charset charset) {
return doPostSoapByCustomerHttpSetting(url,soapXml,soapAction,userpass,"application/soap+xml;charset=UTF-8",
connTimeOut,requestTimeOut,socketTimeOut,retryCount,charset);
}
/**
* 发送SOAP消息,使用自定义的http请求设置
* @param url
* @param soapXml
* @param soapAction
* @param userpass
* @param contentType
* @param connTimeOut
* @param requestTimeOut
* @param socketTimeOut
* @param retryCount
* @param charset
* @return
*/
public static String doPostSoapByCustomerHttpSetting(String url, String soapXml, String soapAction, String userpass, String contentType
, int connTimeOut, int requestTimeOut, int socketTimeOut, int retryCount, Charset charset){
String result = null;
result=HttpUtils.post(createPostRequest(url, soapXml, soapAction, userpass, contentType),connTimeOut,requestTimeOut,socketTimeOut,retryCount,charset);
// 打印响应内容
log.debug("soap响应:{}", result);
return result;
}
/**
* 构建post请求体
* @param url
* @param soapXml
* @param soapAction
* @param userpass
* @param contentType
* @return
*/
private static HttpPost createPostRequest(String url, String soapXml, String soapAction, String userpass,String contentType){
HttpPost httpPost = new HttpPost(url);
httpPost.setHeader("Content-Type", contentType);
if(StringUtils.isNotBlank(soapAction)){
httpPost.setHeader("SOAPAction", soapAction);
}
if (CommonUtils.isNotBlank(userpass)) {
String base64Auth=Base64Utils.encryptForBase64(userpass.getBytes(CommonConstant.DEFAULT_CHARSET));
BasicHeader basicHeader=new BasicHeader("Authorization", "Basic " +(base64Auth));
httpPost.addHeader(basicHeader);
log.debug("加密后内容:{}", new BasicHeader("Authorization", "Basic " + base64Auth));
}
StringEntity data = new StringEntity(soapXml, CommonConstant.DEFAULT_CHARSET);
httpPost.setEntity(data);
return httpPost;
}
/**
* 创建SoapMessage对象,通过传入的参数自动填充
* @param nameSpaceMap
* @param methodInfo
* @return
* @throws Exception
*/
public static SOAPMessage buildSOAPMessage(Map<String, String> nameSpaceMap, SoapMethodInfo methodInfo) throws Exception{
SOAPMessage soapMessage=buildSOAPMessage(nameSpaceMap);
String prefix=methodInfo.getUseNameSpaceName();
String methodName=methodInfo.getMethodName();
if(nameSpaceMap.containsKey(prefix)==false){
throw ExceptionUtils.exception("不存在的命名空间名称:"+prefix);
}
SOAPBody soapBody=soapMessage.getSOAPBody();
SOAPElement methodElement=soapBody.addChildElement(methodName,prefix,nameSpaceMap.get(prefix));
for(SoapMethodParam methodParam:methodInfo.getParams()){
buildParams(methodParam,methodElement,prefix);
}
return soapMessage;
}
/**
* 创建SoapMessage对象,通过传入的Consumer填充调用函数以及参数信息(自定义程度高)
* @param nameSpaceMap
* @param methodBuilder
* @return
* @throws Exception
*/
public static SOAPMessage buildSOAPMessage(Map<String, String> nameSpaceMap, Consumer<SOAPBody> methodBuilder) throws Exception{
SOAPMessage soapMessage=buildSOAPMessage(nameSpaceMap);
SOAPBody soapBody=soapMessage.getSOAPBody();
methodBuilder.accept(soapBody);
return soapMessage;
}
private static SOAPMessage buildSOAPMessage(Map<String, String> nameSpaceMap) throws Exception{
MessageFactory messageFactory = MessageFactory.newInstance();
SOAPMessage soapMessage = messageFactory.createMessage();
SOAPPart soapPart=soapMessage.getSOAPPart();
SOAPEnvelope envelope=soapPart.getEnvelope();
for (Map.Entry<String,String> entry:nameSpaceMap.entrySet()){
envelope.addNamespaceDeclaration(entry.getKey(),entry.getValue());
}
return soapMessage;
}
/**
* 填充参数
* @param methodParam 参数信息
* @param rootElement body结点
*/
private static void buildParams(SoapMethodParam methodParam, SOAPElement rootElement, String nameSpace) throws Exception {
SOAPElement valueElement=rootElement.addChildElement(methodParam.getName(),nameSpace);
if(methodParam.getSimpleValue()!=null){
//简单值模式
valueElement.setValue(methodParam.getSimpleValue());
}else {
//对象模式
buildParams(methodParam.getObjectValue(),valueElement,nameSpace);
}
}
/**
* 将SOAPMessage转换成string
* @param soapMessage
* @return
* @throws Exception
*/
public static String convertSOAPMessageToString(SOAPMessage soapMessage)throws Exception{
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
Source source = soapMessage.getSOAPPart().getContent();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(1000);
StreamResult result = new StreamResult(byteArrayOutputStream);
transformer.transform(source, result);
String xml = new String(byteArrayOutputStream.toByteArray());
return xml;
}
/**
* 把soap字符串格式化为SOAPMessage
*
* @param soapString
* @return
*/
public static SOAPMessage convertStringToSOAPMessage(String soapString) {
MessageFactory msgFactory;
try {
msgFactory = MessageFactory.newInstance();
SOAPMessage reqMsg = msgFactory.createMessage(new MimeHeaders(),
new ByteArrayInputStream(soapString.getBytes(CommonConstant.DEFAULT_CHARSET)));
reqMsg.saveChanges();
return reqMsg;
} catch (Exception e) {
throw ExceptionUtils.exception("soap字符串转换为SOAPMessage失败",e);
}
}
public static void main(String[] args) throws Exception {
/**
* 命名空间,查看wsdl:types结点中的s:schema的targetNamespace
* 键以xmlns:开头,后面带上自定义的名称 eg: xmlns:web="http://WebXml.com.cn/"表示把这个命名空间用定义名字叫web,后续使用的时候,用web:表示引用"http://WebXml.com.cn/"这个命名空间
*/
Map<String,String> nameSpace=new HashMap<>();
/**
* 对应格式:
* <?xml version="1.0" encoding="UTF-8" standalone="no"?>
* <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://WebXml.com.cn/">
* <soapenv:Header/>
* <soapenv:Body>
* <web:getCountryCityByIp>
* <!--Optional:-->
* <web:theIpAddress>144.144.144.1</web:theIpAddress>
* </web:getCountryCityByIp>
* </soapenv:Body>
* </soapenv:Envelope>
*/
// nameSpace.put("a","http://WebXml.com.cn/");
// MethodInfo methodInfo=new MethodInfo();
// methodInfo.setMethodName("getCountryCityByIp");
// methodInfo.setUseNameSpaceName("a");
// MethodParam methodParam=new MethodParam();
// methodParam.setName("theIpAddress");
// methodParam.setSimpleValue("144.144.144.1");
// methodInfo.setParams(Collections.singletonList(methodParam));
// String xml=convertSOAPMessageToString(buildSOAPMessage(nameSpace,methodInfo));
// System.out.println(xml);
// String result=doPostSoap1_1("http://www.webxml.com.cn/WebServices/IpAddressSearchWebService.asmx",xml,"","");
// System.out.println(result);
/**
* 对应格式:
* <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://WebXml.com.cn/">
* <soapenv:Header/>
* <soapenv:Body>
* <web:getDomesticAirlinesTime>
* <!--Optional:-->
* <web:startCity>深圳</web:startCity>
* <!--Optional:-->
* <web:lastCity>上海</web:lastCity>
* <!--Optional:-->
* <web:theDate>2021-01-26</web:theDate>
* <!--Optional:-->
* <web:userID></web:userID>
* </web:getDomesticAirlinesTime>
* </soapenv:Body>
* </soapenv:Envelope>
*/
// nameSpace.put("web","http://WebXml.com.cn/");
// MethodInfo methodInfo=new MethodInfo();
// methodInfo.setMethodName("getDomesticAirlinesTime");
// methodInfo.setUseNameSpaceName("web");
// List<MethodParam> methodParams=new ArrayList<>();
// MethodParam startCity=new MethodParam();
// startCity.setName("startCity");
// startCity.setSimpleValue("深圳");
// MethodParam lastCity=new MethodParam();
// lastCity.setName("lastCity");
// lastCity.setSimpleValue("上海");
// MethodParam theDate=new MethodParam();
// theDate.setName("theDate");
// theDate.setSimpleValue("2021-01-26");
// methodParams.add(startCity);
// methodParams.add(lastCity);
// methodParams.add(theDate);
// methodInfo.setParams(methodParams);
// String xml=convertSOAPMessageToString(buildSOAPMessage(nameSpace,methodInfo));
// System.out.println(xml);
// String result=doPostSoap1_1("http://www.webxml.com.cn/webservices/DomesticAirline.asmx?wsdl",xml,"","");
// System.out.println(result);
//测试自定义控制参数设置
// nameSpace.put("web","http://WebXml.com.cn/");
// MethodInfo methodInfo=new MethodInfo();
// String xml=convertSOAPMessageToString(buildSOAPMessage(nameSpace, new Consumer<SOAPBody>() {
// @Override
// public void accept(SOAPBody soapBody) {
// try {
// SOAPElement methodElement=soapBody.addChildElement("getDomesticAirlinesTime","web","http://WebXml.com.cn/");
// SOAPElement startCity=methodElement.addChildElement("startCity","web");
// startCity.setValue("深圳");
// SOAPElement lastCity=methodElement.addChildElement("lastCity","web");
// lastCity.setValue("上海");
// SOAPElement theDate=methodElement.addChildElement("theDate","web");
// theDate.setValue("2021-01-26");
// } catch (SOAPException e) {
// e.printStackTrace();
// }
// }
// }));
// System.out.println(xml);
// String result=doPostSoap1_1("http://www.webxml.com.cn/webservices/DomesticAirline.asmx?wsdl",xml,"","");
// System.out.println(result);
}
}
SoapMethodInfo.java
/**
* @author linxz
* @version 1.0
* @date 2021/1/26 17:11
*/
@Getter
@Setter
public class SoapMethodInfo {
//调用的方法名
private String methodName;
//调用方法所引用的命名空间,为nameSpace中的key
private String useNameSpaceName;
//调用方法所使用的参数,可以有层级嵌套
private List<SoapMethodParam> params;
}
SoapMethodParam.java
import lombok.Getter;
import lombok.Setter;
/**
* @author linxz
* @version 1.0
* @date 2021/1/26 17:11
*/
@Getter
@Setter
public class SoapMethodParam {
//参数名称
private String name;
//参数值,对象类型,与simpleValue仅需设置一个,优先使用simpleValue
private SoapMethodParam objectValue;
//参数值,简单类型,与objectValue仅需设置一个,优先使用simpleValue
private String simpleValue;
}
文中的
CommonUtils.isNotBlank()方法是判断字符串是否为空
CommonConstant.DEFAULT_CHARSET等价于Charset.forName(DEFAULT_CHARSET_VALUE);