package cn.trinea.android.common.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import android.os.AsyncTask;
import cn.trinea.android.common.constant.HttpConstants;
import cn.trinea.android.common.entity.HttpRequest;
import cn.trinea.android.common.entity.HttpResponse;
import cn.trinea.android.common.service.HttpCache;
/**
* HttpUtils
* <ul>
* <strong>Http get, you can also use {@link HttpCache}</strong>
* <li>{@link #httpGet(HttpRequest)} http get synchronous</li>
* <li>{@link #httpGet(String)} http get synchronous</li>
* <li>{@link #httpGetString(String)} http get synchronous, response is String</li>
* <li>{@link #httpGet(HttpRequest, cn.trinea.android.common.util.HttpUtils.HttpListener)} http get asynchronous</li>
* <li>{@link #httpGet(String, cn.trinea.android.common.util.HttpUtils.HttpListener)} http get asynchronous</li>
* </ul>
* <ul>
* <strong>Http post</strong>
* <li>{@link #httpPost(HttpRequest)}</li>
* <li>{@link #httpPost(String)}</li>
* <li>{@link #httpPostString(String)}</li>
* <li>{@link #httpPostString(String, java.util.Map)}</li>
* </ul>
* <ul>
* <strong>Http params</strong>
* <li>{@link #getUrlWithParas(String, java.util.Map)}</li>
* <li>{@link #getUrlWithValueEncodeParas(String, java.util.Map)}</li>
* <li>{@link #joinParas(java.util.Map)}</li>
* <li>{@link #joinParasWithEncodedValue(java.util.Map)}</li>
* <li>{@link #appendParaToUrl(String, String, String)}</li>
* <li>{@link #parseGmtTime(String)}</li>
* </ul>
*
* @author <a href="http://www.trinea.cn" target="_blank">Trinea</a> 2013-5-12
*/
public class HttpUtils {
/** url and para separator **/
public static final String URL_AND_PARA_SEPARATOR = "?";
/** parameters separator **/
public static final String PARAMETERS_SEPARATOR = "&";
/** paths separator **/
public static final String PATHS_SEPARATOR = "/";
/** equal sign **/
public static final String EQUAL_SIGN = "=";
private HttpUtils() {
throw new AssertionError();
}
/**
* http get synchronous
* <ul>
* <li>use gzip compression default</li>
* <li>use bufferedReader to improve the reading speed</li>
* </ul>
*
* @param request
* @return the response of the url, if null represents http error
*/
public static HttpResponse httpGet(HttpRequest request) {
if (request == null) {
return null;
}
BufferedReader input = null;
HttpURLConnection con = null;
try {
URL url = new URL(request.getUrl());
try {
HttpResponse response = new HttpResponse(request.getUrl());
// default gzip encode
con = (HttpURLConnection)url.openConnection();
setURLConnection(request, con);
input = new BufferedReader(new InputStreamReader(con.getInputStream()));
StringBuilder sb = new StringBuilder();
String s;
while ((s = input.readLine()) != null) {
sb.append(s).append("\n");
}
response.setResponseBody(sb.toString());
setHttpResponse(con, response);
return response;
} catch (IOException e) {
e.printStackTrace();
}
} catch (MalformedURLException e1) {
e1.printStackTrace();
} finally {
// close buffered
if (input != null) {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// disconnecting releases the resources held by a connection so they may be closed or reused
if (con != null) {
con.disconnect();
}
}
return null;
}
/**
* http get synchronous
*
* @param httpUrl
* @return the response of the url, if null represents http error
* @see cn.trinea.android.common.util.HttpUtils#httpGet(HttpRequest)
*/
public static HttpResponse httpGet(String httpUrl) {
return httpGet(new HttpRequest(httpUrl));
}
/**
* http get synchronous
*
* @param request
* @return the content of the url, if null represents http error
* @see cn.trinea.android.common.util.HttpUtils#httpGet(HttpRequest)
*/
public static String httpGetString(HttpRequest request) {
HttpResponse response = httpGet(request);
return response == null ? null : response.getResponseBody();
}
/**
* http get synchronous
*
* @param httpUrl
* @return the content of the url, if null represents http error
* @see cn.trinea.android.common.util.HttpUtils#httpGet(HttpRequest)
*/
public static String httpGetString(String httpUrl) {
HttpResponse response = httpGet(new HttpRequest(httpUrl));
return response == null ? null : response.getResponseBody();
}
/**
* http get asynchronous
* <ul>
* <li>It gets data from network asynchronous.</li>
* <li>If you want get data synchronous, use {@link #httpGet(HttpRequest)} or {@link #httpGetString(HttpRequest)}</li>
* </ul>
*
* @param url
* @param listener listener which can do something before or after HttpGet. this can be null if you not want to do
* something
*/
public static void httpGet(String url, HttpListener listener) {
new HttpStringAsyncTask(listener).execute(url);
}
/**
* http get asynchronous
* <ul>
* <li>It gets data or network asynchronous.</li>
* <li>If you want get data synchronous, use {@link HttpCache#httpGet(HttpRequest)} or
* {@link HttpCache#httpGetString(HttpRequest)}</li>
* </ul>
*
* @param request
* @param listener listener which can do something before or after HttpGet. this can be null if you not want to do
* something
*/
public static void httpGet(HttpRequest request, HttpListener listener) {
new HttpRequestAsyncTask(listener).execute(request);
}
/**
* http post
* <ul>
* <li>use gzip compression default</li>
* <li>use bufferedReader to improve the reading speed</li>
* </ul>
*
* @param httpUrl
* @param paras
* @return the response of the url, if null represents http error
*/
public static HttpResponse httpPost(HttpRequest request) {
if (request == null) {
return null;
}
BufferedReader input = null;
HttpURLConnection con = null;
try {
URL url = new URL(request.getUrl());
try {
HttpResponse response = new HttpResponse(request.getUrl());
// default gzip encode
con = (HttpURLConnection)url.openConnection();
setURLConnection(request, con);
con.setRequestMethod("POST");
con.setDoOutput(true);
String paras = request.getParas();
if (!StringUtils.isEmpty(paras)) {
con.getOutputStream().write(paras.getBytes());
}
input = new BufferedReader(new InputStreamReader(con.getInputStream()));
StringBuilder sb = new StringBuilder();
String s;
while ((s = input.readLine()) != null) {
sb.append(s).append("\n");
}
response.setResponseBody(sb.toString());
setHttpResponse(con, response);
return response;
} catch (IOException e) {
e.printStackTrace();
}
} catch (MalformedURLException e1) {
e1.printStackTrace();
} finally {
// close buffered
if (input != null) {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// disconnecting releases the resources held by a connection so they may be closed or reused
if (con != null) {
con.disconnect();
}
}
return null;
}
/**
* http post
*
* @param httpUrl
* @return the response of the url, if null represents http error
* @see cn.trinea.android.common.util.HttpUtils#httpPost(HttpRequest)
*/
public static HttpResponse httpPost(String httpUrl) {
return httpPost(new HttpRequest(httpUrl));
}
/**
* http post
*
* @param httpUrl
* @return the content of the url, if null represents http error
* @see cn.trinea.android.common.util.HttpUtils#httpPost(HttpRequest)
*/
public static String httpPostString(String httpUrl) {
HttpResponse response = httpPost(new HttpRequest(httpUrl));
return response == null ? null : response.getResponseBody();
}
/**
* http post
*
* @param httpUrl
* @param parasMap paras map, key is para name, value is para value. will be transfrom to String by
* {@link cn.trinea.android.common.util.HttpUtils#joinParas(java.util.Map)}
* @return the content of the url, if null represents http error
* @see cn.trinea.android.common.util.HttpUtils#httpPost(HttpRequest)
*/
public static String httpPostString(String httpUrl, Map<String, String> parasMap) {
HttpResponse response = httpPost(new HttpRequest(httpUrl, parasMap));
return response == null ? null : response.getResponseBody();
}
/**
* join url and paras
*
* <pre>
* getUrlWithParas(null, {(a, b)}) = "?a=b";
* getUrlWithParas("baidu.com", {}) = "baidu.com";
* getUrlWithParas("baidu.com", {(a, b), (i, j)}) = "baidu.com?a=b&i=j";
* getUrlWithParas("baidu.com", {(a, b), (i, j), (c, d)}) = "baidu.com?a=b&i=j&c=d";
* </pre>
*
* @param url url
* @param parasMap paras map, key is para name, value is para value
* @return if url is null, process it as empty string
*/
public static String getUrlWithParas(String url, Map<String, String> parasMap) {
StringBuilder urlWithParas = new StringBuilder(StringUtils.isEmpty(url) ? "" : url);
String paras = joinParas(parasMap);
if (!StringUtils.isEmpty(paras)) {
urlWithParas.append(URL_AND_PARA_SEPARATOR).append(paras);
}
return urlWithParas.toString();
}
/**
* join url and encoded paras
*
* @param url
* @param parasMap
* @return
* @see #getUrlWithParas(String, java.util.Map)
* @see StringUtils#utf8Encode(String)
*/
public static String getUrlWithValueEncodeParas(String url, Map<String, String> parasMap) {
StringBuilder urlWithParas = new StringBuilder(StringUtils.isEmpty(url) ? "" : url);
String paras = joinParasWithEncodedValue(parasMap);
if (!StringUtils.isEmpty(paras)) {
urlWithParas.append(URL_AND_PARA_SEPARATOR).append(paras);
}
return urlWithParas.toString();
}
/**
* join paras
*
* @param parasMap paras map, key is para name, value is para value
* @return join key and value with {@link #EQUAL_SIGN}, join keys with {@link #PARAMETERS_SEPARATOR}
*/
public static String joinParas(Map<String, String> parasMap) {
if (parasMap == null || parasMap.size() == 0) {
return null;
}
StringBuilder paras = new StringBuilder();
Iterator<Map.Entry<String, String>> ite = parasMap.entrySet().iterator();
while (ite.hasNext()) {
Map.Entry<String, String> entry = (Map.Entry<String, String>)ite.next();
paras.append(entry.getKey()).append(EQUAL_SIGN).append(entry.getValue());
if (ite.hasNext()) {
paras.append(PARAMETERS_SEPARATOR);
}
}
return paras.toString();
}
/**
* join paras with encoded value
*
* @param parasMap
* @return
* @see #joinParas(java.util.Map)
* @see StringUtils#utf8Encode(String)
*/
public static String joinParasWithEncodedValue(Map<String, String> parasMap) {
StringBuilder paras = new StringBuilder("");
if (parasMap != null && parasMap.size() > 0) {
Iterator<Map.Entry<String, String>> ite = parasMap.entrySet().iterator();
try {
while (ite.hasNext()) {
Map.Entry<String, String> entry = (Map.Entry<String, String>)ite.next();
paras.append(entry.getKey()).append(EQUAL_SIGN).append(StringUtils.utf8Encode(entry.getValue()));
if (ite.hasNext()) {
paras.append(PARAMETERS_SEPARATOR);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
return paras.toString();
}
/**
* append a key and value pair to url
*
* @param url
* @param paraKey
* @param paraValue
* @return
*/
public static String appendParaToUrl(String url, String paraKey, String paraValue) {
if (StringUtils.isEmpty(url)) {
return url;
}
StringBuilder sb = new StringBuilder(url);
if (!url.contains(URL_AND_PARA_SEPARATOR)) {
sb.append(URL_AND_PARA_SEPARATOR);
} else {
sb.append(PARAMETERS_SEPARATOR);
}
return sb.append(paraKey).append(EQUAL_SIGN).append(paraValue).toString();
}
private static final SimpleDateFormat GMT_FORMAT = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z",
Locale.ENGLISH);
/**
* parse gmt time to long
*
* @param gmtTime likes Thu, 11 Apr 2013 10:20:30 GMT
* @return -1 represents exception otherwise time in milliseconds
*/
public static long parseGmtTime(String gmtTime) {
try {
return GMT_FORMAT.parse(gmtTime).getTime();
} catch (Exception e) {
e.printStackTrace();
}
return -1;
}
/**
* set HttpRequest to HttpURLConnection
*
* @param request source request
* @param urlConnection destin url connection
*/
private static void setURLConnection(HttpRequest request, HttpURLConnection urlConnection) {
if (request == null || urlConnection == null) {
return;
}
setURLConnection(request.getRequestProperties(), urlConnection);
if (request.getConnectTimeout() >= 0) {
urlConnection.setConnectTimeout(request.getConnectTimeout());
}
if (request.getReadTimeout() >= 0) {
urlConnection.setReadTimeout(request.getReadTimeout());
}
}
/**
* set HttpURLConnection property
*
* @param requestProperties
* @param urlConnection
*/
public static void setURLConnection(Map<String, String> requestProperties, HttpURLConnection urlConnection) {
if (MapUtils.isEmpty(requestProperties) || urlConnection == null) {
return;
}
for (Map.Entry<String, String> entry : requestProperties.entrySet()) {
if (!StringUtils.isEmpty(entry.getKey())) {
urlConnection.setRequestProperty(entry.getKey(), entry.getValue());
}
}
}
/**
* set HttpURLConnection to HttpResponse
*
* @param urlConnection source url connection
* @param response destin response
*/
private static void setHttpResponse(HttpURLConnection urlConnection, HttpResponse response) {
if (response == null || urlConnection == null) {
return;
}
try {
response.setResponseCode(urlConnection.getResponseCode());
} catch (IOException e) {
response.setResponseCode(-1);
}
response.setResponseHeader(HttpConstants.EXPIRES, urlConnection.getHeaderField("Expires"));
response.setResponseHeader(HttpConstants.CACHE_CONTROL, urlConnection.getHeaderField("Cache-Control"));
}
/**
* AsyncTask to get data by String url
*
* @author <a href="http://www.trinea.cn" target="_blank">Trinea</a> 2013-11-15
*/
private static class HttpStringAsyncTask extends AsyncTask<String, Void, HttpResponse> {
private HttpListener listener;
public HttpStringAsyncTask(HttpListener listener) {
this.listener = listener;
}
protected HttpResponse doInBackground(String... url) {
if (ArrayUtils.isEmpty(url)) {
return null;
}
return httpGet(url[0]);
}
protected void onPreExecute() {
if (listener != null) {
listener.onPreGet();
}
}
protected void onPostExecute(HttpResponse httpResponse) {
if (listener != null) {
listener.onPostGet(httpResponse);
}
}
}
/**
* AsyncTask to get data by HttpRequest
*
* @author <a href="http://www.trinea.cn" target="_blank">Trinea</a> 2013-11-15
*/
private static class HttpRequestAsyncTask extends AsyncTask<HttpRequest, Void, HttpResponse> {
private HttpListener listener;
public HttpRequestAsyncTask(HttpListener listener) {
this.listener = listener;
}
protected HttpResponse doInBackground(HttpRequest... httpRequest) {
if (ArrayUtils.isEmpty(httpRequest)) {
return null;
}
return httpGet(httpRequest[0]);
}
protected void onPreExecute() {
if (listener != null) {
listener.onPreGet();
}
}
protected void onPostExecute(HttpResponse httpResponse) {
if (listener != null) {
listener.onPostGet(httpResponse);
}
}
}
/**
* HttpListener, can do something before or after HttpGet
*
* @author <a href="http://www.trinea.cn" target="_blank">Trinea</a> 2013-11-15
*/
public static abstract class HttpListener {
/**
* Runs on the UI thread before httpGet.<br/>
* <ul>
* <li>this can be null if you not want to do something</li>
* </ul>
*/
protected void onPreGet() {}
/**
* Runs on the UI thread after httpGet. The httpResponse is returned by httpGet.
* <ul>
* <li>this can be null if you not want to do something</li>
* </ul>
*
* @param httpResponse get by the url
*/
protected void onPostGet(HttpResponse httpResponse) {}
}
}