微信支付开发教程JAVA编[004]-使用HttpClient详解

        需要注意的是,HttpClient并不是基本的java库(android下就有).
http://hc.apache.org/downloads.cgi
我下载的是
http://mirrors.tuna.tsinghua.edu.cn/apache/httpcomponents/httpclient/binary/httpcomponents-client-4.5.3-bin.zip
下载后,会有很多jar,大家可以酌情添加到工程,我就只添加了commons-codec-1.9.jar,commons-logging-1.2.jar,httpmime-4.5.3.jar,httpcore-4.4.6.jar,httpclient-4.5.3.jar

        HttpClient网上例子比较多,我直接附上调试好了的代码:

 

/***************************************************************
 * http,https访问的站点
 ***************************************************************/
package wxlib.wxsdk.lib.utils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.Map;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
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.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.json.JSONObject;

public class HttpRequest {
	/**
	 * @tutorial 支持http,https
	 * @param string $url 要访问的站点
	 * @param array,object $data get只能是key/value的参数集合
	 * @param int $timeout 超时时间,单位秒
	 * @return 站点数据或失败信息
	 */
	static public Object get(String url, Object data/* = null*/, int timeout/* = 30*/) {
		//将data转化为url参数:par1=val1&par2=va2&par3=val3
		String param = "";
		if(data != null && !data.equals("") && data instanceof Map) {
			@SuppressWarnings("unchecked")
			Map map = (Map)data;
			for(Map.Entry entry : map.entrySet()) {
				String key = entry.getKey() != null ? entry.getKey().toString() : "";
				String val = entry.getValue() != null ? entry.getValue().toString() : "";
				if(key.equals(""))
					continue;
				param += key + "=" + val + "&";
			}
		}
		if(data != null && !data.equals("") && data instanceof JSONObject) {
			JSONObject map = (JSONObject)data;
			for(String key : map.keySet()) {
				if(key == null || key.equals(""))
					continue;
				String val = map.optString(key);
				if(val == null)
					continue;
				param += key + "=" + val + "&";
			}
		}
		if(param.endsWith("&"))
			param = param.substring(0, param.length() - 1);
		if(!param.equals(""))
			url += ((url.indexOf("?") != -1) ? "&" : "?") + param;

		String result = "";

		//创建http请求(post方式)
		HttpGet httpGet = new HttpGet(url);
		httpGet.addHeader("Content-Type", "text/html; charset=UTF-8");
		//得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别
		//StringEntity stringEntity = new StringEntity(data.toString(), "UTF-8");
		//httpGet.setEntity(stringEntity);

		//设置请求器配置:如超时限制等
		RequestConfig config = RequestConfig.custom().setSocketTimeout(timeout * 1000).setConnectTimeout(timeout * 1000).build();
		httpGet.setConfig(config);

		//提交post访问请求并获得返回值
		//System.out.println("request: " + httpPost.getRequestLine());
		try {
			CloseableHttpClient httpClient = HttpClients.createDefault();
			CloseableHttpResponse response = httpClient.execute(httpGet); //throw
			HttpEntity httpEntity = response.getEntity();
			//System.out.println("response status: " + response.getStatusLine());
			result = EntityUtils.toString(httpEntity, "UTF-8"); //throw
			//System.out.println("result: " + result);
			try {
				response.close(); //throw
			}
			catch(Exception e) {
			}
			httpClient.close(); //throw
		}
		catch(Exception e) {
		}
		//httpGet.abort();

		return result;
	}

	/**
	 * @tutorial 支持http,https
	 * @param string $url 要访问的站点
	 * @param  mixed $data post可以是任意类型的数据,例如string,array,object,json等
	 * @param int $timeout 超时时间,单位秒
	 * @return 站点数据或失败信息
	 */
	static public Object post(String url, Object data, int timeout/* = 30*/) {
		String result = "";

		//创建http请求(post方式)
		HttpPost httpPost = new HttpPost(url);
		httpPost.addHeader("Content-Type", "text/html; charset=UTF-8");
		//得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别
		if(data != null && data instanceof String) { //支持上传字符串,如text,xml,json
			StringEntity stringEntity = new StringEntity(data.toString(), "UTF-8");
			httpPost.setEntity(stringEntity);
		}
		else if(data != null && data instanceof byte[]) { //支持上传原始数据,如文件
			ByteArrayEntity byteArrayEntity = new ByteArrayEntity((byte[])data);
			httpPost.setEntity(byteArrayEntity);
		}

		//设置请求器配置:如超时限制等
		RequestConfig config = RequestConfig.custom().setSocketTimeout(timeout * 1000).setConnectTimeout(timeout * 1000).build();
		httpPost.setConfig(config);

		//提交post访问请求并获得返回值
		//System.out.println("request: " + httpPost.getRequestLine());
		try {
			CloseableHttpClient httpClient = HttpClients.createDefault();
			CloseableHttpResponse response = httpClient.execute(httpPost); //throw
			HttpEntity httpEntity = response.getEntity();
			//System.out.println("response status: " + response.getStatusLine());
			result = EntityUtils.toString(httpEntity, "UTF-8"); //throw
			//System.out.println("result: " + result);
			try {
				response.close(); //throw
			}
			catch(Exception e) {
			}
			httpClient.close(); //throw
		}
		catch(Exception e) {
		}
		//httpPost.abort();

		return result;
	}

	/**
	 * @tutorial 支持http,https
	 * @param string $url 要访问的站点
	 * @param string $field 文件域.微信公众号一般为"media"
	 * @param string $file 要上传的文件名.可以是相对路径或绝对路径
	 * @param array $extra 额外要上传的字段.类型为key/value数组.数组元素中key为string类型,value可以是mixed类型.
	 * 例如:在上传视频素材时需要POST另一个表单,id为description,包含素材的描述信息,内容格式为JSON字符串.
	 * array('merchant' => '微微花语商城', 'description' =>'{"title": "猜灯谜抢红包活动", "introduction": "感谢您参加猜灯谜活动,祝您节日快乐"}'
	 * 调用方式为:
	 * ****$ curl -F [email protected] -F merchant='微微花语商城' -F description='{"title": "猜灯谜抢红包活动", "introduction": "感谢您参加猜灯谜活动,祝您节日快乐"}' "http://localhost/weixin/server.php"
	 * 对应表单为:
	 * 
* * * *
* @param int $timeout 超时时间,单位秒 * @return 站点数据或失败信息 * @see * ****以下2者的调用方式,效果是一样的: * ****curl_http_upload("http://localhost/weixin/server.php", "media", "a.jpg", null, 30); * ****$ curl -F "[email protected]" "http://localhost/weixin/server.php" * ****后台得到的$_FILES应该为: * ****array("media" => array("name" => "a.jpg", "type" => "image/jpeg", "tmp_name" => "C:\wamp\tmp\php9CC4.tmp", "error" => 0, "size" => 46192)); * @category * ****注:和php版比较,这里稍微美中不足的是,后台得到的mimetype不是真正的类型: * ****array("media" => array("name" => "a.jpg", "type" => "application/octet-stream", "tmp_name" => "C:\wamp\tmp\php9CC4.tmp", "error" => 0, "size" => 46192)); */ static public Object upload(String url, String field, String file, Object extra/* = null*/, int timeout/* = 30*/) { String result = ""; //创建http请求(post方式) HttpPost httpPost = new HttpPost(url); /*********************************************************************** //httpPost.setHeader("Content-Type", "multipart/form-data; charset=UTF-8"); //builder.setCharset(Charset.forName(HTTP.UTF_8)); //设置请求的编码格式 //builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);//设置浏览器兼容模式 上面高亮的两个地方就是在微信素材上传时的两个大坑. 1.当遇到乱码时,第一错觉就是设置请求的编码格式,恰恰在微信上传时,如果设置这个编码,就会导致多媒体文件丢失,上传不成功.(具体原因不明) 2.设置浏览器兼容模式,这个好多文章说,设置成BOWSER_COMPATIBLE就不会乱码了,问题就出现在这里,设置模式时,应该设置成HttpMultipartMode.RFC6532,这样才是真正的不会出现乱码. 3.不要设置编码,模式设置要注意. 详见<>: http://blog.csdn.net/kookob/article/details/46914777 ***********************************************************************/ //httpPost.addHeader("Content-Type", "multipart/form-data; charset=UTF-8"); //"text/html; charset=UTF-8" //"multipart/form-data; charset=UTF-8" //ContentType.MULTIPART_FORM_DATA.toString() //得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别 //StringEntity stringEntity = new StringEntity(data.toString(), "UTF-8"); //httpPost.setEntity(stringEntity); //添加表单项 MultipartEntityBuilder builder = MultipartEntityBuilder.create().setMode(HttpMultipartMode.RFC6532); //BROWSER_COMPATIBLE自定义charset,RFC6532=utf-8,STRICT=iso-8859-1 //$filename = realpath($file); //>>??这两个功能后期要加上 //$mimetype = mime_content_type($filename); //如果不手动设置$mimetype,curl会默认为"application/octet-stream" builder.addBinaryBody(field, new File(file)); //builder.addPart(field, new FileBody(new File(file))); if(extra != null && !extra.equals("") && extra instanceof Map) { @SuppressWarnings("unchecked") Map map = (Map)extra; for(Map.Entry entry : map.entrySet()) { String key = entry.getKey() != null ? entry.getKey().toString() : ""; String val = entry.getValue() != null ? entry.getValue().toString() : ""; if(key.equals("")) continue; //param += key + "=" + val + "&"; builder.addTextBody(key, val, ContentType.create("text/plain", "UTF-8")); } } if(extra != null && !extra.equals("") && extra instanceof JSONObject) { JSONObject map = (JSONObject)extra; for(String key : map.keySet()) { if(key == null || key.equals("")) continue; String val = map.optString(key); if(val == null) continue; //param += key + "=" + val + "&"; builder.addTextBody(key, val, ContentType.create("text/plain", "UTF-8")); } } httpPost.setEntity(builder.build()); //设置请求器配置:如超时限制等 RequestConfig config = RequestConfig.custom().setSocketTimeout(timeout * 1000).setConnectTimeout(timeout * 1000).build(); httpPost.setConfig(config); //提交post访问请求并获得返回值 //System.out.println("request: " + httpPost.getRequestLine()); try { CloseableHttpClient httpClient = HttpClients.createDefault(); CloseableHttpResponse response = httpClient.execute(httpPost); //throw HttpEntity httpEntity = response.getEntity(); //System.out.println("response status: " + response.getStatusLine()); result = EntityUtils.toString(httpEntity, "UTF-8"); //throw //System.out.println("result: " + result); try { response.close(); //throw } catch(Exception e) { } httpClient.close(); //throw } catch(Exception e) { e.printStackTrace(); } //httpPost.abort(); return result; } /** * @tutorial 支持http,https * @param string $url 要访问的站点 * @param string $file 保存到本地的文件名,如果需要的话 * @param int $timeout 超时时间,单位秒 * @return 站点数据或失败信息.对于下载来说,成功时的站点数据即为文件的二进制内容. * 对于java版来说,是原始的数据byte[]类型. * 可以直接输出到文件:fs.write(result); * 如果解析成字符串的话,需指定服务器传送过来的编码:new String(result, "ISO-8859-1");new String(result, "UTF-8"); * @see * ****成功返回时: * ****1).如果提供了$file参数,则文件会直接保存到本地; * ****2).同时,将文件的二进制内容作为返回值,可灵活用于缩放,旋转,渲染,保存等. */ static public Object download(String url, String file, int timeout/* = 30*/) { byte[] result = null; //创建http请求(post方式) HttpGet httpGet = new HttpGet(url); httpGet.addHeader("Content-Type", "text/html; charset=UTF-8"); //得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别 //StringEntity stringEntity = new StringEntity(data.toString(), "UTF-8"); //httpGet.setEntity(stringEntity); //设置请求器配置:如超时限制等 RequestConfig config = RequestConfig.custom().setSocketTimeout(timeout * 1000).setConnectTimeout(timeout * 1000).build(); httpGet.setConfig(config); //提交post访问请求并获得返回值 //System.out.println("request: " + httpPost.getRequestLine()); try { CloseableHttpClient httpClient = HttpClients.createDefault(); CloseableHttpResponse response = httpClient.execute(httpGet); //throw HttpEntity httpEntity = response.getEntity(); //System.out.println("response status: " + response.getStatusLine()); //result = EntityUtils.toString(httpEntity, "UTF-8"); //throw result = EntityUtils.toByteArray(httpEntity); //throw //System.out.println("result: " + result); try { response.close(); //throw } catch(Exception e) { } httpClient.close(); //throw } catch(Exception e) { } //httpGet.abort(); if(result != null && result.length > 0 && file != null && !file.equals("")) { try { OutputStream fs = new FileOutputStream(file); fs.write(result); fs.close(); } catch(Exception e) { } } return result; } }


        着重说明的是,微信公众号上传素材时,不需要设置Content-Type头,这一点很重要,我就调试了很久,才在一个大神文章里找到问题关键.详见<>: http://blog.csdn.net/kookob/article/details/46914777

 

 

你可能感兴趣的:(微信支付开发教程JAVA编[004]-使用HttpClient详解)