import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
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.entity.BasicHttpEntity;
import org.apache.http.entity.ContentType;
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.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.pool.PoolStats;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
/**
* 通过http连接池来管理连接
* 注:closeConnections()方法需要另起一个线程,每隔一段时间执行一次回收已成功或者已过期的连接。(如用spring的定时任务)
* @author liluqing
* @date 2016-06-01
*/
public class HttpUtils {
static Logger logger=Logger.getLogger(HttpUtils.class);
private static PoolingHttpClientConnectionManager cm =null;
//定义编码格式 UTF-8
public static final String URL_PARAM_DECODECHARSET_UTF8 = "UTF-8";
//定义编码格式 GBK
public static final String URL_PARAM_DECODECHARSET_GBK = "GBK";
private static final String URL_PARAM_CONNECT_FLAG = "&";
private static final String EMPTY = "";
private static int connectionTimeOut = 20*60*1000;
private static int socketTimeOut = 20*60*1000;
//链接管理器容量,将每个路由的最大连接数增加到200
private static int maxTotal =100;
//将每个路由的默认最大并发数。超过最大并发数的线程将进入阻塞状态。直到有链接过期或被关闭。
private static int maxPerRoute = 20;
static{
//创建链接管理器
cm=new PoolingHttpClientConnectionManager();
//链接管理器容量,将每个路由的最大连接数增加到200
cm.setMaxTotal(maxTotal);
//将每个路由的默认最大并发数。超过最大并发数的线程将进入阻塞状态。直到有链接过期或被关闭。
cm.setDefaultMaxPerRoute(maxPerRoute);
//定义将某个路由的最大并发数
//HttpHost localhost = new HttpHost("locahost", 80);
//cm.setMaxPerRoute(new HttpRoute(localhost), 50);//设置对于某个目标主机的最大并发数
}
/**
* 重连接管理器中获取CloseableHttpClient对象
* @return
*/
public static CloseableHttpClient getCloseableHttpClient(){
return HttpClients.custom().setConnectionManager(cm).build();
}
/**
* 关闭回收所有已经请求成功,或者请求超时的连接
* 该方法需用spring做一个定时任务每隔5秒(根据具体情况来配置)执行一次
*/
public static void closeConnections(){
cm.closeExpiredConnections();
cm.closeIdleConnections(30, TimeUnit.SECONDS);
}
/**
* 获取连接管理器状态。
*/
public static String getState(){
PoolStats state=cm.getTotalStats();
return "http连接池信息:[可用连接:"+state.getAvailable()+"; 正在执行的连接:"+state.getLeased()+"; 被阻塞的连接:"+state.getPending()+"; 最大可用连接数:"+state.getMax()+"]";
}
/**
* 以UTF8的方式发送报文。当目标服务器采用UTF8时,需用该方法。否则会导致请求参数乱码,目标服务器无法解析
* @param url 连接地址
* @param xml 报文
* @param decode 响应报文的编码
* @return
*/
public static String httpPostForXMLUTF8(String url,String xml,String decode){
String result=null;
CloseableHttpClient client=getCloseableHttpClient();//创建会话
HttpPost httppost= new HttpPost(url);
httppost.setHeader("Content-Type", "text/xml;charset=UTF-8");//设置请求头
StringEntity entity = new StringEntity(xml,
ContentType.create("text/xml", Consts.UTF_8));//定义请求消息实体
entity.setChunked(false);
RequestConfig requestConfig = RequestConfig.custom().
setSocketTimeout(socketTimeOut).setConnectTimeout(connectionTimeOut).build();//设置连接超时和socket超时时间
httppost.setConfig(requestConfig);
httppost.setEntity(entity);
CloseableHttpResponse response=null;
try {
response=client.execute(httppost);//执行请求
HttpEntity ety=response.getEntity();//获取响应实体
result=EntityUtils.toString(ety,decode);//由于税控服务器的编码格式为GBK,故需将返回内容按GBK的方式来解码
} catch (ClientProtocolException e) {
logger.error("request url=" + url + ", exception, msg=" + e.getMessage(),e);
} catch (IOException e) {
logger.error("request url=" + url + ", exception, msg=" + e.getMessage(),e);
}finally{
try {
if(response!=null){
response.close();//关闭响应流
}
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
/**
* 以GBK的方式发送报文。当目标服务器采用GBK时,需用该方法。否则会导致请求参数乱码,目标服务器无法解析
* @param url 连接地址
* @param xml 报文
* @param decode 响应报文的编码
* @return
*/
public static String httpPostForXMLGBK(String url,String xml,String decode){
String result=null;
CloseableHttpClient client=getCloseableHttpClient();//创建会话
HttpPost httppost= new HttpPost(url);
httppost.setHeader("Content-Type", "text/xml;charset=UTF-8");//设置请求头
StringEntity entity = new StringEntity(xml,"gbk");//定义请求消息实体
entity.setChunked(true);
RequestConfig requestConfig = RequestConfig.custom().
setSocketTimeout(socketTimeOut).setConnectTimeout(connectionTimeOut).build();//设置连接超时和socket超时时间
httppost.setConfig(requestConfig);
httppost.setEntity(entity);
CloseableHttpResponse response=null;
try {
response=client.execute(httppost);//执行请求
HttpEntity ety=response.getEntity();//获取响应实体
result=EntityUtils.toString(ety,decode);//由于税控服务器的编码格式为GBK,故需将返回内容按GBK的方式来解码
} catch (ClientProtocolException e) {
logger.error("request url=" + url + ", exception, msg=" + e.getMessage(),e);
} catch (IOException e) {
logger.error("request url=" + url + ", exception, msg=" + e.getMessage(),e);
}finally{
try {
if(response!=null){
response.close();//关闭响应流
}
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
/**
* post请求模拟form表单提交
* @param url 连接地址
* @param params post请求参数
* @param enc 请求参数编码
* @return
*/
public static String httpPost(String url, Map<String, String> params, String enc){
String result=null;
CloseableHttpClient client=getCloseableHttpClient();//创建会话
//设置超时禁止自动提交的2种方法
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(0,false));
HttpPost httppost= new HttpPost(url);
//设置头类型为from表单提交
httppost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=" + enc);
RequestConfig requestConfig = RequestConfig.custom().
setSocketTimeout(socketTimeOut).setConnectTimeout(connectionTimeOut).build();//设置连接超时和socket超时时间
httppost.setConfig(requestConfig);
UrlEncodedFormEntity entity=getUrlEncodedFormEntity(params);
httppost.setEntity(entity);
CloseableHttpResponse response=null;
try {
response=client.execute(httppost);//执行请求
HttpEntity ety=response.getEntity();//获取响应实体
result=EntityUtils.toString(ety,URL_PARAM_DECODECHARSET_UTF8);
} catch (ClientProtocolException e) {
logger.error("request url=" + url + ", exception, msg=" + e.getMessage(),e);
} catch (IOException e) {
logger.error("request url=" + url + ", exception, msg=" + e.getMessage(),e);
}finally{
try {
if(response!=null){
response.close();//关闭响应流
}
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
/**
* get请求
* @param url
* @return
*/
public static String httpGet(String url){
HttpGet httpGet = new HttpGet(url);
CloseableHttpResponse response = null;
CloseableHttpClient httpClient = getCloseableHttpClient();
RequestConfig requestConfig = RequestConfig.custom().
setSocketTimeout(socketTimeOut).setConnectTimeout(connectionTimeOut).build();
httpGet.setConfig(requestConfig);
try {
response = httpClient.execute(httpGet, new BasicHttpContext());
if (response.getStatusLine().getStatusCode() != 200) {
return null;
}
HttpEntity entity = response.getEntity();
if (entity != null) {
String resultStr = EntityUtils.toString(entity,URL_PARAM_DECODECHARSET_UTF8);
return resultStr;
}
} catch (IOException e) {
logger.error("request url=" + url + ", exception, msg=" + e.getMessage(),e);
} finally {
if (response != null) try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
/**
* get请求模拟表单提交
* @param url
* @param params
* @param enc
* @return
*/
public static String httpGet(String url, Map<String, String> params, String enc){
StringBuilder strtTotalURL = new StringBuilder(EMPTY);
if(strtTotalURL.indexOf("?") == -1) {
strtTotalURL.append(url).append("?").append(getUrl(params, enc));
} else {
strtTotalURL.append(url).append("&").append(getUrl(params, enc));
}
HttpGet httpGet = new HttpGet(strtTotalURL.toString());
//设置头类型为from表单提交
httpGet.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=" + enc);
CloseableHttpResponse response = null;
CloseableHttpClient httpClient = getCloseableHttpClient();
RequestConfig requestConfig = RequestConfig.custom().
setSocketTimeout(socketTimeOut).setConnectTimeout(connectionTimeOut).build();
httpGet.setConfig(requestConfig);
try {
response = httpClient.execute(httpGet, new BasicHttpContext());
if (response.getStatusLine().getStatusCode() != 200) {
return null;
}
HttpEntity entity = response.getEntity();
if (entity != null) {
String resultStr = EntityUtils.toString(entity,URL_PARAM_DECODECHARSET_UTF8);
return resultStr;
}
} catch (IOException e) {
logger.error("request url=" + strtTotalURL.toString() + ", exception, msg=" + e.getMessage(),e);
} finally {
if (response != null) try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
/**
* 据Map生成URL字符串
* @param map
* Map
* @param valueEnc
* URL编码
* @return
* URL
*/
private static String getUrl(Map<String, String> map, String valueEnc) {
if (null == map || map.keySet().size() == 0) {
return (EMPTY);
}
StringBuffer url = new StringBuffer();
Set<String> keys = map.keySet();
for (Iterator<String> it = keys.iterator(); it.hasNext();) {
String key = it.next();
if (map.containsKey(key)) {
String val = map.get(key);
String str = val != null ? val : EMPTY;
try {
str = URLEncoder.encode(str, valueEnc);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
url.append(key).append("=").append(str).append(URL_PARAM_CONNECT_FLAG);
}
}
String strURL = EMPTY;
strURL = url.toString();
if (URL_PARAM_CONNECT_FLAG.equals(EMPTY + strURL.charAt(strURL.length() - 1))) {
strURL = strURL.substring(0, strURL.length() - 1);
}
return (strURL);
}
public static UrlEncodedFormEntity getUrlEncodedFormEntity(Map<String, String> params){
List<NameValuePair> formparams = new ArrayList<NameValuePair>();
if(params!=null&¶ms.size()>0){
Iterator<Entry<String, String>> it=params.entrySet().iterator();
while(it.hasNext()){
Entry<String, String> en=it.next();
formparams.add(new BasicNameValuePair(en.getKey(),en.getValue()));
}
}
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams,
Consts.UTF_8);
entity.setChunked(true);
return entity;
}
public static String dopostXmlStr(String surl,String xml) throws IOException{
URL url=null;
HttpURLConnection connection = null;
url = new URL(surl);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty("Content-Type", "text/xml");
connection.setDoOutput(true);
OutputStreamWriter out = new OutputStreamWriter(connection
.getOutputStream(), "utf-8");
out.write(xml);
out.flush();
out.close();
// 一旦发送成功,用以下方法就可以得到服务器的回应:
String responseContent = "";
//读取数据并按GBK方式进行解码
InputStreamReader l_urlStream = new InputStreamReader(connection.getInputStream(),"utf-8");
// 传说中的三层包装阿
BufferedReader l_reader = new BufferedReader(l_urlStream);
String sCurrentLine="";//按行读取xml
while ((sCurrentLine = l_reader.readLine()) != null) {
responseContent += sCurrentLine + "
";
}
if (connection != null) {
connection.disconnect();//销毁连接
}
return responseContent;
}
}