轻松把玩HttpClient之封装HttpClient工具类,封装输入参数,简化工具类

Posted 龙轩

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了轻松把玩HttpClient之封装HttpClient工具类,封装输入参数,简化工具类相关的知识,希望对你有一定的参考价值。

       在写这个工具类的时候发现传入的参数太多,以至于方法泛滥,只一个send方法就有30多个,所以对工具类进行了优化,把输入参数封装在一个对象里,这样以后再扩展输入参数,直接修改这个类就ok了。


       不多说了,先上代码:

/** 
 * 请求配置类
 * 
 * @author arron
 * @date 2016年2月2日 下午3:14:32 
 * @version 1.0 
 */
public class HttpConfig {
	
	private HttpConfig(){};
	
	/**
	 * 获取实例
	 * @return
	 */
	public static HttpConfig custom(){
		return new HttpConfig();
	}

	/**
	 * HttpClient对象
	 */
	private HttpClient client;

	/**
	 * CloseableHttpAsyncClient对象
	 */
	private CloseableHttpAsyncClient asynclient;
	
	/**
	 * 资源url
	 */
	private String url;

	/**
	 * Header头信息
	 */
	private Header[] headers;

	/**
	 * 请求方法
	 */
	private HttpMethods method=HttpMethods.GET;
	
	/**
	 * 请求方法名称
	 */
	private String methodName;

	/**
	 * 用于cookie操作
	 */
	private HttpContext context;

	/**
	 * 传递参数
	 */
	private Map<String, Object> map;

	/**
	 * 输入输出编码
	 */
	private String encoding=Charset.defaultCharset().displayName();

	/**
	 * 输入编码
	 */
	private String inenc;

	/**
	 * 输出编码
	 */
	private String outenc;
	
	/**
	 * 输出流对象
	 */
	private OutputStream out;
	
	/**
	 * 异步操作回调执行器
	 */
	private IHandler handler;

	/**
	 * HttpClient对象
	 */
	public HttpConfig client(HttpClient client) {
		this.client = client;
		return this;
	}
	
	/**
	 * CloseableHttpAsyncClient对象
	 */
	public HttpConfig asynclient(CloseableHttpAsyncClient asynclient) {
		this.asynclient = asynclient;
		return this;
	}
	
	/**
	 * 资源url
	 */
	public HttpConfig url(String url) {
		this.url = url;
		return this;
	}
	
	/**
	 * Header头信息
	 */
	public HttpConfig headers(Header[] headers) {
		this.headers = headers;
		return this;
	}
	
	/**
	 * 请求方法
	 */
	public HttpConfig method(HttpMethods method) {
		this.method = method;
		return this;
	}
	
	/**
	 * 请求方法
	 */
	public HttpConfig methodName(String methodName) {
		this.methodName = methodName;
		return this;
	}
	
	/**
	 * cookie操作相关
	 */
	public HttpConfig context(HttpContext context) {
		this.context = context;
		return this;
	}
	
	/**
	 * 传递参数
	 */
	public HttpConfig map(Map<String, Object> map) {
		this.map = map;
		return this;
	}
	
	/**
	 * 输入输出编码
	 */
	public HttpConfig encoding(String encoding) {
		//设置输入输出
		inenc(encoding);
		outenc(encoding);
		this.encoding = encoding;
		return this;
	}
	
	/**
	 * 输入编码
	 */
	public HttpConfig inenc(String inenc) {
		this.inenc = inenc;
		return this;
	}
	
	/**
	 * 输出编码
	 */
	public HttpConfig outenc(String outenc) {
		this.outenc = outenc;
		return this;
	}
	
	/**
	 * 输出流对象
	 */
	public HttpConfig out(OutputStream out) {
		this.out = out;
		return this;
	}
	
	/**
	 * 异步操作回调执行器
	 */
	public HttpConfig handler(IHandler handler) {
		this.handler = handler;
		return this;
	}


	public HttpClient client() {
		return client;
	}
	
	public CloseableHttpAsyncClient asynclient() {
		return asynclient;
	}
	
	public Header[] headers() {
		return headers;
	}
	
	public String url() {
		return url;
	}

	public HttpMethods method() {
		return method;
	}

	public String methodName() {
		return methodName;
	}

	public HttpContext context() {
		return context;
	}

	public Map<String, Object> map() {
		return map;
	}

	public String encoding() {
		return encoding;
	}

	public String inenc() {
		return inenc == null ? encoding : inenc;
	}

	public String outenc() {
		return outenc == null ? encoding : outenc;
	}
	
	public OutputStream out() {
		return out;
	}
	
	public IHandler handler() {
		return handler;
	}
}
       将构造方法设置为private,然后提供一个custom()方法来获取新的实例,所有的set方法,都是返回HttpConfig,这样就支持链式调用(创建者模式)了。

       工具类的核心方法如下:

	/**
	 * 请求资源或服务
	 * 
	 * @param config
	 * @return
	 * @throws HttpProcessException
	 */
	public static String send(HttpConfig config) throws HttpProcessException {
		return fmt2String(execute(config), config.outenc());
	}
	
	/**
	 * 请求资源或服务
	 * 
	 * @param client				client对象
	 * @param url					资源地址
	 * @param httpMethod	请求方法
	 * @param parasMap		请求参数
	 * @param headers			请求头信息
	 * @param encoding		编码
	 * @return						返回处理结果
	 * @throws HttpProcessException 
	 */
	private static HttpResponse execute(HttpConfig config) throws HttpProcessException {
		if(config.client()==null){//检测是否设置了client
			config.client(create(config.url()));
		}
		HttpResponse resp = null;
		try {
			//创建请求对象
			HttpRequestBase request = getRequest(config.url(), config.method());
			
			//设置header信息
			request.setHeaders(config.headers());
			
			//判断是否支持设置entity(仅HttpPost、HttpPut、HttpPatch支持)
			if(HttpEntityEnclosingRequestBase.class.isAssignableFrom(request.getClass())){
				List<NameValuePair> nvps = new ArrayList<NameValuePair>();
				
				//检测url中是否存在参数
				config.url(Utils.checkHasParas(config.url(), nvps, config.inenc()));
				
				//装填参数
				HttpEntity entity = Utils.map2List(nvps, config.map(), config.inenc());
				
				//设置参数到请求对象中
				((HttpEntityEnclosingRequestBase)request).setEntity(entity);
				
				logger.info("请求地址:"+config.url());
				if(nvps.size()>0){
					logger.info("请求参数:"+nvps.toString());
				}
			}else{
				int idx = config.url().indexOf("?");
				logger.info("请求地址:"+config.url().substring(0, (idx>0 ? idx : config.url().length())));
				if(idx>0){
					logger.info("请求参数:"+config.url().substring(idx+1));
				}
			}
			//执行请求操作,并拿到结果(同步阻塞)
			resp = (config.context()==null)?config.client().execute(request) : config.client().execute(request, config.context()) ;
			
			//获取结果实体
			return resp;
			
		} catch (IOException e) {
			throw new HttpProcessException(e);
		}
	}
	
	//-----------华----丽----分----割----线--------------
	//-----------华----丽----分----割----线--------------
	//-----------华----丽----分----割----线--------------
	
	/**
	 * 转化为字符串
	 * 
	 * @param entity			实体
	 * @param encoding	编码
	 * @return
	 * @throws HttpProcessException 
	 */
	public static String fmt2String(HttpResponse resp, String encoding) throws HttpProcessException {
		String body = "";
		try {
			if (resp.getEntity() != null) {
				// 按指定编码转换结果实体为String类型
				body = EntityUtils.toString(resp.getEntity(), encoding);
				logger.debug(body);
			}
			EntityUtils.consume(resp.getEntity());
		} catch (ParseException | IOException e) {
			throw new HttpProcessException(e);
		}finally{
			close(resp);
		}
		return body;
	}
	
	/**
	 * 转化为流
	 * 
	 * @param entity			实体
	 * @param out				输出流
	 * @return
	 * @throws HttpProcessException 
	 */
	public static OutputStream fmt2Stream(HttpResponse resp, OutputStream out) throws HttpProcessException {
		try {
			resp.getEntity().writeTo(out);
			EntityUtils.consume(resp.getEntity());
		} catch (ParseException | IOException e) {
			throw new HttpProcessException(e);
		}finally{
			close(resp);
		}
		return out;
	}

       再附上测试代码:

	public static void testOne() throws HttpProcessException{
		
		System.out.println("--------简单方式调用(默认post)--------");
		String url = "http://tool.oschina.net/";
		HttpConfig  config = HttpConfig.custom();
		//简单调用
		String resp = HttpClientUtil.get(config.url(url));

		System.out.println("请求结果内容长度:"+ resp.length());
		
		System.out.println("\\n#################################\\n");
		
		System.out.println("--------加入header设置--------");
		url="http://blog.csdn.net/xiaoxian8023";
		//设置header信息
		Header[] headers=HttpHeader.custom().userAgent("Mozilla/5.0").build();
		//执行请求
		resp = HttpClientUtil.get(config.headers(headers));
		System.out.println("请求结果内容长度:"+ resp.length());

		System.out.println("\\n#################################\\n");
		
		System.out.println("--------代理设置(绕过证书验证)-------");
		url="https://www.facebook.com/";
		HttpClient client= HCB.custom().timeout(10000).proxy("127.0.0.1", 8087).ssl().build();//采用默认方式(绕过证书验证)
		//执行请求
		resp = HttpClientUtil.get(config.client(client));
		System.out.println("请求结果内容长度:"+ resp.length());

		System.out.println("\\n#################################\\n");

//		System.out.println("--------代理设置(自签名证书验证)+header+get方式-------");
//		url = "https://sso.tgb.com:8443/cas/login";
//		client= HCB.custom().timeout(10000).ssl("D:\\\\keys\\\\wsriakey","tomcat").build();
//		headers=HttpHeader.custom().keepAlive("false").connection("close").contentType(Headers.APP_FORM_URLENCODED).build();
//		//执行请求
//		resp = CopyOfHttpClientUtil.get(config.method(HttpMethods.GET));
//		System.out.println("请求结果内容长度:"+ resp.length());
		try {
			System.out.println("--------下载测试-------");
			url="http://ss.bdimg.com/static/superman/img/logo/logo_white_fe6da1ec.png";
			FileOutputStream out = new FileOutputStream(new File("d://aaa//000.png"));
			HttpClientUtil.down(HttpConfig.custom().url(url).out(out));
			out.flush();
			out.close();
			System.out.println("--------下载测试+代理-------");
			
			out = new FileOutputStream(new File("d://aaa//001.png"));
			HttpClientUtil.down(HttpConfig.custom().client(client).url(url).out(out));
			out.flush();
			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

		System.out.println("\\n#################################\\n");
	}

       可以看到这样调用会更显得清晰明了。以后再添加功能时,改起来也会比较方便了。工具类也提供了输出流的功能,可以用于下载文件或者加载验证码图片,非常方便。


       最新的完整代码请到GitHub上进行下载:https://github.com/Arronlong/httpclientUtil 。


       httpclientUtil (QQ交流群:548452686 httpclientUtil交流

以上是关于轻松把玩HttpClient之封装HttpClient工具类,封装输入参数,简化工具类的主要内容,如果未能解决你的问题,请参考以下文章

轻松把玩HttpClient之封装HttpClient工具类,封装输入参数,简化工具类

轻松把玩HttpClient之封装HttpClient工具类,插件式配置Header

轻松把玩HttpClient之封装HttpClient工具类,携带Cookie的请求

轻松把玩HttpClient之封装HttpClient工具类,单线程调用及多线程批量调用测试

轻松把玩HttpClient之封装HttpClient工具类,新增验证码识别功能

轻松把玩HttpClient之封装HttpClient工具类,优化启用Http连接池策略