下午对公司中http请求的代码进行了重构,之前的每个请求都需要写一个post方法,不相同的只是请求的参数.而且代码中有很多累赘的代码,比如每次请求都需要重新new一个DefaultHttpClient,在finally中每次都需要shutdown一下.之前看过的一本重构书籍中也提到了对于这样的代码存在的臭味.所以下午就对之前的代码进行了重构并根据apache httpclient官网重新写了一个单例的DefaultHttpClient类.单例类如下:
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.util.EntityUtils;
/**
* 保证HttpClient的单例使用
*
* @author Administrator
*
*/
public class SingletonClient {
private static final String CHARSET = "UTF-8";
private static HttpClient singleHttpClient;
private SingletonClient() {
}
public static synchronized HttpClient getHttpClient() {
if (null == singleHttpClient) {
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, CHARSET);
HttpProtocolParams.setUseExpectContinue(params, true);
HttpProtocolParams
.setUserAgent(
params,
"Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 GTB6 (.NET CLR 3.5.30729)");
/* 连接超时 */
HttpConnectionParams.setConnectionTimeout(params, 2000);
/* 请求超时 */
HttpConnectionParams.setSoTimeout(params, 4000);
// 设置HttpClient支持的请求模式
SchemeRegistry schReg = new SchemeRegistry();
schReg.register(new Scheme("http", 80, PlainSocketFactory
.getSocketFactory()));
schReg.register(new Scheme("https", 443, SSLSocketFactory
.getSocketFactory()));
// 在最新版本的httpclient中ThreadSafeClientConnManager已被@Deprecated掉,这里使用PoolingClientConnectionManager。
ClientConnectionManager conMgr = new PoolingClientConnectionManager(
schReg);
singleHttpClient = new DefaultHttpClient(conMgr, params);
}
return singleHttpClient;
}
static class TestThread extends Thread {
@Override
public void run() {
try {
System.out.println(getHttpClient());
HttpResponse response = getHttpClient().execute(
new HttpGet("http://www.baidu.com"));
HttpEntity entity = response.getEntity();
if (entity != null) {
String x = EntityUtils.toString(entity);
System.out.println(x.substring(200, 230));
// 保证连接能释放回管理器
EntityUtils.consume(entity);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
for (int i = 0; i < 30; i++) {
try {
Thread.sleep(2000);
new TestThread().start();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
多个线程测试后可以看到得到的DefaultHttpClient的字节码是一样的.所以这样可以保证在整个应用当中我们的DefaultHttpClient只存在一个.
下面的代码是对请求重构后的代码:
@SuppressWarnings("unchecked")
public static Object post(String url, Object object) {
Object o = null;
if (url == null || url.length() <= 0)
throw new ServiceException("Url can not be null.");
url = BASE_URL + url;
String temp = url.toLowerCase();
if (!temp.startsWith("http://") && !temp.startsWith("https://"))
url = "http://" + url;
url = URI.create(url).toASCIIString();
DefaultHttpClient httpClient = (DefaultHttpClient) SingletonClient.getHttpClient();
try {
HttpPost httpMethod = new HttpPost(url);
httpMethod.setHeader("key", "********");
if (object instanceof Map) {
InputStreamEntity reqEntity = new InputStreamEntity(Streams
.wrap(Json.toJson(object).getBytes("UTF-8")), -1);
reqEntity.setContentType("binary/octet-stream");
reqEntity.setChunked(true);
reqEntity.setContentEncoding("UTF-8");
httpMethod.setEntity(reqEntity);
} else if (String.class.isAssignableFrom(object.getClass())) {
httpMethod.setEntity(new StringEntity(Json.toJson(object
.toString())));
} else {
throw new ServiceException("illegal request arguments");
}
HttpResponse response = httpClient.execute(httpMethod);
int status=response.getStatusLine().getStatusCode();
if (status != org.apache.http.HttpStatus.SC_OK) {
LOG.warn("Http Satus:" + status + ",Url:" + url);
if (status >= 500 && status < 600)
throw new IOException("Remote service<" + url
+ "> respose a error, status:" + status);
return null;
}
HttpEntity entity = response.getEntity();
o = EntityUtils.toString(entity);
EntityUtils.consume(entity);
} catch (Exception e) {
throw new ServiceException("error!");
} finally {
//httpClient.getConnectionManager().shutdown();
}
return o;
}
上面的代码中json解析采用的是Nutz框架中的Json类(性能不亚于google的Gson).这段代码现在只支持Map,String类型参数的请求,以后如有需求还会进行重构.暂时是可以应对需求的.我们现在只需要传过去对象或者字符串在另一个项目中进行数据库查找验证.在这个项目中只需要获取请求是否成功即可