在写这个工具类的时候发现传入的参数太多,以至于方法泛滥,只一个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 。