OKHttpUtil.java 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701
  1. package com.edufound.android.xyyf.util;
  2. import android.os.Handler;
  3. import android.os.Looper;
  4. import java.io.File;
  5. import java.io.FileOutputStream;
  6. import java.io.IOException;
  7. import java.io.InputStream;
  8. import java.net.FileNameMap;
  9. import java.net.URLConnection;
  10. import java.util.ArrayList;
  11. import java.util.HashMap;
  12. import java.util.List;
  13. import java.util.Map;
  14. import java.util.Set;
  15. import okhttp3.Call;
  16. import okhttp3.Callback;
  17. import okhttp3.Cookie;
  18. import okhttp3.CookieJar;
  19. import okhttp3.FormBody;
  20. import okhttp3.Headers;
  21. import okhttp3.HttpUrl;
  22. import okhttp3.Interceptor;
  23. import okhttp3.MediaType;
  24. import okhttp3.MultipartBody;
  25. import okhttp3.OkHttpClient;
  26. import okhttp3.Request;
  27. import okhttp3.RequestBody;
  28. import okhttp3.Response;
  29. import okhttp3.ResponseBody;
  30. import okio.Buffer;
  31. import okio.BufferedSource;
  32. import okio.ForwardingSource;
  33. import okio.Okio;
  34. public class OKHttpUtil {
  35. private OkHttpClient okHttpClient;
  36. private Handler handler;
  37. private static OKHttpUtil mInstance;
  38. private final HashMap<String, List<Cookie>> cookieStore = new HashMap<>();
  39. private OKHttpUtil() {
  40. //添加cookie
  41. okHttpClient = new OkHttpClient.Builder().cookieJar(new CookieJar() {
  42. @Override
  43. public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
  44. cookieStore.put(url.host(), cookies);
  45. }
  46. @Override
  47. public List<Cookie> loadForRequest(HttpUrl url) {
  48. List<Cookie> cookies = cookieStore.get(url.host());
  49. return cookies != null ? cookies : new ArrayList<Cookie>();
  50. }
  51. }).build();
  52. handler = new Handler(Looper.getMainLooper());
  53. }
  54. /**
  55. * 单例模式创建OkHttpUtil
  56. *
  57. * @return mInstance
  58. */
  59. public static OKHttpUtil getInstance() {
  60. if (mInstance == null) {
  61. synchronized (OKHttpUtil.class) {
  62. mInstance = new OKHttpUtil();
  63. }
  64. }
  65. return mInstance;
  66. }
  67. /**
  68. * get 同步请求
  69. *
  70. * @return response
  71. */
  72. private Response _getDataSync(String url) {
  73. Request request = new Request.Builder()
  74. .get()//默认get,可省略
  75. .url(url)
  76. .build();
  77. Response response = null;
  78. try {
  79. response = okHttpClient.newCall(request).execute();
  80. } catch (IOException e) {
  81. e.printStackTrace();
  82. }
  83. return response;
  84. }
  85. /**
  86. * get 同步请求
  87. *
  88. * @return 字符串
  89. */
  90. private String _getDataString(String url) throws IOException {
  91. Response response = _getDataSync(url);
  92. if (response.body() != null) {
  93. return response.body().string();
  94. }
  95. return null;
  96. }
  97. /**
  98. * get 异步请求
  99. */
  100. private void _getDataAsync(String url, final ResultCallback callback) {
  101. final Request request = new Request.Builder()
  102. .url(url)
  103. .build();
  104. deliveryResult(callback, request);
  105. }
  106. /**
  107. * post 同步请求
  108. *
  109. * @return response
  110. */
  111. private Response _postDataSync(String url, Param... params) throws IOException {
  112. Request request = buildPostRequest(url, params);
  113. return okHttpClient.newCall(request).execute();
  114. }
  115. /**
  116. * post 同步请求
  117. *
  118. * @return 字符串
  119. */
  120. private String _postDataString(String url, Param... params) throws IOException {
  121. Response response = _postDataSync(url, params);
  122. return response.body().string();
  123. }
  124. /**
  125. * post 异步请求
  126. */
  127. private void _postDataAsync(String url, final ResultCallback callback, Param... params) {
  128. Request request = buildPostRequest(url, params);
  129. deliveryResult(callback, request);
  130. }
  131. /**
  132. * post 异步请求
  133. */
  134. private void _postDataAsync(String url, final ResultCallback callback, Map<String, String> params) {
  135. Param[] paramsArr = map2Params(params);
  136. Request request = buildPostRequest(url, paramsArr);
  137. deliveryResult(callback, request);
  138. }
  139. /**
  140. * post 同步文件上传
  141. */
  142. private Response _postDataFileSync(String url, File[] files, String[] fileKeys, Param... params) throws IOException {
  143. Request request = buildMultipartFormRequest(url, files, fileKeys, params);
  144. return okHttpClient.newCall(request).execute();
  145. }
  146. private Response _postDataFileSync(String url, File file, String fileKey) throws IOException {
  147. Request request = buildMultipartFormRequest(url, new File[]{file}, new String[]{fileKey}, null);
  148. return okHttpClient.newCall(request).execute();
  149. }
  150. private Response _postDataFileSync(String url, File file, String fileKey, Param... params) throws IOException {
  151. Request request = buildMultipartFormRequest(url, new File[]{file}, new String[]{fileKey}, params);
  152. return okHttpClient.newCall(request).execute();
  153. }
  154. /**
  155. * 异步基于post的多文件上传
  156. */
  157. private void _postDataFileAsync(String url, final ResultCallback callback, File[] files, String[] fileKeys, Param... params) {
  158. Request request = buildMultipartFormRequest(url, files, fileKeys, params);
  159. deliveryResult(callback, request);
  160. }
  161. /**
  162. * 异步基于post的文件上传,单文件不带参数上传
  163. *
  164. * @param url
  165. * @param callback
  166. * @param file
  167. * @param fileKey
  168. */
  169. private void _postDataFileAsync(String url, ResultCallback callback, File file, String fileKey) {
  170. Request request = buildMultipartFormRequest(url, new File[]{file}, new String[]{fileKey}, null);
  171. deliveryResult(callback, request);
  172. }
  173. /**
  174. * 异步基于post的文件上传,单文件且携带其他form参数上传
  175. *
  176. * @param url 接口地址
  177. * @param callback callback
  178. * @param file file
  179. * @param fileKey fileKey
  180. * @param params params
  181. */
  182. private void _postDataFileAsync(String url, ResultCallback callback, File file, String fileKey, Param... params) {
  183. Request request = buildMultipartFormRequest(url, new File[]{file}, new String[]{fileKey}, params);
  184. deliveryResult(callback, request);
  185. }
  186. /**
  187. * 同步 post上传json对象
  188. *
  189. * @param url url;
  190. * @param jsonStr json 字符串
  191. * @return 字符串
  192. * @throws IOException
  193. */
  194. private String _postJsonDataSync(String url, String jsonStr) throws IOException {
  195. String result = null;
  196. MediaType JSON = MediaType.parse("text/html;charset=utf-8");
  197. RequestBody requestBody = RequestBody.create(JSON, jsonStr);
  198. Request request = new Request.Builder().url(url).post(requestBody).build();
  199. Response response = okHttpClient.newCall(request).execute();
  200. result = response.body().string();
  201. return result;
  202. }
  203. /**
  204. * 异步 post上传json对象
  205. *
  206. * @param url url
  207. * @param jsonStr json数据字符串
  208. * @param callback callback
  209. */
  210. private void _postJsonDataAsync(String url, String jsonStr, final ResultCallback callback) {
  211. MediaType JSON = MediaType.parse("text/html;charset=utf-8");
  212. RequestBody requestBody = RequestBody.create(JSON, jsonStr);
  213. Request request = new Request.Builder().url(url).post(requestBody).build();
  214. deliveryResult(callback, request);
  215. }
  216. /**
  217. * post 异步上传图片
  218. *
  219. * @param url url
  220. * @param callback callback
  221. * @param file file
  222. * @param fileKey fileKey
  223. * @param map map
  224. */
  225. private void _upLoadImg(String url, final ResultCallback callback, File file, String fileKey, Map<String, String> map) {
  226. Param[] params = map2Params(map);
  227. getInstance()._postDataFileAsync(url, callback, file, fileKey, params);
  228. }
  229. /**
  230. * 创建 MultipartFormRequest
  231. *
  232. * @param url 接口地址
  233. * @param files files
  234. * @param fileKeys file keys
  235. * @param params params
  236. * @return MultipartFormRequest
  237. */
  238. private Request buildMultipartFormRequest(String url, File[] files,
  239. String[] fileKeys, Param[] params) {
  240. params = validateParam(params);
  241. MultipartBody.Builder builder = new MultipartBody.Builder();
  242. for (Param param : params) {
  243. builder.addPart(Headers.of("Content-Disposition", "form-data; name=\"" + param.key + "\""),
  244. RequestBody.create(null, param.value));
  245. }
  246. if (files != null) {
  247. RequestBody fileBody;
  248. for (int i = 0; i < files.length; i++) {
  249. File file = files[i];
  250. String fileName = file.getName();
  251. fileBody = RequestBody.create(MediaType.parse(guessMimeType(fileName)), file);
  252. //TODO 根据文件名设置contentType
  253. builder.addPart(Headers.of("Content-Disposition",
  254. "form-data; name=\"" + fileKeys[i] + "\"; filename=\"" + fileName + "\""),
  255. fileBody);
  256. }
  257. }
  258. RequestBody requestBody = builder.build();
  259. return new Request.Builder()
  260. .url(url)
  261. .post(requestBody)
  262. .build();
  263. }
  264. private Param[] validateParam(Param[] params) {
  265. if (params == null)
  266. return new Param[0];
  267. else
  268. return params;
  269. }
  270. private String guessMimeType(String path) {
  271. FileNameMap fileNameMap = URLConnection.getFileNameMap();
  272. String contentTypeFor = fileNameMap.getContentTypeFor(path);
  273. if (contentTypeFor == null) {
  274. contentTypeFor = "application/octet-stream";
  275. }
  276. return contentTypeFor;
  277. }
  278. /**
  279. * 异步下载文件
  280. */
  281. private void _downloadFileAsync(final String url, final String destFileDir,
  282. final DownloadListener downloadListener) {
  283. final Request request = new Request.Builder().url(url).build();
  284. // 重写ResponseBody监听请求
  285. Interceptor interceptor = new Interceptor() {
  286. @Override
  287. public Response intercept(Chain chain) throws IOException {
  288. Response originalResponse = chain.proceed(chain.request());
  289. return originalResponse.newBuilder()
  290. .body(new DownloadResponseBody(originalResponse, 0, downloadListener))
  291. .build();
  292. }
  293. };
  294. OkHttpClient.Builder dlOkhttp = new OkHttpClient.Builder()
  295. .addNetworkInterceptor(interceptor);
  296. final Call call = dlOkhttp.build().newCall(request);
  297. call.enqueue(new Callback() {
  298. @Override
  299. public void onFailure(Call call, IOException e) {
  300. downloadListener.fail(e.getMessage());
  301. }
  302. @Override
  303. public void onResponse(Call call, Response response) throws IOException {
  304. long length = response.body().contentLength();
  305. downloadListener.start(length);
  306. InputStream is = null;
  307. byte[] b = new byte[2048];
  308. int len;
  309. FileOutputStream fos = null;
  310. try {
  311. is = response.body().byteStream();
  312. File file = new File(destFileDir, getFileName(url));
  313. fos = new FileOutputStream(file);
  314. while ((len = is.read(b)) != -1) {
  315. fos.write(b, 0, len);
  316. }
  317. fos.flush();
  318. // 如果下载文件成功,第一个参数为文件的绝对路径
  319. downloadListener.complete(file.getAbsolutePath());
  320. } catch (Exception e) {
  321. downloadListener.loadfail(e.getMessage());
  322. } finally {
  323. if (is != null) {
  324. is.close();
  325. }
  326. if (fos != null) {
  327. fos.close();
  328. }
  329. }
  330. }
  331. });
  332. }
  333. private String getFileName(String path) {
  334. int separatorIndex = path.lastIndexOf("/");
  335. return (separatorIndex < 0) ? path : path.substring(separatorIndex + 1,
  336. path.length());
  337. }
  338. /***************************************************************** 公共方法***************************************************/
  339. /**
  340. * get 同步请求
  341. *
  342. * @param url 接口地址
  343. * @return response
  344. */
  345. public static Response getDataSync(String url) {
  346. return getInstance()._getDataSync(url);
  347. }
  348. /**
  349. * get 同步请求
  350. *
  351. * @param url 接口地址
  352. * @return 字符串
  353. * @throws IOException
  354. */
  355. public static String getDataString(String url) throws IOException {
  356. return getInstance()._getDataString(url);
  357. }
  358. /**
  359. * get 异步请求
  360. *
  361. * @param url 接口地址
  362. */
  363. public static void getDataAsync(String url, final ResultCallback callback) {
  364. getInstance()._getDataAsync(url, callback);
  365. }
  366. /**
  367. * post 同步请求
  368. *
  369. * @param url url
  370. * @param param param
  371. * @return response
  372. * @throws IOException
  373. */
  374. public static Response postDataSync(String url, Param... param) throws IOException {
  375. return getInstance()._postDataSync(url, param);
  376. }
  377. /**
  378. * post 同步请求
  379. *
  380. * @param url url
  381. * @param params param
  382. * @return 字符串
  383. * @throws IOException
  384. */
  385. public static String postDataString(String url, Param... params) throws IOException {
  386. return getInstance()._postDataString(url, params);
  387. }
  388. /**
  389. * post 异步请求
  390. *
  391. * @param url url
  392. * @param callback 异步回调
  393. * @param params params
  394. */
  395. public static void postDataAsync(String url, final ResultCallback callback, Param... params) {
  396. getInstance()._postDataAsync(url, callback, params);
  397. }
  398. /**
  399. * post map集合 异步请求
  400. *
  401. * @param url url
  402. * @param callback callback
  403. * @param params params
  404. */
  405. public static void postDataAsync(String url, final ResultCallback callback, Map<String, String> params) {
  406. getInstance()._postDataAsync(url, callback, params);
  407. }
  408. /**
  409. * post 异步上传图片
  410. *
  411. * @param url url
  412. * @param callback callback
  413. * @param file file
  414. * @param fileKey fileKey
  415. * @param map map
  416. */
  417. public static void upLoadImg(String url, final ResultCallback callback, File file, String fileKey, Map<String, String> map) {
  418. getInstance()._upLoadImg(url, callback, file, fileKey, map);
  419. }
  420. /**
  421. * @param url 下载地址
  422. * @param destFileDir 保存地址
  423. * @param downloadListener downloadListener
  424. */
  425. public static void downloadFileAsync(String url, String destFileDir, DownloadListener downloadListener) {
  426. getInstance()._downloadFileAsync(url, destFileDir, downloadListener);
  427. }
  428. public void doGetSync(String url, Callback callback) throws IOException {
  429. // 创建一个Request
  430. Request request = new Request.Builder()
  431. .url(url)
  432. .build();
  433. doAsync(request, callback);
  434. }
  435. /**
  436. * 异步请求
  437. */
  438. public void doAsync(Request request, Callback callback) throws IOException {
  439. //创建请求会话
  440. Call call = okHttpClient.newCall(request);
  441. //同步执行会话请求
  442. call.enqueue(callback);
  443. }
  444. /**
  445. * map 转换为 Param
  446. *
  447. * @param params map
  448. * @return params
  449. */
  450. private Param[] map2Params(Map<String, String> params) {
  451. if (params == null) {
  452. return new Param[0];
  453. }
  454. int size = params.size();
  455. Param[] res = new Param[size];
  456. Set<Map.Entry<String, String>> entries = params.entrySet();
  457. int i = 0;
  458. for (Map.Entry<String, String> entry : entries) {
  459. res[i++] = new Param(entry.getKey(), entry.getValue());
  460. }
  461. return res;
  462. }
  463. /**
  464. * 创建 PostRequest
  465. *
  466. * @param url url
  467. * @param params params
  468. * @return request
  469. */
  470. private Request buildPostRequest(String url, Param[] params) {
  471. if (params == null) {
  472. params = new Param[0];
  473. }
  474. FormBody.Builder builder = new FormBody.Builder();
  475. for (Param param : params) {
  476. builder.add(param.key, param.value);
  477. }
  478. RequestBody requestBody = builder.build();
  479. return new Request.Builder()
  480. .url(url)
  481. .post(requestBody)
  482. .build();
  483. }
  484. /**
  485. * 抽象类,用于请求成功后的回调
  486. *
  487. * @param <T>
  488. */
  489. public static abstract class ResultCallback<T> {
  490. //这是请求数据的返回类型,包含常见的(Bean,List等)
  491. //失败回调
  492. public abstract void onError(Request request, Exception e);
  493. //成功的回调
  494. public abstract void onResponse(T response);
  495. }
  496. private Map<String, String> mSessions = new HashMap<>();
  497. /**
  498. * 请求回调处理方法并传递返回值
  499. *
  500. * @param callback Map类型请求参数
  501. * @param request Request请求
  502. */
  503. private void deliveryResult(final ResultCallback callback, final Request request) {
  504. okHttpClient.newCall(request).enqueue(new Callback() {
  505. @Override
  506. public void onFailure(Call call, IOException e) {
  507. sendFailedStringCallback(request, e, callback);
  508. }
  509. @Override
  510. public void onResponse(Call call, Response response) throws IOException {
  511. try {
  512. final String string = response.body().string();
  513. sendSuccessResultCallback(string, callback);
  514. } catch (IOException e) {
  515. sendFailedStringCallback(response.request(), e, callback);
  516. }
  517. }
  518. });
  519. }
  520. /**
  521. * 处理请求失败的回调信息方法
  522. *
  523. * @param e 错误信息
  524. * @param callback 回调类
  525. */
  526. private void sendFailedStringCallback(final Request request, final Exception e, final ResultCallback callback) {
  527. handler.post(new Runnable() {
  528. @Override
  529. public void run() {
  530. if (callback != null)
  531. callback.onError(request, e);
  532. }
  533. });
  534. }
  535. /**
  536. * 处理请求成功的回调信息方法
  537. *
  538. * @param object 服务器响应信息
  539. * @param callback 回调类
  540. */
  541. private void sendSuccessResultCallback(final Object object, final ResultCallback callback) {
  542. handler.post(new Runnable() {
  543. @Override
  544. public void run() {
  545. if (callback != null) {
  546. callback.onResponse(object);
  547. }
  548. }
  549. });
  550. }
  551. public static class Param {
  552. public Param() {
  553. }
  554. public Param(String key, String value) {
  555. this.key = key;
  556. this.value = value;
  557. }
  558. String key;
  559. String value;
  560. }
  561. public class DownloadResponseBody extends ResponseBody {
  562. private Response originalResponse;
  563. private DownloadListener downloadListener;
  564. private long oldPoint = 0;
  565. public DownloadResponseBody(Response originalResponse, long startsPoint, DownloadListener downloadListener) {
  566. this.originalResponse = originalResponse;
  567. this.downloadListener = downloadListener;
  568. this.oldPoint = startsPoint;
  569. Logger.e("DownloadResponseBody");
  570. }
  571. @Override
  572. public MediaType contentType() {
  573. return originalResponse.body().contentType();
  574. }
  575. @Override
  576. public long contentLength() {
  577. return originalResponse.body().contentLength();
  578. }
  579. @Override
  580. public BufferedSource source() {
  581. return Okio.buffer(new ForwardingSource(originalResponse.body().source()) {
  582. private long bytesReaded = 0;
  583. @Override
  584. public long read(Buffer sink, long byteCount) throws IOException {
  585. long bytesRead = super.read(sink, byteCount);
  586. bytesReaded += bytesRead == -1 ? 0 : bytesRead;
  587. if (downloadListener != null) {
  588. downloadListener.loading((int) ((bytesReaded + oldPoint)));
  589. }
  590. return bytesRead;
  591. }
  592. });
  593. }
  594. }
  595. public interface DownloadListener {
  596. /**
  597. * 开始下载
  598. */
  599. void start(long max);
  600. /**
  601. * 正在下载
  602. */
  603. void loading(int progress);
  604. /**
  605. * 下载完成
  606. */
  607. void complete(String path);
  608. /**
  609. * 请求失败
  610. */
  611. void fail(String message);
  612. /**
  613. * 下载过程中失败
  614. */
  615. void loadfail(String message);
  616. }
  617. }