<!--okhttp-->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.14.9</version>
</dependency>
import coms.common.http.RetryIntercepter;
import coms.common.sys.Usual;
import okhttp3.*;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* HttpUtil封装,异步连接池模式
*/
public class HttpUtil {
/**
* Http连接超时时间
*/
private static final int minCONNECT_TIMEOUT = 3000;
/**
* Http 写入超时时间
*/
private static final int minWRITE_TIMEOUT = 3000;
/**
* Http Read超时时间
*/
private static final int minREAD_TIMEOUT = 3000;
/**
* Http Async Call Timeout
*/
private static final int minCall_TIMEOUT = 3000;
/**
* Http连接池
*/
private static final int connectionPoolSize = 1000;
// /**
// * 静态Http请求池
// */
// private static OkHttpClient client=null;
/**
* 静态连接池对象
*/
private static ConnectionPool mConnectionPool=new ConnectionPool(connectionPoolSize, 30, TimeUnit.MINUTES);
//executor = new ThreadPoolExecutor(0, 2147483647, ...这个是静态的,21亿连接数量
// private static RealConnectionPool mConnectionPool=new RealConnectionPool(connectionPoolSize, 30, TimeUnit.MINUTES);
/**
* ContentType
*/
private static final String ContentType="application/json;charset=utf-8";
/**
* AcceptType
*/
private static final String AcceptType="application/json;charset=utf-8";
/**
* Content-Type
*/
private static final MediaType MediaType_ContentType = MediaType.parse(ContentType);
/**
* 获取Http Client对象
* 降低连接时间
* @return
*/
public static OkHttpClient getHttpClient(){
OkHttpClient client = new OkHttpClient.Builder()
// .addInterceptor(new RetryIntercepter(3))//重试3次
// .addInterceptor(new GzipRequestInterceptor())//gzip压缩
.connectTimeout(minCONNECT_TIMEOUT, TimeUnit.MILLISECONDS) //连接超时
.readTimeout(minREAD_TIMEOUT, TimeUnit.MILLISECONDS) //读取超时
.writeTimeout(minWRITE_TIMEOUT, TimeUnit.MILLISECONDS) //写超时
.callTimeout(minCall_TIMEOUT, TimeUnit.MILLISECONDS)
// okhttp默认使用的RealConnectionPool初始化线程数==2147483647,在服务端会导致大量线程TIMED_WAITING
//ThreadPoolExecutor(0, 2147483647, 60L, TimeUnit.SECONDS, new SynchronousQueue(), Util.threadFactory("OkHttp ConnectionPool", true));
.connectionPool(mConnectionPool)
.build();
return client;
}
//import java.nio.file.*;
public static void main(String[] args) {
//百度的Logo
String imgUrl = "https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png";
try {
OkHttpClient client = HttpUtil.getHttpClient();
Request request = new Request.Builder()
//访问路径
.url(imgUrl)
.build();
Response response = null;
response = client.newCall(request).execute();
//转化成byte数组
byte[] bytes = response.body().bytes();
//本地文件夹目录(下载位置)
String folder = "D:/q/w/e/r/";
//切割出图片名称==》PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png
String filename = StringUtils.substringAfterLast(imgUrl, "/");
Path folderPath = Paths.get(folder);
boolean desk = Files.exists(folderPath);
if (!desk) {
//不存在文件夹 => 创建
Files.createDirectories(folderPath);
}
//完整图片路径==》D:/q/w/e/r/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png
Path filePath = Paths.get(folder + filename);
boolean exists = Files.exists(filePath, LinkOption.NOFOLLOW_LINKS);
if (!exists) {
//不存在文件 => 创建
Files.write(filePath, bytes, StandardOpenOption.CREATE);
}
} catch (Exception e) {
e.printStackTrace();
}
}
//import java.net.URL;
//import java.net.URLConnection;
public void download() {
String downLoadUrl = "https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png";
try {
// 构造URL
URL url = new URL(downLoadUrl);
// 打开连接
URLConnection con = url.openConnection();
// 输入流
InputStream is = con.getInputStream();
// 1K的数据缓冲
byte[] bs = new byte[1024];
// 读取到的数据长度
int len;
//图片的完整路径
String filename = "D:/a/b/1.jpg";
// 输出的文件流
File file = new File(filename);
//是否存在目录
isChartPathExist("D:/a/b/");
FileOutputStream os = new FileOutputStream(file, true);
// 开始读取
while ((len = is.read(bs)) != -1) {
os.write(bs, 0, len);
}
// 完毕,关闭所有链接
os.close();
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//java判断指定路径文件夹是否存在,若不存在则创建新的文件夹
private static void isChartPathExist(String dirPath) {
File file = new File(dirPath);
if (!file.exists()) {
file.mkdirs();
}
}
1. 说明:
HTTP是现代应用常用的一种交换数据和媒体的网络方式,高效地使用HTTP能让资源加载更快,节省带宽。OkHttp是一个高效的HTTP客户端,它有以下默认特性:
2. 使用okhttp来访问请求(GET),是使用 .string()
//例如:
OkHttpClient client = HttpUtil.getHttpClient();
Request request = new Request.Builder()
.addHeader("访求球头")
.url("访问地址")
.build();
//默认get方法
Response response = client.newCall(request).execute();
result = response.body().string();
//输出json(string)
3. okhttp的其他基本使用-demo
01、同步get请求
/**
* 同步get请求
*/
//import org.junit.jupiter.api.Test;
@Test
public void syncGet01() throws IOException {
String urlBaidu = "http://www.baidu.com/";
OkHttpClient okHttpClient = new OkHttpClient(); // 创建OkHttpClient对象
Request request = new Request.Builder().url(urlBaidu).build(); // 创建一个请求
Response response = okHttpClient.newCall(request).execute(); // 返回实体
if (response.isSuccessful()) { // 判断是否成功
/**
* 获取返回的数据,可通过response.body().string()获取,默认返回的是utf-8格式;
* string()适用于获取小数据信息,如果返回的数据超过1M,建议使用stream()获取返回的数据,
* 因为string() 方法会将整个文档加载到内存中
*/
System.out.println(response.body().string()); // 打印数据
} else {
System.out.println("失败"); // 链接失败
}
}
02、亦步get请求
/**
* 异步Get请求
*/
@Test
public void asyncGet02() {
String urlBaidu = "http://www.baidu.com/";
// 创建OkHttpClient对象
OkHttpClient okHttpClient = new OkHttpClient();
// 创建一个请求
Request request = new Request.Builder().url(urlBaidu).build();
// 回调
okHttpClient.newCall(request).enqueue(new Callback() {
public void onResponse(Call call, Response response) {
// 请求成功调用,该回调在子线程
try {
System.out.println("ok");
String result = response.body().string();
System.out.println(result);
} catch (IOException e) {
e.printStackTrace();
}
}
public void onFailure(Call call, IOException e) {
// 请求失败调用
System.out.println(e.getMessage());
}
});
//测试时候,保证主线程活着。
Thread.sleep(1000000);
}
03、post提交表单数据
/**
* Post提交表单
*/
public void asyncPost_Form() {
//表单参数
String name = "";
//访问地址
String url = "";
// OkHttpClient对象
OkHttpClient okHttpClient = new OkHttpClient();
//设置数据
RequestBody formBody = new FormBody.Builder()
//表单键值对
.add("name", name)
.build();
// post请求
Request request = new Request
.Builder()
.url(url)
.post(formBody)
.build();
// 回调
okHttpClient.newCall(request).enqueue(new Callback() {
public void onResponse(Call call, Response response) throws IOException {
//成功后的回调
System.out.println(response.body().string());
}
public void onFailure(Call call, IOException e) {
//失败后的回调
System.out.println(e.getMessage());
}
});
}
04、post提交字符串
/**
* Post提交字符串
*/
@Test
public void post_StringParam(){
MediaType MEDIA_TYPE = MediaType.parse("text/text; charset=utf-8");
// 请求链接
String url = "";
// OkHttpClient对象
OkHttpClient okHttpClient = new OkHttpClient();
String string = "name=zhangsan"; // 要发送的字符串
/**
* RequestBody.create(MEDIA_TYPE, string)
* 第二个参数可以分别为:byte[],byteString,File,String。
*/
Request request = new Request.Builder()
//地址
.url(url)
//参数
.post(RequestBody.create(MEDIA_TYPE,string))
.build();
okHttpClient.newCall(request).enqueue(new Callback() {
//成功
public void onResponse(Call call, Response response) throws IOException {
System.out.println(response.body().string());
//这里可以把string转成json
//jackson,gson...
/**
* 步骤
* 创建一个字段对应的实体类Vo
* gson的方式-> gson.fromJson(response.body().string(), 实体类.class)
*/
}
//失败
public void onFailure(Call call, IOException e) {
System.out.println(e.getMessage());
}
});
}
最后在附上一个示例
/**
* 使用用例
* @param args
*/
public static void main(String[] args) throws InterruptedException {
//测试地址
String mUrl="";
//测试数据
//TODO: 建议byte[]直接传输,避免Base64数据长度及Chartset编码问题
byte[] mData=new byte[0];
String mDataStr="测试是大法师大法是";
mData=Usual.toBytes(mDataStr);
//getHttpClient()是文章开头封装那个okhttp的方法
OkHttpClient client = getHttpClient();
//可以为空
RequestBody body = RequestBody.create(null, mData);
//在Request中统一设置Header
//如果Request的header中用户加了header("Accept-Encoding")的话,那么Okhttp不会帮你处理Gzip的解压,需要你自己去处理
Request request = new Request.Builder()
.addHeader("Content-Type",ContentType)
.addHeader("Accept",AcceptType)
// .addHeader("Accept-Encoding", "gzip")
.addHeader("Connection","keep-alive")
.cacheControl(new CacheControl.Builder().noCache().build()) //不做缓存
.url(mUrl)
.post(body) //这里指定了POST
.build();
Call call = client.newCall(request);
//这里定义异步返回后,同步参数
//TODO: 建议模式 A->自己->C,并顺序返回情况
// //同步调用
// try{
// Response response = call.execute();
// }catch(IOException exp){
//
// }
// finally{
//
// }
//TODO: 建议模式 自己->[C,并返回情况A]->自己->C并返回自己;
//TODO: Android不受该影响
//异步回调
Lock cht_stLock = new ReentrantLock();
final TestBean mBean=new TestBean();
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
// log.error(e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
//TODO: 建议byte[]直接回传,避免Base64数据长度及Chartset编码问题
//Stream处理用例,使用pipe管道
// mReturnData=Streams.readAll(response.body().byteStream());
//默认编码处理用例
// String result = response.body().string();
// log.info(result);
byte[] mReturnData=new byte[0];
//byte[]处理用例
mReturnData=response.body().bytes();
if(Usual.isNullOrZeroBytes(mReturnData)==false){
String result =Usual.fromBytes(mReturnData);
}
mBean.setByteData(mReturnData);
//最后再设置curState
cht_stLock.lock();
try{
mBean.setCurState(true);
}finally{
cht_stLock.unlock();
}
}
});
//TODO: A->自己->C,并顺序返回情况,使用final TestBean方式
//阻塞进行等待
while(mBean.getCurState()!=true){
Thread.sleep(30);
}
//返回后,可以同步返回,其他调用的Http
}
//=================================================================================
//实体类
public class TestBean {
private String strData;
private byte[] byteData;
private Boolean curState;
//省略get/set。。。
}
完结