最近学习向第三方接口发出http请求,获取返回数据进行存储,把内容总结一下。
查了一些资料,总共有这么几种方法发出http请求:
第一个java的net提供的HttpURLConnection功能相较而言较少;HttpClient 是实现客户端与服务器通信的实现库,一般步骤是首先新建一个httpclient对象,并进行初始设置,然后设置get、post方法对象,设置请求参数,之后执行get、post方法获取response响应结果,最后处理结果释放连接;CloseableHttpClient进行了优化,能够自动关闭连接,默认会创建一个大小为5的连接池;RestTemplate功能更广泛,程序也不复杂。因为是小程序,所以选了使用CloseableHttpClient,用不着SpringBoot。
新建maven工程,在pom.xml中导入httpclient与fastjson包,httpclient用来请求,fastjson进行参数转换与处理数据。
get方法:利用 HttpClientBuilder创建连接对象
public static String getMethod(String url){
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
HttpGet get = new HttpGet(url);
try{
//这里可以设置请求参数,token等
get.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36");
HttpResponse response = httpClient.execute(get);//执行获取响应
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK){//根据状态码处理
//返回字符串
String res = EntityUtils.toString(response.getEntity());
return res;
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
post方法:
public static String postMethod(String url, JSONObject json){
try {
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
HttpPost post = new HttpPost(url);
post.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36");
StringEntity s = new StringEntity(json.toString());
s.setContentEncoding("UTF-8");
//发送json数据需要设置contentType
s.setContentType("application/x-www-form-urlencoded");
post.setEntity(s); //设置请求参数
HttpResponse response = httpClient.execute(post);
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
//返回String
String res = EntityUtils.toString(response.getEntity());
return res;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
获取token等可以根据需要编写
获得的响应参数可以使用json‘进行分析,[ ]为数组,{ }为对象,利用 JSONObject.parseObject(String text)将字符串转为json对象,调用getJSONArray(key)获取json数组JSONArray,getString(key)获取对应的值,getJSONObject()获取json对象。可以根据json结构层层解析,获取需要的数据。
新建json对象,调用put方法可以赋值,之后作为请求参数设置。
发出请求链接可能出现数字证书无效,PKIX path building failed、unable to find valid certification path to requested target
可以在代码中创建忽略证书验证的CloseableHttpClient
public CloseableHttpClient getIgnoeSSLClient() throws Exception {
SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, new TrustStrategy() {
@Override
public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
return true;
}
}).build();
//创建httpClient
CloseableHttpClient client = HttpClients.custom().setSSLContext(sslContext).
setSSLHostnameVerifier(new NoopHostnameVerifier()).build();
return client;
}
由于http请求需要token验证,调用不同接口需要将token放入请求参数,token有一定时限,为了避免不停获取token,可以将其放入缓存中,减少交互提高效率。利用并发的ConcurrentHashMap实现。
object对象存token,需要用token时从缓存中找,若是过期或者为null则获取token放入缓存
//预缓存信息
private static final Map CACHE_MAP = new ConcurrentHashMap();
//每个缓存生效时间10小时
public static final long CACHE_HOLD_TIME_24H = 24 * 60 * 60 * 1000L;
/**
* 存放一个缓存对象,默认保存时间24小时
* @param cacheName
* @param obj
*/
/*public static void put(String cacheName, Object obj) {
put(cacheName, obj, CACHE_HOLD_TIME_24H);
}*/
/**
* 存放一个缓存对象,保存时间为holdTime
* @param cacheName
* @param obj
* @param holdTime
*/
public static void put(String cacheName, Object obj, long holdTime) {
CACHE_MAP.put(cacheName, obj);
CACHE_MAP.put(cacheName + "_HoldTime", System.currentTimeMillis() + holdTime);//缓存失效时间
}
/**
* 检查缓存对象是否存在,
* 若不存在,则返回false
* 若存在,检查其是否已过有效期,如果已经过了则删除该缓存并返回false
* @param cacheName
* @return
*/
public static boolean checkCacheName(String cacheName) {
Long cacheHoldTime = (Long) CACHE_MAP.get(cacheName + "_HoldTime");
if (cacheHoldTime == null || cacheHoldTime == 0L) {
return false;
}
if (cacheHoldTime < System.currentTimeMillis()) {
remove(cacheName);
return false;
}
return true;
}
/**
* 删除所有缓存
*/
/*public static void removeAll() {
CACHE_MAP.clear();
}*/
/**
* 删除某个缓存
* @param cacheName
*/
public static void remove(String cacheName) {
CACHE_MAP.remove(cacheName);
CACHE_MAP.remove(cacheName + "_HoldTime");
}
/**
* 取出一个缓存对象
* @param cacheName
* @return
*/
public static Object get(String cacheName) {
if (checkCacheName(cacheName)) {
return CACHE_MAP.get(cacheName);
}
return null;
}
/**
* 获取缓存中的token,24小时更新
* @param loginJson
* @return
*/
public static String getCacheToken(JSONObject loginJson){
if (get("token")==null || get("token").equals("")){
put("token",getToken(loginJson),CACHE_HOLD_TIME_24H);
}
return String.valueOf(get("tokenString"));
}
还有个定时任务周期性执行,使用scheduleWithFixedDelay实现,这里传对象进去的话要声明为final
ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
Runnable runnable = new Runnable() {
public void run() {
try{
//执行内容
}catch (Exception e){
e.printStackTrace();
}
}
};
service.scheduleWithFixedDelay(runnable,10,20, TimeUnit.MINUTES);
service.execute(runnable);
参考: https://www.cnblogs.com/swordfall/p/10757499.html.
https://www.imooc.com/article/18585
https://blog.csdn.net/qb170217/article/details/81699439
https://blog.csdn.net/walle167/article/details/50957400
附一个Spring-boot的学习地址 https://github.com/ityouknow/spring-boot-examples