1. 程式人生 > >基於OkHttp網路通訊工具類(傳送get、post請求、檔案上傳和下載)

基於OkHttp網路通訊工具類(傳送get、post請求、檔案上傳和下載)

一、為什麼要用OkHttp?


okhttp是專注於提升網路連線效率的http客戶端。
優點:

1、它能實現同一ip和埠的請求重用一個socket,這種方式能大大降低網路連線的時間,和每次請求都建立socket,再斷開socket的方式相比,降低了伺服器伺服器的壓力。

2、okhttp 對http和https都有良好的支援。

3、okhttp 不用擔心android版本變換的困擾。

4、成熟的網路請求解決方案,比HttpURLConnection更好用。
5、支援非同步傳送網路請求,響應可線上程處理。



二、其它的網路通訊框架:


1、HttpURLConnection:java.util包下的http客戶端,對網路請求的封裝沒有HttpClient那麼徹底,api使用起來比較簡單,易於擴充套件。
2、HttpClient:Apache的一個第三方網路框架,api眾多,用起來比較方便,實現比較穩定,但不易於擴充套件。
3、Volley:google推出的網路通訊框架,適合處理資料量小、通訊頻繁的網路操作,內部封裝了非同步執行緒,不適合大資料量的請求。


下面對OkHttp做了一個簡單的封裝,可用於傳送get、post請求(支援請求引數格式為鍵值對、json格式)、檔案上傳、檔案下載。


import java.io.IOException;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import com.alibaba.fastjson.JSONObject;

import okhttp3.FormBody;
import okhttp3.Headers;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

public class OkHttpUtils {

  private static final Logger LOGGER = LoggerFactory.getLogger(OkHttpUtils.class);

  public static final MediaType JSON = MediaType.get("application/json;charset=utf-8");

  public static final MediaType OCTET_STREAM = MediaType.get("application/octet-stream");

  /**
   * 請求帶的UA
   */
  public static final String USER_AGENT = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36";

  /**
   * 超時、讀、寫時長
   */
  public static final int TIMEOUT = 10;

  public static OkHttpClient getOkHttpClient() {
    return getOkHttpClient(TIMEOUT);
  }

  public static OkHttpClient getOkHttpClient(int timeout) {
    OkHttpClient.Builder builder = new OkHttpClient.Builder();
    builder.readTimeout(TIMEOUT, TimeUnit.SECONDS);
    builder.writeTimeout(TIMEOUT, TimeUnit.SECONDS);
    builder.connectTimeout(TIMEOUT, TimeUnit.SECONDS);
    return builder.build();
  }

  public static OkHttpResp sendGet(String url, Map<String, Object> reqHeaders, Map<String, Object> params) throws IOException {
    return sendGet(url, reqHeaders, params, TIMEOUT);
  }

  /**
   * get請求
   * @param url 請求地址
   * @param reqHeaders 請求頭
   * @param params 請求引數
   * @param timeout 超時時長
   * @return
   * @throws IOException
   */
  public static OkHttpResp sendGet(String url, Map<String, Object> reqHeaders, Map<String, Object> params, int timeout) throws IOException {
    if (StringUtils.isBlank(url)) {
      throw new IllegalArgumentException("request url can not be null");
    }

    OkHttpClient client = getOkHttpClient(timeout);
    HttpUrl.Builder urlBuilder = HttpUrl.get(url).newBuilder();
    // 拼接引數
    if (!CollectionUtils.isEmpty(params)) {
      for (Entry<String, Object> param : params.entrySet()) {
        Object value = param.getValue();
        if (value == null) {
          urlBuilder.addEncodedQueryParameter(param.getKey(), null);
        } else {
          urlBuilder.addEncodedQueryParameter(param.getKey(), String.valueOf(param.getValue()));
        }
      }
    }

    HttpUrl httpUrl = urlBuilder.build();
    Request.Builder reqBuilder = new Request.Builder().url(httpUrl).addHeader("User-Agent", USER_AGENT);
    // 增加請求頭
    addHeaders(reqHeaders, reqBuilder);
    Request request = reqBuilder.get().build();
    System.out.println(httpUrl.toString());
    return getResponse(httpUrl.toString(), client, request);
  }

  public static OkHttpResp sendPostWithKeyValue(String url, Map<String, Object> headers, Map<String, Object> params) throws IOException {
    return sendPostWithKeyValue(url, headers, params, TIMEOUT);
  }

  /**
   * 傳送post請求,請求引數格式為鍵值對
   * @param url 請求地址
   * @param reqHeaders 請求頭
   * @param params 請求引數
   * @param timeout 超時時長
   * @return
   * @throws IOException
   */
  public static OkHttpResp sendPostWithKeyValue(String url, Map<String, Object> reqHeaders, Map<String, Object> params, int timeout) throws IOException {
    if (StringUtils.isBlank(url)) {
      throw new IllegalArgumentException("request url can not be null");
    }

    OkHttpClient client = getOkHttpClient(timeout);
    Request.Builder reqBuilder = new Request.Builder().url(url).addHeader("User-Agent", USER_AGENT);
    // 增加請求頭
    addHeaders(reqHeaders, reqBuilder);

    FormBody.Builder formBuilder = new FormBody.Builder(Charset.forName("UTF-8"));
    FormBody formBody = formBuilder.build();
    // 新增請求引數
    if (!CollectionUtils.isEmpty(params)) {
      for (Map.Entry<String, Object> param : params.entrySet()) {
        Object obj = param.getValue();
        if (obj != null) {
          formBuilder.add(param.getKey(), String.valueOf(param.getValue()));
        } else {
          formBuilder.add(param.getKey(), null);
        }
      }
    }

    Request request = reqBuilder.post(formBody).build();
    return getResponse(url, client, request);
  }

  public static OkHttpResp sendPostWithJson(String url, Map<String, Object> reqHeaders, Map<String, Object> params) throws IOException {
    return sendPostWithJson(url, reqHeaders, params, TIMEOUT);
  }

  /**
   * 傳送post請求,請求引數格式為json格式
   * @param url 請求地址
   * @param reqHeaders 請求頭
   * @param params 請求引數
   * @param timeout 超時時長
   * @return
   * @throws IOException
   */
  public static OkHttpResp sendPostWithJson(String url, Map<String, Object> reqHeaders, Map<String, Object> params, int timeout) throws IOException {
    if (StringUtils.isBlank(url)) {
      throw new IllegalArgumentException("request url can not be null");
    }

    OkHttpClient client = getOkHttpClient(timeout);

    Request.Builder reqBuilder = new Request.Builder().url(url).addHeader("User-Agent", USER_AGENT);
    // 新增請求頭
    addHeaders(reqHeaders, reqBuilder);

    // 新增請求引數
    RequestBody requestBody = RequestBody.create(JSON, JSONObject.toJSONString(params));
    if (CollectionUtils.isEmpty(params)) {
      requestBody = RequestBody.create(JSON, "");
    }

    Request request = reqBuilder.post(requestBody).build();
    return getResponse(url, client, request);
  }

  public static OkHttpResp uploadFile(String url, List<MultipartFile> files) throws IOException {
    return uploadFile(url, files, TIMEOUT);
  }

  /**
   * 上傳檔案
   * @param url 請求地址
   * @param files 檔案列表
   * @param timeout 超時時長
   * @return
   * @throws IOException
   */
  public static OkHttpResp uploadFile(String url, List<MultipartFile> files, int timeout) throws IOException {
    if (StringUtils.isBlank(url)) {
      throw new IllegalArgumentException("request url can not be null");
    }

    OkHttpClient client = getOkHttpClient(timeout);
    MultipartBody.Builder multiBuilder = new MultipartBody.Builder();
    multiBuilder.setType(MultipartBody.FORM);

    if (!CollectionUtils.isEmpty(files)) {
      for (MultipartFile multipartFile : files) {
        String fieldName = multipartFile.getFieldName();
        String fileName = multipartFile.getFileName();
        byte[] content = multipartFile.getContent();
        multiBuilder.addFormDataPart(fieldName, fileName, RequestBody.create(OCTET_STREAM, content));
      }
    }

    MultipartBody requestBody = multiBuilder.build();
    Request request = new Request.Builder().url(url).addHeader("User-Agent", USER_AGENT).post(requestBody).build();
    return getResponse(url, client, request);
  }

  public static byte[] downloadFile(String url) throws IOException {
    return downloadFile(url, TIMEOUT);
  }

  /**
   * 下載檔案
   * @param url 請求地址
   * @param timeout 超時時長
   * @return
   * @throws IOException
   */
  public static byte[] downloadFile(String url, int timeout) throws IOException {
    if (StringUtils.isBlank(url)) {
      throw new IllegalArgumentException("request url can not be null");
    }

    OkHttpClient client = getOkHttpClient(timeout);
    Request request = new Request.Builder().url(url).addHeader("User-Agent", USER_AGENT).get().build();

    try (Response response = client.newCall(request).execute()) {
      if (!response.isSuccessful()) {
        return null;
      }

      return response.body().bytes();
    } catch (IOException e) {
      LOGGER.error("fail to establish the connection with " + url, e);
      throw e;
    }
  }

  private static OkHttpResp getResponse(String url, OkHttpClient client, Request request) throws IOException {
    // 確保Response和ResponseBody關閉
    try (Response response = client.newCall(request).execute()) {
      if (!response.isSuccessful()) {
        return null;
      }

      OkHttpResp resp = new OkHttpResp();
      resp.setRespStr(response.body().string());
      resp.setRespHeaders(response.headers());
      return resp;
    } catch (IOException e) {
      LOGGER.error("fail to establish the connection with " + url, e);
      throw e;
    }
  }

  private static void addHeaders(Map<String, Object> reqHeaders, Request.Builder reqBuilder) {
    if (!CollectionUtils.isEmpty(reqHeaders)) {
      for (Entry<String, Object> reqHeader : reqHeaders.entrySet()) {
        Object value = reqHeader.getValue();
        if (value != null) {
          reqBuilder.addHeader(reqHeader.getKey(), String.valueOf(reqHeader.getValue()));
        } else {
          reqBuilder.addHeader(reqHeader.getKey(), null);
        }

      }
    }
  }

  public static class MultipartFile {

    /**
     * 檔案域名,相當於表單中檔案域名
     */
    private String fieldName;
    /**
     * 檔名
     */
    private String fileName;
    /**
     * 檔案路徑
     */
    private byte[] content;

    public MultipartFile() {
      super();
    }

    public MultipartFile(String fieldName, String fileName, byte[] content) {
      super();
      this.fieldName = fieldName;
      this.fileName = fileName;
      this.content = content;
    }

    public String getFieldName() {
      return fieldName;
    }

    public void setFieldName(String fieldName) {
      this.fieldName = fieldName;
    }

    public String getFileName() {
      return fileName;
    }

    public void setFileName(String fileName) {
      this.fileName = fileName;
    }

    public byte[] getContent() {
      return content;
    }

    public void setContent(byte[] content) {
      this.content = content;
    }
  }

  public static class OkHttpResp {

    /**
     * 響應字串
     */
    private String respStr;
    /**
     * 響應頭
     */
    private Headers respHeaders;

    public String getRespStr() {
      return respStr;
    }

    public void setRespStr(String respStr) {
      this.respStr = respStr;
    }

    public Headers getRespHeaders() {
      return respHeaders;
    }

    public void setRespHeaders(Headers respHeaders) {
      this.respHeaders = respHeaders;
    }
  }

}


對阿里FastJSONj進行JavaBean到json字串對映的簡單封裝。

import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.serializer.SerializerFeature;

public class JsonUtils {

	/**
	 * 將物件轉換為json字串
	 * 
	 * @param obj
	 *            轉換的物件
	 * @return
	 */
	public static String toJsonString(Object obj) {
		return toJsonString(obj, false);
	}

	/**
	 * 物件轉換為json字串,可允許轉換空值
	 * 
	 * @param obj
	 *            轉換的物件
	 * @param isNullValueAllowed
	 *            是否允許空值
	 * @return
	 */
	public static String toJsonString(Object obj, boolean isNullValueAllowed) {
		if (obj == null) {
			return null;
		}

		if (!isNullValueAllowed) {
			return JSON.toJSONString(obj);
		}

		return JSON.toJSONString(obj, SerializerFeature.WRITE_MAP_NULL_FEATURES);
	}

	/**
	 * 將json字串轉換為javaBean
	 * 
	 * @param jsonStr
	 *            json字串
	 * @param clazz
	 *            執行時物件
	 * @return
	 */
	public static <T> T toJavaBean(String jsonStr, Class<T> clazz) {
		if (StringUtils.isBlank(jsonStr)) {
			return null;
		}

		return JSON.parseObject(jsonStr, clazz);
	}

	/**
	 * 字串轉換為list
	 * 
	 * @param jsonStr
	 *            json字串
	 * @param clazz
	 *            執行時物件
	 * @return
	 */
	public static <T> List<T> toList(String jsonStr, Class<T> clazz) {
		if (StringUtils.isBlank(jsonStr)) {
			return null;
		}

		return JSON.parseArray(jsonStr, clazz);
	}

	/**
	 * 將json字串轉換為map
	 * 
	 * @param jsonStr
	 *            json字串
	 * @return
	 */
	public static Map<String, Object> toMap(String jsonStr) {
		if (StringUtils.isBlank(jsonStr)) {
			return null;
		}

		return JSON.parseObject(jsonStr, new TypeReference<Map<String, Object>>() {
		});
	}

	/**
	 * 將javaBean轉換為map
	 * 
	 * @param obj
	 *            轉換的物件
	 * @return
	 */
	public static Map<String, Object> javaBeanToMap(Object obj) {
		if (obj == null) {
			return null;
		}

		return toMap(toJsonString(obj));
	}

	/**
	 * 將map轉換為javaBean
	 * 
	 * @param map
	 *            map例項
	 * @param clazz
	 *            執行時物件
	 * @return
	 */
	public static <T> T mapToJavaBean(Map<String, ? extends Object> map, Class<T> clazz) {
		if (CollectionUtils.isEmpty(map)) {
			return null;
		}

		String jsonStr = JSON.toJSONString(map);
		return JSON.parseObject(jsonStr, clazz);
	}

}