本文参考自 整理HttpClient4.5的Fluent API的用法 ,如有侵权,请作者联系删除。
<!-- java端模拟浏览器发送请求 -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>fluent-hc</artifactId>
<version>4.5.6</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.6</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.5.6</version>
</dependency>
<!-- 工具集 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8.1</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>27.0-jre</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.3</version>
</dependency>
package vip.coinbag.managemoneymatters.common.http;
import org.apache.commons.beanutils.BeanMap;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.NameValuePair;
import org.apache.http.client.fluent.Request;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.util.Args;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/**
* 类描述:Apache HttpClient Fluent快速发送GET/POST访问,目前不支持需要登录的操作,待后续完善。
* @author wzx
* @time 2018/11/1
*/
public class HttpFluent {
private static final Logger LOGGER = LoggerFactory.getLogger(HttpFluent.class);
private static final Integer CONNECT_TIMEOUT = 5000; // 连接超时5s
private static final Integer SOCKET_TIMEOUT = 30000; // 数据传输超时30s
/**
* 功能描述:无参数的GET请求。
* jl
* @param url
* @since JDK1.8
* 创建日期:2018/11/2 14:37。
* 更新日期:[日期YYYY-MM-DD][更改人姓名][变更描述]。
*/
public static String doGet(String url) {
Args.notNull(url, "url");
try {
return Request.Get(url).connectTimeout(CONNECT_TIMEOUT).socketTimeout(SOCKET_TIMEOUT).execute().returnContent().asString(Consts.UTF_8);
} catch (IOException e) {
e.printStackTrace();
LOGGER.error(e.getMessage(), e.toString());
}
return null;
}
/**
* 功能描述:带参数的GET请求。
* jl
* @param url
* @param params
* @since JDK1.8
* 创建日期:2018/11/2 14:39。
* 更新日期:[日期YYYY-MM-DD][更改人姓名][变更描述]。
*/
public static String doGet(String url, Object params) {
return executeGet(url, null, null, null, params);
}
/**
* 功能描述:设置代理的 GET 请求。
* jl
* @param url
* @param hostName
* @param port
* @param schemeName
* @param params
* @since JDK1.8
* 创建日期:2018/11/2 17:34。
* 更新日期:[日期YYYY-MM-DD][更改人姓名][变更描述]。
*/
public static String doGet(String url, String hostName, Integer port, String schemeName, Object params) {
return executeGet(url, hostName, port, schemeName, params);
}
/**
* 功能描述:执行 GET 请求。
* jl
* @param url
* @param hostName
* @param port
* @param schemeName
* @param params
* @since JDK1.8
* 创建日期:2018/11/2 17:35。
* 更新日期:[日期YYYY-MM-DD][更改人姓名][变更描述]。
*/
private static String executeGet(String url, String hostName, Integer port, String schemeName, Object params) {
if (StringUtils.isEmpty(url)) {
return null;
}
url = buildGetParam(url, params);
Request request = Request.Get(url).connectTimeout(CONNECT_TIMEOUT).socketTimeout(SOCKET_TIMEOUT);
request = buildProxy(request, hostName, port, schemeName);
try {
return request.execute().returnContent().asString(Consts.UTF_8);
} catch (IOException e) {
e.printStackTrace();
LOGGER.error(e.getMessage(), e.toString());
}
return null;
}
/**
* 功能描述:构建 GET 参数。
* jl
* @param url
* @param params
* @since JDK1.8
* 创建日期:2018/11/2 16:52。
* 更新日期:[日期YYYY-MM-DD][更改人姓名][变更描述]。
*/
private static String buildGetParam(String url, Object params) {
if (params != null) {
//拼接参数
url += "?" + URLEncodedUtilsPerfect.format(params, Consts.UTF_8);
}
return url;
}
/**
* 功能描述:不带参数的 POST 请求。
* jl
* @param url
* @since JDK1.8
* 创建日期:2018/11/2 17:36。
* 更新日期:[日期YYYY-MM-DD][更改人姓名][变更描述]。
*/
public static String doPost(String url) {
return doPost(url, null, null, null, null, null);
}
/**
* 功能描述:发送json格式的post请求。
* jl
* @param url
* @param jsonData
* @since JDK1.8
* 创建日期:2018/11/1 16:45。
* 更新日期:[日期YYYY-MM-DD][更改人姓名][变更描述]。
*/
public static String doPost(String url, String jsonData) {
if (StringUtils.isEmpty(jsonData)) {
return doPost(url);
}
Request request = Request.Post(url).connectTimeout(CONNECT_TIMEOUT).socketTimeout(SOCKET_TIMEOUT).bodyString(jsonData, ContentType.APPLICATION_JSON);
try {
return request.execute().returnContent().asString(Consts.UTF_8);
} catch (IOException e) {
e.printStackTrace();
LOGGER.error(e.getMessage(), e.toString());
}
return null;
}
public static String doPost(String url, Object params) {
return doPost(url, null, null, null, params, null);
}
public static void doPost(String url, Object params, List<File> files) {
doPost(url, null, null, null, params, files);
}
public static String doPost(String url, String hostName, Integer port, String schemeName, Object params, List<File> files) {
return executePost(url, hostName, port, schemeName, params, files);
}
private static String executePost(String url, String hostName, Integer port, String schemeName, Object params, List<File> files) {
if (StringUtils.isEmpty(url)) {
return null;
}
HttpEntity entity = buildPostParam(params, files);
/**
* Content type 'application/x-www-form-urlencoded'
* 这是默认的不设置contentType时的请求头,那么在controller层接收的时候就要用 @RequestParam FirstProject firstProject
* 这样的响应头来接收
* 如果controller层用 @RequestBody FirstProject firstProject 这样的格式来接收,那么contentType应该设为 'application/json'
* 传输数据的格式应该是json格式的,可以调用 doPost(String url, String jsonData)方法
*/
Request request = Request.Post(url).connectTimeout(CONNECT_TIMEOUT).socketTimeout(SOCKET_TIMEOUT).body(entity);
request = buildProxy(request, hostName, port, schemeName);
try {
return request.execute().returnContent().asString(Consts.UTF_8);
} catch (IOException e) {
e.printStackTrace();
LOGGER.error(e.getMessage(), e.toString());
}
return null;
}
/**
* 构建POST方法请求参数
* @return
*/
private static HttpEntity buildPostParam(Object params, List<File> files) {
if(params == null && CollectionUtils.isEmpty(files)) {
return null;
}
if(CollectionUtils.isNotEmpty(files)) {
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
for (File file : files) {
/**
* 在接收文件的响应头中默认是这样写的 @RequestParam List file
* 其实这样写默认接收响应头name为file的文件,即接收文件参数其实是这样的 @RequestParam("file") List file
* 所以addBinaryBody的name应该设为file,但是可根据自己接收参数的设置做相应修改
*/
builder.addBinaryBody("file", file, ContentType.APPLICATION_OCTET_STREAM, file.getName());
}
if (params != null) {
if (params instanceof Map) {
Map map = (Map) params;
for (Object key : map.keySet()) {
if (key == null || map.get(key) == null) {
continue;
}
builder.addTextBody(key.toString(), map.get(key).toString(), ContentType.create("text/plain", Consts.UTF_8));
}
} else if (params instanceof List) {
List list = (List) params;
if (list.get(0) instanceof NameValuePair) {
List<NameValuePair> nameValuePairs = list;
for (NameValuePair nameValuePair : nameValuePairs) {
//设置ContentType为UTF-8,默认为text/plain; charset=ISO-8859-1,传递中文参数会乱码
builder.addTextBody(nameValuePair.getName(), nameValuePair.getValue(), ContentType.create("text/plain", Consts.UTF_8));
}
}
} else { // 参数类型为 javaBean
// Object 转 Map 类型
Map map = new BeanMap(params);
for (Object key : map.keySet()) {
if (key == null || map.get(key) == null) {
continue;
}
builder.addTextBody(key.toString(), map.get(key).toString(), ContentType.create("text/plain", Consts.UTF_8));
}
}
}
return builder.build();
} else {
return new UrlEncodedFormEntityPerfect(params, Consts.UTF_8);
}
}
/**
* 设置代理
* @param request
* @param hostName
* @param port
* @param schemeName
* @return
*/
private static Request buildProxy(Request request, String hostName, Integer port, String schemeName) {
if(StringUtils.isNotEmpty(hostName) && port != null) {
//设置代理
if (StringUtils.isEmpty(schemeName)) {
schemeName = HttpHost.DEFAULT_SCHEME_NAME;
}
request.viaProxy(new HttpHost(hostName, port, schemeName));
}
return request;
}
}
URLEncodedUtils工具类只提供了List
package vip.coinbag.managemoneymatters.common.http;
import org.apache.commons.beanutils.BeanMap;
import org.apache.http.Consts;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.util.Args;
import org.springframework.util.StringUtils;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Map;
/**
* 类描述:。
*
* @author jl
* @version v1.0.0.1。
* @since JDK1.8。
* 创建日期:2018/11/2 15:12。
*/
public class URLEncodedUtilsPerfect extends URLEncodedUtils {
private static final char QP_SEP_A = '&';
private static final String NAME_VALUE_SEPARATOR = "=";
/**
* 功能描述:构造参数。
* jl
* @param parameters
* @param charset
* @since JDK1.8
* 创建日期:2018/11/2 17:09。
* 更新日期:[日期YYYY-MM-DD][更改人姓名][变更描述]。
*/
public static String format(
final Object parameters,
final Charset charset) {
if (parameters == null) {
return "";
}
if (parameters instanceof Map) { // 参数类型为 Map
Map map = (Map) parameters;
return format(map, QP_SEP_A, charset != null ? charset : Consts.UTF_8);
} else if ((parameters instanceof List)) {
List list = (List) parameters;
if (list.get(0) instanceof NameValuePair) { // 参数类型为 List
List<NameValuePair> nameValuePairs = list;
return format(nameValuePairs, charset != null ? charset : Consts.UTF_8);
}
return "";
} else { // 参数类型为 javaBean
// Object 转 Map 类型
Map map = new BeanMap(parameters);
return format(map, QP_SEP_A, charset != null ? charset : Consts.UTF_8);
}
}
/**
* 功能描述:构造参数类型为 Map 的参数。
* jl
* @param parameters
* @param parameterSeparator
* @param charset
* @since JDK1.8
* 创建日期:2018/11/2 17:23。
* 更新日期:[日期YYYY-MM-DD][更改人姓名][变更描述]。
*/
public static String format(
final Map parameters,
final char parameterSeparator,
final Charset charset) {
Args.notNull(parameters, "Parameters");
final StringBuilder result = new StringBuilder();
for (final Object key : parameters.keySet()) {
try {
final String encodedName = encodeFormFields(key, charset.toString());
final String encodedValue = encodeFormFields(parameters.get(key), charset.toString());
if (result.length() > 0) {
result.append(parameterSeparator);
}
if (StringUtils.isEmpty(encodedName) || StringUtils.isEmpty(encodedValue)) {
continue;
}
result.append(encodedName);
if (encodedValue != null) {
result.append(NAME_VALUE_SEPARATOR);
result.append(encodedValue);
}
} catch (Exception e) {
e.printStackTrace();
}
}
return result.toString();
}
/**
* 功能描述:参数编码。
* jl
* @param content
* @param charset
* @since JDK1.8
* 创建日期:2018/11/2 17:22。
* 更新日期:[日期YYYY-MM-DD][更改人姓名][变更描述]。
*/
private static String encodeFormFields(final Object content, final String charset) throws UnsupportedEncodingException {
if (content == null) {
return null;
}
return URLEncoder.encode(content.toString(), charset);
}
}
在构造post参数时同样只提供了List
package vip.coinbag.managemoneymatters.common.http;
import org.apache.http.Consts;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import java.nio.charset.Charset;
/**
* 类描述:。
*
* @author jl
* @version v1.0.0.1。
* @since JDK1.8。
* 创建日期:2018/11/2 17:40。
*/
public class UrlEncodedFormEntityPerfect extends StringEntity {
public UrlEncodedFormEntityPerfect(final Object parameters, final Charset charset) {
super(URLEncodedUtilsPerfect.format(parameters,
charset != null ? charset : Consts.UTF_8),
ContentType.create(URLEncodedUtils.CONTENT_TYPE, charset != null ? charset : Consts.UTF_8));
}
}