Okhttp3 網絡請求框架與 Gson


Maven環境 :

      <dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> <version>3.14.1</version> </dependency> <dependency> <groupId>com.squareup.okhttp</groupId> <artifactId>logging-interceptor</artifactId> <version>2.7.5</version> </dependency>

logging-interceptor 是Okhttp攔截器,用於打印 Log 日志。

代碼 :

我采用的是實體類請求方式,一般請求都是使用HashMap作為Formbody,我來說一下我這么做的原因 :
1. 如果參數有改動,那么HashMap的 put 方法是不會報錯的,而實體類的set會報錯,這在代碼量大,復雜的時候很容易維護。
2. HashMap 的put需要手動填寫Key值,這毫無疑問是影響編碼體驗和效率的,特別是在請求參數繁雜的情況下。

通用請求工具類 :

public class OkHttpUtil { private static OkHttpClient okHttpClient = new OkHttpClient.Builder().addInterceptor(new LoggingInterceptor()).build(); public static Response sendPostRequest(String url, Object parameter) throws IOException { Map<String, Object> map = ReqUtil.ParameToMap(parameter); //動態添加參數 FormBody.Builder params = new FormBody.Builder(); //遍歷參數,KV對應。 for (Map.Entry<String, Object> mapping : map.entrySet()) { params.add(mapping.getKey(), String.valueOf(mapping.getValue())); } Request request = new Request.Builder() .url(url) .post(params.build()) .build(); return okHttpClient.newCall(request).execute(); } } 

這里的 ReqUtil.ParameToMap(parameter) 會對傳入的對象進行反射獲取所有屬性和值並轉換成HashMap。

addInterceptor(new LoggingInterceptor()).build() 加入請求日志攔截器。

對象轉HashMap ParameToMap 工具類

class ReqUtil { @SuppressWarnings("unchecked") static <K, V> Map<K, V> ParameToMap(Object javaBean) { Map<K, V> ret = new HashMap<K, V>(); try { Method[] methods = javaBean.getClass().getDeclaredMethods(); for (Method method : methods) { if (method.getName().startsWith("get")) { String field = method.getName(); field = field.substring(field.indexOf("get") + 3); field = field.toLowerCase().charAt(0) + field.substring(1); Object value = method.invoke(javaBean, (Object[]) null); ret.put((K) field, (V) (null == value ? null : value)); } } } catch (Exception e) { } return ret; } }

請求攔截器,打印請求信息及 Formbody :

public class LoggingInterceptor implements Interceptor {
    private Logger logger = LoggerFactory.getLogger(LoggingInterceptor.class);

    public Response intercept(Chain chain) throws IOException {
        // 這個chain里面包含了request和response,所以你要什么都可以從這里拿 Request request = chain.request(); long t1 = System.nanoTime();// 請求發起的時間 logger.info(String.format("發送請求 %s on %s%n%s", request.url(), chain.connection(), request.headers())); // logger.info("請求參數:{\n +" + request.body().writeTo(); + "\n}"); StringBuilder bodyLog = new StringBuilder(); if (request.body() instanceof FormBody) { FormBody body = (FormBody) request.body(); for (int i = 0; i < body.size(); i++) { bodyLog.append(body.encodedName(i)).append("=").append(body.encodedValue(i)).append(","); } bodyLog.delete(bodyLog.length() - 1, bodyLog.length()); logger.info("請求參數:" + bodyLog.toString()); } // System.out.println(String.format("發送請求 %s on %s%n%s", request.url(), chain.connection(), request.headers())); Response response = chain.proceed(request); long t2 = System.nanoTime();// 收到響應的時間 // 這里不能直接使用response.body().string()的方式輸出日志 // 因為response.body().string()之后,response中的流會被關閉,程序會報錯,我們需要創建出一 // 個新的response給應用層處理 ResponseBody responseBody = response.peekBody(1024 * 1024); logger.info(String.format("接收響應: [%s] %n返回json:【%s】 %.1fms%n%s", response.request().url(), responseBody.string(), (t2 - t1) / 1e6d, response.headers())); return response; } } 

使用 :

 public static ResponseBody registerUser(RegisterParameter registerParameter) throws IOException { return OkHttpUtil.sendPostRequest(Origin.register, registerParameter).body(); }

效果 :

Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2dd98b52]
2019-06-03 21:29:28.367 INFO 7884 --- [p-nio-80-exec-3] c.s.g.m.n.r.LoggingInterceptor : 發送請求 https://api.ttlock.com.cn/v3/user/list on null
2019-06-03 21:29:28.367 INFO 7884 --- [p-nio-80-exec-3] c.s.g.m.n.r.LoggingInterceptor : 請求參數:date=1559568568366,clientId=63eb3d5111b443969f4224cb2db65076,endDate=0,pageNo=1,pageSize=10,clientSecret=17a8d3cc6227e79fdeb3ee09f9bf5f8b,startDate=0
2019-06-03 21:29:28.621 INFO 7884 --- [p-nio-80-exec-3] c.s.g.m.n.r.LoggingInterceptor : 接收響應: [https://api.ttlock.com.cn/v3/user/list]
返回json:【{"list":[{"regtime":1559529910000,"userid":"testbl_23"},{"regtime":1559461353000,"userid":"testbl_admin"},{"regtime":1559529920000,"userid":"testbl_admin4"}],"pageNo":1,"pageSize":10,"pages":1,"total":3}】 254.3ms
Server: Tengine
Date: Mon, 03 Jun 2019 13:29:30 GMT
Content-Type: application/json;charset=utf-8
Content-Length: 203
Connection: keep-alive

關於JSON解析嵌套實體類 :

在 Json 解析這方面,JSONObject 是出場率最高的,但JSONObject 處理解析嵌套數據格式的時候就有些差強人意了,比如這種 :

@Data public class UserPage { private int pageNo; private int pageSize; private int pages; private int total; private List<User> list; }
{
    "list":[ { "regtime":1559529910000, "userid":"testbl_23" }, { "regtime":1559461353000, "userid":"testbl_admin" }, { "regtime":1559529920000, "userid":"testbl_admin4" } ], "pageNo":1, "pageSize":10, "pages":1, "total":3 }

如果用 JSONObject解析,List<User> 值會是null,而使用Gson則可以完美解析,不愧是Google家的東西,寫的真周全。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM